Grande variação no tempo de inserção em massa

13

Portanto, eu tenho um processo simples de inserção em massa para pegar os dados da nossa tabela de preparação e movê-los para o nosso datamart.

O processo é uma tarefa simples de fluxo de dados com configurações padrão para "Linhas por lote" e as opções são "tablock" e "sem restrição de verificação".

A mesa é bastante grande. 587.162.986 com um tamanho de dados de 201 GB e 49 GB de espaço de índice. O índice clusterizado para a tabela é

CREATE CLUSTERED INDEX ImageData ON dbo.ImageData
(
    DOC_ID ASC,
    ACCT_NUM ASC,
    MasterID ASC
)

E a chave primária é:

ALTER TABLE dbo.ImageData 
ADD CONSTRAINT ImageData 
PRIMARY KEY NONCLUSTERED 
(
    ImageID ASC,
    DT_CRTE_DOC ASC
)

Agora, estamos tendo um problema em que BULK INSERTvia SSIS está executando incrivelmente lento. 1 hora para inserir um milhão de linhas. A consulta que preenche a tabela já está classificada e a consulta a preencher leva menos de um minuto para ser executada.

Quando o processo está em execução, posso ver a consulta aguardando a inserção BULK, que leva de 5 a 20 segundos e mostra um tipo de espera de PAGEIOLATCH_EX. O processo é capaz apenas de INSERTcerca de mil linhas por vez.

Ontem, enquanto testava esse processo no meu ambiente UAT, estava com o mesmo problema. Eu estava executando o processo algumas vezes e tentando determinar qual é a causa raiz dessa inserção lenta. De repente, começou a funcionar em menos de 5 minutos. Então eu executei mais algumas vezes, tudo com o mesmo resultado. Além disso, o número de inserções em massa que aguardavam 5 segundos ou mais caiu de centenas para cerca de 4.

Agora, isso é desconcertante, porque não é como se tivéssemos tido uma grande queda de atividade.

CPU durante a duração é baixa.

CPU

Nos momentos em que é mais lento, parece haver menos esperas no disco.

Espera

A latência do disco realmente aumenta durante o período em que o processo estava sendo executado em menos de 5 minutos.

Latência

E o IO foi muito mais baixo durante o período em que esse processo ocorre mal.

IO

Eu já verifiquei e não houve crescimento de arquivos, pois os arquivos estão apenas 70% cheios. O arquivo de log ainda tem 50% para ir. O banco de dados está no modo de recuperação simples. O banco de dados possui apenas um grupo de arquivos, mas está espalhado por quatro arquivos.

Então, o que eu estou pensando A: por que eu estava vendo tempos de espera tão grandes nessas inserções em massa. B: que tipo de mágica aconteceu que a fez correr mais rápido?

Nota. Hoje corre como lixo novamente.

ATUALIZAÇÃO está atualmente particionada. No entanto, é feito em um método que é, na melhor das hipóteses, bobo.

CREATE PARTITION SCHEME [ps_Image] AS PARTITION [pf_Image] 
TO ([FG_Image], [FG_Image], [FG_Image], [FG_Image])

CREATE PARTITION FUNCTION [pf_Image](datetime) AS 
RANGE RIGHT FOR VALUES (
      N'2011-12-01T00:00:00.000'
    , N'2013-04-01T00:00:00.000'
    , N'2013-07-01T00:00:00.000'
);

Isso deixa essencialmente todos os dados na 4ª partição. No entanto, já que tudo está indo para o mesmo grupo de arquivos. Atualmente, os dados são divididos de maneira bastante uniforme entre esses arquivos.

ATUALIZAÇÃO 2 Essas são as esperas gerais quando o processo está sendo executado de maneira inadequada.

Espera 1

Estas são as esperas durante o período em que eu fui capaz de executar o processo.

Wait2

O subsistema de armazenamento é RAID conectado localmente, sem SAN envolvida. Os logs estão em uma unidade diferente. O controlador RAID é PERC H800 com tamanho de cache de 1 GB. (Para UAT) Prod é um PERC (810).

