Regra rígida e rápida para incluir colunas no índice

38

Existe alguma regra rígida e rápida para decidir quais colunas e em qual ordem ela deve ser colocada em Incluído no índice não clusterizado. Eu estava lendo este post https://stackoverflow.com/questions/1307990/why-use-the-include-clause-when-creating-an-index e achei isso para a seguinte consulta:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5

O pôster sugeriu fazer um índice como este:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)

aqui vem a minha pergunta por que não podemos fazer o índice como este

CREATE NONCLUSTERED INDEX NC_EmpDep 
      ON Employee( EmployeeID, DepartmentID, LastName)

ou

    CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

e o que leva o pôster a decidir manter a coluna Sobrenome incluída. Por que não outras colunas? e como decidir em que ordem devemos manter as colunas lá?

Comunidade
fonte
3
INCLUIR normalmente deve ter os campos que você precisará APÓS um registro ser encontrado, economizando uma viagem de ida e volta para obter mais dados. A ordem dos campos no INCLUDE não é importante.
Jimbo 31/05
Ryk, pessoalmente, acho este post útil.
Jason Young
Acho esta pergunta útil também. Vamos foco em boas perguntas e boas respostas em vez de indivíduos perseguindo ....
Volvox

Respostas:

47

Essa sugestão de índice por marc_s está errada. Adicionei um comentário. (E foi minha resposta aceita também!)

O índice para esta consulta seria

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (Lastname, EmployeeID)

Um índice é tipicamente

CREATE INDEX <name> ON <table> (KeyColList) INCLUDE (NonKeyColList)

Onde:

  • KeyColList = Colunas-chave = usadas para restrição e processamento de linhas
    ONDE, JUNTA, ORDENAR POR, GRUPO POR etc
  • NonKeyColList = Colunas sem chave = usadas em SELECT e agregação (por exemplo, SUM (col)) após a seleção / restrição
gbn
fonte
+1 - Concordo (veja minhas ans) que os índices de amostra no OP não valem nada para a consulta!
JNK
Ótimo! apenas mais uma coisa que decidirá a ordem de KeyColList e NonKeyColList. Você pode apenas explicar com o meu exemplo? Suponha que agora minha consulta seja SELECT CódigoDoEmpregado, CódigoDoDomínio, Sobrenome FROM CódigoDoEmpregadoWHERE DepartmentID = 5, StateID = 4 Como deve ser o índice agora?
@Rocky - a NonKeyColListordem não importa. KeyColLista ordem deve estar na ordem da frequência em que você espera que sejam usadas nas consultas. Veja minhas anotações na minha resposta abaixo, mas é como Last Name, First Name, Middile Initialem uma lista telefônica. Você precisa do primeiro campo para encontrar o segundo campo.
JNK
@gbn Nós realmente solicitamos EmployeeID na lista de inclusão? Como se tivéssemos um índice clusterizado na coluna EmployeeID e, além disso, se criarmos um índice não clusterizado na coluna DeptId, o índice NonClustered já terá referência à chave de cluster incluída na estrutura do NonClustered Index, incluindo a chave de cluster na lista INCLUDE '' Não adicione nenhum benefício.
Viswanathan Iyer
1
@ViswanathanIyer, ele não será adicionado duas vezes ao armazenamento em disco real: o SQL Server detecta isso. Portanto, não é necessário, mas torna as coisas mais claras. No entanto, não conhecemos nenhum índice agrupado na pergunta, portanto é mais seguro não assumir nenhum.
gbn 7/08/17
19

