Esta pergunta é sobre o desempenho do índice do SQL Server com um varchar(2000)
índice INCLUDE
de cobertura.
Estou tentando melhorar o desempenho em um aplicativo de banco de dados lento e instável. Em alguns casos, os dados são acessados por meio de strings varchar grandes, com as consultas incluindo várias operações de string como SUBSTRING()
, SPACE()
e DATALENGTH()
. Aqui está um exemplo simplificado de acesso;
update fattable set col3 =
SUBSTRING(col3,1,10) + '*' +
SUBSTRING(col3,12,DATALENGTH(col3)-12)
from fattable where substring(col3,10,1) = 'A' and col2 = 2
O esquema fica assim:
CREATE TABLE [dbo].[FatTable](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[col1] [nchar](12) NOT NULL,
[col2] [int] NOT NULL,
[col3] [varchar](2000) NOT NULL, ...
O índice a seguir foi definido, com um campo de cobertura na coluna de texto grande.
CREATE NONCLUSTERED INDEX [IndexCol2Col3] ON [dbo].[FatTable] ( [col2] ASC )
INCLUDE( [col3] )
Pelo que li, é RUIM colocar grandes campos de dados em um índice. Tenho lido vários artigos, incluindo http://msdn.microsoft.com/en-us/library/ms190806.aspx , que discute o impacto da paginação e do tamanho do disco no desempenho do índice. Dito isto, o plano de consulta definitivamente usa o índice de cobertura. Não tenho informações suficientes para determinar quanto isso realmente está me custando em termos de carga do sistema. Eu sei que, no geral, o sistema está funcionando mal e estou preocupado que esse seja um dos problemas. Perguntas:
Colocar esta
varchar(2000)
coluna no índiceINCLUDE
é uma boa ideia?Como os
INCLUDE
campos são armazenados em nós folha, eles têm muito impacto no desempenho do índice?
Atualização: Obrigado pelas excelentes respostas! Esta é uma pergunta injusta de certa forma - como vocês dizem, não há resposta certa absoluta sem estatísticas e perfis reais. Como tantos problemas de desempenho, acho que a resposta é "depende".
Ever é uma palavra grande, mas, em geral, não, eu não colocaria um campo varchar(2000) em um INCLUDE.
E sim, a maneira como os dados são armazenados no nível da página pode afetar seriamente o desempenho do índice, dependendo de como o índice é usado.
O problema é que, quanto mais linhas de dados você pode colocar em uma página, menos páginas precisam ser acessadas, mais rápido é o seu sistema, na maior parte. Adicionar uma coluna muito grande significa menos informações armazenadas em uma página, portanto, no caso de buscas ou varreduras de intervalo, mais páginas devem ser lidas para recuperar os dados, tornando as coisas muito lentas.
Para saber com certeza se isso é um problema em sua consulta ou em seu sistema, você precisa monitorar as leituras, especialmente o número de páginas que a consulta usa.
Você pode revisar a chave de índice clusterizado atual e, talvez, criar
col2
a chave de índice clusterizado? Dessa forma, você obtém o comportamento 'incluir' de cobertura (já que os índices agrupados estão sempre 'incluindo' tudo) sem duplicar os dados. Isso, é claro, está sujeito a muitosif
ebut
, no entanto, talvez valha a pena considerar. Obviamente, se o índice clusterizado atual estiver impondo uma restrição (chave primária, exclusiva), essa restrição teria que ser movida para um índice não clusterizado.É difícil responder. Tudo vai depender da sua taxa de leitura:gravação. Você testou uma carga de trabalho ou simulou um ciclo de negócios inteiro em um sistema de teste, com e sem a coluna incluída? A pesquisa sem ele pode custar muito, mas se você estiver atualizando os dados com mais frequência do que lendo, pode ser bom.
Sei que estou atrasado para esta festa, mas indexaria exatamente as expressões usadas para localizar linhas, como substring(col3,10,1). Se toda a col3 for usada, eu indexaria CHECKSUM (col3) (entendendo que pode haver colisões, é claro).