Tenho uma dúvida sobre indexador e planos de execução no T-SQL.
Meu banco de dados é o SQL Server 2008.
Eu tenho um esquema de banco de dados simples de três tabelas:
A InverterData
tabela é muito grande e particionada (28.880.436 linhas).
A Date
coluna é calculada assim:
[Date] AS (ISNULL(CONVERT([date], [TimeStamp]), CONVERT([DATE], '19000101', (112)))) PERSISTED NOT NULL,
Há também um índice para esta coluna:
CREATE NONCLUSTERED INDEX [NonClusteredIndex]
ON [InverterData] ([Date] DESC, [InverterID] ASC)
Selecione a consulta nº 1 :
Agora quero fazer uma seleção simples que inclua todas as três tabelas e a coluna 'Data' em uma cláusula where:
SELECT
[TimeStamp], [ACPower], [DCPower]
FROM
[InverterData]
JOIN
[Inverter] ON [InverterData].[InverterID] = [Inverter].[ID]
JOIN
[DataLogger] ON [Inverter].[DataLoggerID] = [DataLogger].[ID]
WHERE
[InverterData].[Date] = '05.01.2016'
AND [DataLogger].[ProjectID] = 20686
Demorou cerca de 19 segundos no banco de dados atual (resultado ~ 80 linhas).
Este é o plano de execução:
Selecione a consulta nº 2 :
No primeiro select detectei que existe uma busca de índice de longa duração para a coluna 'Data'. Portanto, executo uma segunda seleção que inclui apenas a coluna de chave primária 'TimeStamp'.
Esta é a segunda seleção:
SELECT
[TimeStamp], [ACPower], [DCPower]
FROM
[InverterData]
JOIN
[Inverter] ON [InverterData].[InverterID] = [Inverter].[ID]
JOIN
[DataLogger] ON [Inverter].[DataLoggerID] = [DataLogger].[ID]
WHERE
[TimeStamp] >= '05.01.2016' AND [TimeStamp] < '06.01.2016'
AND [DataLogger].[ProjectID] = 20686
Demorou apenas cerca de 2 segundos no meu banco de dados atual.
Este é o plano de execução:
Pergunta:
Por que há duas buscas de índice? Incluí todas as colunas usadas do select 1 em um índice. Por que demorou tanto mais?
Atualização 1 :
Se alguém precisar do esquema completo, irei adicioná-lo a um violino SQL e publicá-lo.
Atualização 2 :
Dica de busca de índice
Em sua primeira consulta, o índice é usado para encontrar linhas correspondentes
[InverterData].[Date] = '05.01.2016'
, então ele precisa procurar o restante dos dados da linha para satisfazer a capacidade de retornarACPower
eDCPower
- se você remover essas colunas da saída, verá a pesquisa extra desaparecer.Você pode incluir as colunas extras no índice com:
Isso remove a pesquisa extra por meio do índice clusterizado, fazendo com que o índice não clusterizado consuma mais espaço no disco (e na memória). Essa compensação de velocidade de consulta e espaço usado é algo que você terá que decidir executando benchmarks nos bits do aplicativo que usam essa tabela.
Observe que você também pode fazer:
que usa as colunas extras como parte da chave, em vez de apenas
INCLUDING
elas. É provável que o exemplo anterior seja mais eficiente, pois é improvável que os valores sejam filtrados/classificados, portanto, ele salva as divisões de página causadas pelo mecanismo que tenta manter os valores (efetivamente aleatórios) armazenados em ordem.Os planos de execução parecem bons e lógicos para mim.
Em sua primeira consulta, você está fazendo uma busca de índice em seu índice não clusterizado em sua
Date
coluna e, em seguida, fazendo umclustered key lookup
( acho que meu alemão está enferrujado para dizer o mínimo, mas pelo contexto ele combina ).Não é uma operação de 'duas buscas'. É uma busca e obter dados adicionais.
Em sua segunda consulta você não está usando seu índice não clusterizado porque você qualificou sua consulta com
timestamp
coluna e então ela pode usar seu índice clusterizado (no seu caso também chave primária), que contém todos os dados e, portanto, não precisa procurar até adicional.Parece bastante sensato.