O JNK e o gbn deram ótimas respostas, mas também vale a pena considerar o cenário geral - não apenas o foco em uma única consulta. Embora essa consulta em particular possa se beneficiar de um índice (# 1):

Employee(DepartmentID) INCLUDE (Lastname, EmployeeID)

Este índice não ajuda em nada se a consulta mudar um pouco, como:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5 AND LastName = 'Smith'

Isso precisaria do índice (# 2):

Employee(DepartmentID, LastName) INCLUDE (EmployeeID)

Imagine que você tinha 1.000 funcionários no Departamento 5. Usando o índice 1, para encontrar todos os Smiths, seria necessário procurar por todas as 1.000 linhas no Departamento 5, pois as colunas incluídas não fazem parte da chave. Usando o índice 2, você pode procurar diretamente no Departamento 5, Sobrenome Smith.

O índice 2 é, portanto, mais útil para atender a uma gama mais ampla de consultas - mas o custo é uma chave de índice mais inchada, o que aumentará as páginas que não são folhas do índice. Cada sistema será diferente, portanto não há regra de ouro aqui.


Como observação lateral, vale ressaltar que, se CódigoDoEmpregado for a chave de cluster desta tabela - assumindo um índice em cluster - você não precisará incluir Código do Empregado - ele estará presente em todos os índices não em cluster, o que significa que o índice 2 estar

Employee(DepartmentID, LastName)

fonte
2
+1 para informações mais úteis. Como último argumento, testei isso e o uso explícito do CódigoDoEmpregado no INCLUDE é realmente ignorado (com base no tamanho do índice) se CódigoDoEmpregado for o índice em cluster. É mais óbvio que eu penso e não há espaço negativo.
gbn
1
Eu concordo absolutamente - é sempre melhor ser explícito, especialmente se não custa nada!
1
Apenas no caso ... quero dizer, eu testei a chave de cluster no INCLUDE (não o EmployeeID explicitamente) e ele não adiciona espaço. Nas colunas principais, ele faz.
gbn
@gbn Sim, a chave do cluster precisa residir apenas no nível da folha do índice, onde as colunas INCLUDE residem. Movê-lo para a chave de índice significaria que também existiria nas páginas que não são folhas. Isso resultaria em um pouco de inchaço, mas não em uma quantidade terrível (nas páginas de nível intermediário, você adicionaria outros 4 bytes por página no nível da folha, assumindo um número inteiro).
Essa é uma ótima resposta, que inclui alguns dos efeitos descritos neste artigo: sqlperformance.com/2014/07/sql-indexes/… Se sua consulta for alterada, os requisitos de seus índices também serão alterados. Você pode estar melhor com a resposta de Jim, mas pode se sair melhor com a resposta @gbn.
precisa saber é o seguinte
7

Não tenho certeza de como você conseguiu esse primeiro. Para mim, para essa consulta, eu usaria:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (EmployeeID, Lastname)

Não existe uma "regra rígida e rápida" para praticamente qualquer coisa no SQL.

Mas, para o seu exemplo, o único campo que o índice usará é DepartmentIDporque está na WHEREcláusula.

Os outros campos só precisam ser facilmente acessíveis a partir daí. Você selecionar com base em DepartmentIDseguida, o INCLUDEtem esses campos no nó de folha do índice.

Você não deseja usar seus outros exemplos porque eles não funcionariam para este índice.

Pense em um índice como uma lista telefônica. A maioria dos catálogos telefônicos é ordenada por Sobrenome, Nome e Inicial do meio. Se você souber o nome de alguém, mas não o sobrenome, a lista telefônica não será útil, pois você não poderá procurar o primeiro nome com base na ordem do índice da lista telefônica.

Os INCLUDEcampos são como o número de telefone, endereço, etc. outras informações para cada entrada no livro.

EDITAR:

Para esclarecer melhor por que não usar:

CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

Esse índice é útil apenas se você tiver um EmployeeIDou ambos EmployeeID e LastNameem sua WHEREcláusula. Esse é praticamente o OPOSTO do que você precisa para esta consulta.

JNK
fonte
@ajbeaven isso é verdade, e é por isso que o comentário que eu coloquei na edição diz que você precisa de employeeID ou de ambas as colunas.
JNK
durr desculpe mal interpretado :(
ajbeaven
0

Acho que você ainda poderá usar o índice (employee_id, department_id), mas precisará incluir uma linha 'fictícia' na frase where, como: "employee_id = employee_id)

  • ter um índice em (employee_id, departemnent_id),
  • ter que pesquisar / restringir apenas em um departamento_id
  • sabendo que não usará o índice desde a ordem errada (ou as coisas mudaram até agora, e o seguinte "truque" não é mais necessário. Eu sou um "velho"?) .
  • Use o "velho" tricK?

    selecione * no Employee emp
    onde emp.employee_id = emp.employee_id
    e emp.department_id = 5

(Portanto, não estou focando na parte de inclusão aqui do Sobrenome, mas no sim / ou não sendo usado da chave.)

Atenciosamente,

Miguell

Miguel Leeuwe
fonte
2
Não, isso é inútil e não eficiente.
ypercubeᵀᴹ
Especificamente, ainda será necessário fazer uma varredura de índice para pesquisar todos os IDs de funcionários para encontrar todas as instâncias de department_id 5. Se houver 1000 funcionários e 5 departamentos, o SQL precisará procurar todos os 1000 funcionários para encontrar todas as linhas de um departamento específico.
Mark Sowul 30/09
Agora considere o caso oposto (o índice está em department_id, employee_id). Obviamente, é fácil encontrar um departamento em particular agora, mas também observe que, para encontrar um funcionário em particular, o SQL só precisa varrer cinco departamentos para encontrar todas as linhas de um funcionário em particular.
Mark Sowul 30/09