Eu tenho a seguinte tabela com 7,5 milhões de registros:
CREATE TABLE [dbo].[TestTable](
[Id] [int] IDENTITY(1,1) NOT NULL,
[TestCol] [nvarchar](50) NOT NULL,
[TestCol2] [nvarchar](50) NOT NULL,
[TestCol3] [nvarchar](50) NOT NULL,
[Anonymised] [tinyint] NOT NULL,
[Date] [datetime] NOT NULL,
CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Percebo que quando há um índice não agrupado no campo de data:
CREATE NONCLUSTERED INDEX IX_TestTable_Date ON [dbo].[TestTable] ([Date])
e eu executo a seguinte consulta:
UPDATE TestTable
SET TestCol='*GDPR*', TestCol2='*GDPR*', TestCol3='*GDPR*', Anonymised=1
WHERE [Date] <= '25 August 2016'
- os dados retornados pela operação de acesso ao índice são classificados para corresponder à ordem das chaves do PK / CX, reduzindo o desempenho.
Fiquei surpreso ao descobrir que a remoção do índice do campo de data realmente melhora o desempenho da consulta em cerca de 30% porque ela não executa mais a classificação:
Minha teoria, e isso pode ser óbvio para os mais experientes entre vocês, é que descobriu que a coluna da data está implicitamente ordenada exatamente da mesma forma que a chave primária / índice clusterizado.
Portanto, minha pergunta é: É possível aproveitar esse fato para melhorar o desempenho da minha consulta?
fonte
[Date]
mas emDESC
ordem? Apenas curioso, já que o predicado é<=
. Além disso, se o índice ativadoDate
(por padrão,ACS
ordem) ajudar outras consultas, talvez você possa tentar adicionar uma dica de tabela ao UPDATE para forçá-lo a usar o PK? Ou, talvez, divida isso em duas partes: crie uma tabela temporária, preencha com[Id]
base em[Date] <= '25 August 2016'
e remova oWHERE
da UPDATE e adicioneFROM dbo.TestTable tt INNER JOIN #tmp ids ON ids.[Id] = tt.[Id]
. É uma atualização, afinal, e precisa encontrar as linhas reais, índice ou não.Respostas:
Simulei dados de teste que reproduzem principalmente o seu problema:
Estatísticas para a consulta que usa o índice não clusterizado:
Estatísticas para a consulta que usa o índice em cluster:
Chegando à sua pergunta:
Sim. Você pode usar o índice não clusterizado que você já precisa para encontrar com eficiência o
id
valor máximo que precisa ser atualizado. Se você salvar isso em uma variável e filtrar, obterá um plano de consulta para a atualização que faz a verificação do índice em cluster (sem a classificação) que para mais cedo e, portanto, faz menos IO. Aqui está uma implementação:Execute estatísticas para a nova consulta:
Bem como o plano de consulta:
Com tudo isso dito, seu desejo de acelerar a consulta sugere que você planeja executar a consulta mais de uma vez. No momento, sua consulta tem um filtro aberto na
date
coluna. É realmente necessário anonimizar as linhas mais de uma vez? Você pode evitar atualizar ou varrer linhas que já foram anonimizadas? Certamente deve ser mais rápido atualizar um intervalo de datas com datas dos dois lados. Você também pode adicionar aAnonymised
coluna ao seu índice, mas esse índice precisará ser atualizado durante suaUPDATE
consulta. Em resumo, evite processar os mesmos dados repetidamente, se puder.A consulta original que você possui com a classificação é mais lenta devido ao trabalho realizado no
Clustered Index Update
operador. A quantidade de tempo gasto no índice procura e a classificação é de apenas 407 ms. Você pode ver isso no plano real. O plano é executado no modo de linha, para que o tempo gasto na classificação seja o tempo desse operador junto com todos os operadores filhos:Isso deixa o operador de classificação com cerca de 1600 ms de tempo. O SQL Server precisa ler páginas do índice clusterizado para executar a atualização. Você pode ver que o
Clustered Index Update
operador faz 1205921 leituras lógicas. Você pode ler mais sobre a classificação de otimizações para DML e a pré-busca otimizada nesta postagem de blog de Paul White .O outro plano de consulta que você possui (sem a classificação) leva 683 ms para a verificação de índice em cluster e cerca de 550 ms para o
Clustered Index Update
operador. O operador de atualização não faz nenhum pedido de entrada / saída para esta consulta.A resposta simples para o motivo pelo qual o plano com a classificação é mais lento é que o SQL Server faz leituras mais lógicas no índice de cluster para esse plano em comparação com o plano de verificação de índice em cluster. Mesmo se todos os dados necessários estiverem na memória, ainda haverá um custo adicional para fazer essas leituras lógicas. É muito mais difícil obter uma resposta melhor, pois, até onde sei, os planos não fornecerão mais detalhes. É possível usar o PerfView ou outra ferramenta baseada no rastreamento ETW para comparar pilhas de chamadas entre as consultas:
À esquerda, a consulta que faz a verificação do índice em cluster e, à direita, a consulta que faz a classificação. Marquei pilhas de chamadas em azul ou vermelho que aparecem apenas em uma consulta. Não é de surpreender que as diferentes pilhas de chamadas com um alto número de ciclos de CPU amostrados para a consulta de classificação pareçam ter a ver com as leituras lógicas necessárias para executar a atualização no índice em cluster. Além disso, existem diferenças no número de ciclos amostrados entre as consultas para a mesma operação. Por exemplo, a consulta com a classificação gasta 31 ciclos adquirindo travas, enquanto a consulta com a varredura gasta apenas 9 ciclos adquirindo travas.
Suspeito que o SQL Server esteja escolhendo o plano mais lento devido a uma limitação de custo do operador do plano de consulta. Talvez parte da diferença no tempo de execução seja devido ao hardware ou à sua edição do SQL Server. De qualquer forma, o SQL Server não é capaz de descobrir que a coluna da data está implicitamente ordenada exatamente da mesma forma que o índice clusterizado. Os dados são retornados da varredura de índice em cluster na ordem das chaves em cluster, portanto, não há necessidade de executar uma classificação na tentativa de otimizar a E / S ao fazer a atualização do índice em cluster.
fonte