COMO usa índice, CHARINDEX não?


22

Esta pergunta está relacionada à minha pergunta antiga . A consulta abaixo estava demorando 10 a 15 segundos para executar:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE (Charindex('123456789',CAST([company].dbo.[customer].[Phone no] AS VARCHAR(MAX)))>0) 

Em alguns artigos, vi que o uso CASTe CHARINDEXnão se beneficiarão da indexação. Existem também alguns artigos que afirmam que o uso LIKE '%abc%'não se beneficiará da indexação, enquanto LIKE 'abc%':

http://bytes.com/topic/sql-server/answers/81467-using-charindex-vs-like-where /programming/803783/sql-server-index-any-improvement-for -like-queries http://www.sqlservercentral.com/Forums/Topic186262-8-1.aspx#bm186568

No meu caso, posso reescrever a consulta como:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE [company].dbo.[customer].[Phone no]  LIKE '%123456789%'

Esta consulta fornece a mesma saída que a anterior. Eu criei um índice não clusterizado para a coluna Phone no. Quando executo essa consulta, ela é executada em apenas 1 segundo . Esta é uma grande mudança em comparação com 14 segundos anteriormente.

Como se LIKE '%123456789%'beneficia da indexação?

Por que os artigos listados afirmam que isso não melhora o desempenho?

Tentei reescrever a consulta para usar CHARINDEX, mas o desempenho ainda é lento. Por que CHARINDEXnão se beneficia da indexação como parece que a LIKEconsulta faz?

Consulta usando CHARINDEX:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

Plano de execução:

insira a descrição da imagem aqui

Consulta usando LIKE:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE[Company].dbo.[customer].[Phone no] LIKE '%9000413237%'

Plano de execução:

COMO plano de consulta

Respostas:


28

Como o LIKE '% 123456789%' se beneficia da indexação?

Só um pouco. O processador de consultas pode varrer todo o índice não clusterizado procurando correspondências em vez da tabela inteira (o índice clusterizado). Os índices não clusterizados são geralmente menores que a tabela em que são criados, portanto, a varredura do índice não clusterizado pode ser mais rápida.

A desvantagem é que todas as colunas necessárias à consulta que não estão incluídas na definição de índice não clusterizado devem ser consultadas na tabela base, por linha.

O otimizador toma uma decisão entre a varredura da tabela (índice clusterizado) e a varredura do índice não clusterizado com pesquisas, com base em estimativas de custo. Os custos estimados dependem, em grande medida, quantas linhas o otimizador espera seu LIKEou CHARINDEXpredicado para selecionar.

Por que os artigos listados afirmam que isso não melhora o desempenho?

Para uma LIKEcondição que não inicia com um curinga, o SQL Server pode executar uma verificação parcial do índice em vez de verificar a coisa toda. Por exemplo, LIKE 'A%pode ser avaliado corretamente testando apenas registros de índice >= 'A'e < 'B'(os valores exatos dos limites dependem do agrupamento).

Esse tipo de consulta pode usar a capacidade de busca de índices da árvore b: podemos ir diretamente para o primeiro registro >= 'A'usando a árvore b e, em seguida, avançar na ordem das chaves de índice até chegarmos a um registro que falha no < 'B'teste. Como precisamos aplicar o LIKEteste apenas a um número menor de linhas, o desempenho geralmente é melhor.

Por outro lado, LIKE '%Anão pode ser transformado em uma varredura parcial porque não sabemos por onde começar ou terminar; qualquer registro pode terminar 'A', portanto, não podemos melhorar a verificação de todo o índice e o teste de cada linha individualmente.

Tentei reescrever a consulta para usar CHARINDEX, mas o desempenho ainda é lento. Por que CHARINDEXnão se beneficia da indexação como parece a consulta LIKE?

O otimizador de consulta tem a mesma opção entre varrer a tabela (índice clusterizado) e varrer o índice não clusterizado (com pesquisas) nos dois casos.

A escolha é feita entre os dois com base na estimativa de custos . Acontece que o SQL Server pode produzir uma estimativa diferente para os dois métodos. Para a LIKEforma da consulta, a estimativa pode usar estatísticas especiais de cadeias para produzir uma estimativa razoavelmente precisa. O CHARINDEX > 0formulário produz uma estimativa com base em um palpite.

As diferentes estimativas são suficientes para fazer com que o otimizador escolha uma Varredura de índice clusterizado CHARINDEXe uma Varredura de índice não clusterizado com pesquisas para o LIKE. Se você forçar a CHARINDEXconsulta a usar o índice não clusterizado com uma dica, obterá o mesmo plano de para LIKEe o desempenho será o mesmo:

SELECT
    [Customer name],
    [Sl_No],
    [Id]
FROM dbo.customer WITH (INDEX (f))
WHERE 
    CHARINDEX('9000413237', [Phone no]) >0;

O número de linhas processadas em tempo de execução será o mesmo para os dois métodos, apenas que o LIKEformulário produz uma estimativa mais precisa nesse caso; portanto, o otimizador de consultas escolhe um plano melhor.

Se você precisar de LIKE %thing%pesquisas com frequência, considere uma técnica sobre a qual escrevi na Pesquisa de strings curinga no trigrama no SQL Server .


16

O SQL Server mantém estatísticas sobre substrings em colunas de seqüência de caracteres na forma de tentativas que podem ser usadas pela LIKEconsulta, mas não pela CHARINDEX.

Veja a seção Estatísticas de Resumo de String para mais informações sobre isso.

Algumas advertências importantes são que qualquer escape de curingas deve ser feito com a técnica proprietária de colchetes em vez da ESCAPEpalavra - chave e que, para cadeias com mais de 80 caracteres, apenas o primeiro e o último 40 caracteres são usados.

WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

usará apenas o palpite padrão para um predicado de desigualdade de que 30% das linhas serão retornadas.

A LIKEconsulta (no seu caso) presumivelmente estima que muito menos linhas corresponderão ao predicado.

Observe que o curinga principal ainda impede uma busca no índice. Um índice inteiro ainda é verificado, mas usa um índice mais estreito que o índice em cluster. O índice mais estreito não cobre todas as colunas usadas pela consulta, portanto, o segundo plano exige uma pesquisa de chave para recuperar as colunas ausentes.

É improvável que esse plano seja escolhido com a estimativa de 30%. O SQL Server considerará mais barato varrer todo o índice em cluster e evitar muitas pesquisas. Veja este artigo no ponto de inflexão para obter exemplos adicionais.


Eu não sou claro com sua explicação. Você está dizendo que usar like é melhor que charindex?
TI pesquisador

3
@ITresearcher - Sim, potencialmente, em vez de usar apenas um palpite de quantas linhas corresponderão à condição ( 30%), ele pode observar o LIKEpadrão fornecido e as estatísticas de resumo da sequência e obter uma estimativa mais precisa. Armado com isso, pode escolher um plano diferente e mais apropriado.
Martin Smith

3
... ou, no "pior dos casos", o mesmo plano.
Aaron Bertrand
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.