Estamos usando a recuperação simples, sem backups. É restaurado a partir de uma cópia de produção todas as noites.

Também configuramos o IsSorted property = TRUESSIS, já que os dados já estão classificados.

Zane
fonte
ASYNC_NETWORK_IOsignifica que o SQL Server estava aguardando o envio de linhas para um cliente em algum lugar. Suponho que esteja mostrando a atividade do SSIS consumindo linhas da tabela de preparação.
Max Vernon
PAGEIOLATCH_EXe ASYNC_IO_COMPLETIONestão indicando que está demorando um pouco para obter dados do disco na memória. Isso pode ser um indicador de um problema com o subsistema de disco ou pode ser uma contenção de memória. Quanta memória o SQL Server tem disponível?
Max Vernon
Com um nome de tabela ImageData, você me deixa curioso - qual é a definição real da tabela? Se você está puxando os dados LOB, você pode ter sido buffer para o disco (que vai para BLOBTempStoragePath que se indefinido será diretório% TEMP% do usuário executando aka unidade C)
billinkc
Não é possível postar a definição da tabela, mas as informações são documentos fora da imagem.
Zane
Eu suspeito que é um problema de processamento paralelo. Eu recomendo que você ajuste seu MAXDOP (começando de 1 a 4) e veja como tudo vai. Por outro lado, para fins de teste, prefiro criar um comando BCP para substituir o SSIS e verificar se há alguma diferença.
jyao

Respostas:

1

Não posso apontar a causa, mas acredito que as linhas por lote padrão para uma operação BULK INSERT são "todas". Definir um limite em linhas pode tornar a operação mais digerível: é por isso que é uma opção. (Aqui e continuando, estou analisando a documentação "BULK INSERT" do Transact-SQL, para que possa estar muito longe do SSIS)

Isso terá o efeito de dividir a operação em vários lotes de X linhas, cada uma operando como uma transação separada. Se houver um erro, os lotes concluídos permanecerão confirmados na tabela de destino, e o lote que foi parado será revertido. Se isso é tolerável no que você está fazendo, ou seja, você pode executá-lo mais tarde e recuperar o atraso, tente isso.

Não é errado ter uma função de partição que coloque todas as inserções atuais em uma partição de tabela, mas não vejo como é útil particionar com partições no mesmo grupo de arquivos. E usar datetime é ruim e, na verdade, meio que quebrado para datetime e 'AAAA-MM-DD' sem a fórmula CONVERT explícita desde o SQL Server 2008 (o SQL pode tratá-lo alegremente como AAAA-DD-MM: sem brincadeira: não entre em pânico, basta alterá-lo para 'AAAAMMDD', corrigido: ou CONVERT (data e hora, 'AAAA-MM-DDT00: 00: 00', 126), acho que é). Mas acho que usar um proxy para o valor de data (ano como int ou ano + trimestre) para particionar funcionará melhor.

Talvez seja um design copiado de outro lugar ou duplicado em vários datamarts. Se esse é um verdadeiro datamart, um despejo do data warehouse para fornecer aos gerentes de departamento alguns dados para jogar, que não estão sendo enviados por você (a você) em outro lugar e provavelmente somente leitura no que diz respeito aos usuários de dados , parece-me que você pode remover a função de partição - ou alterá-la para colocar explicitamente todos os novos dados na quarta partição, não importa o que aconteça, e ninguém se importaria. (Talvez você deva verificar se ninguém se importa.)

Parece um design em que o plano é eliminar o conteúdo da partição 1 em algum momento no futuro e criar outra nova partição para obter mais dados novos, mas não parece que isso esteja acontecendo aqui. Pelo menos isso não acontece desde 2013.

Robert Carnegie
fonte
0

Eu já vi essa mesma lentidão extrema esporádica nas inserções de grandes tabelas particionadas. Você tentou atualizar as tabelas de destino Estatísticas e depois executar novamente? O tempo de espera extremo pode ser devido a estatísticas ruins, e se uma atualização de estatísticas foi acionada em algum momento durante o teste, isso explicaria o aumento da velocidade. Apenas um pensamento e um teste fácil de verificar.

Richard Herling
fonte