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 INSERT
via 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 INSERT
cerca 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.
Nos momentos em que é mais lento, parece haver menos esperas no disco.
A latência do disco realmente aumenta durante o período em que o processo estava sendo executado em menos de 5 minutos.
E o IO foi muito mais baixo durante o período em que esse processo ocorre mal.
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.
Estas são as esperas durante o período em que eu fui capaz de executar o processo.
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 = TRUE
SSIS, já que os dados já estão classificados.
ASYNC_NETWORK_IO
significa 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.PAGEIOLATCH_EX
eASYNC_IO_COMPLETION
estã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?Respostas:
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.
fonte
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.
fonte