O que torna uma instrução SQL sargável?

253

Por definição (pelo menos pelo que vi), sargable significa que uma consulta é capaz de fazer com que o mecanismo de consulta otimize o plano de execução que a consulta usa. Tentei procurar as respostas, mas não parece haver muito sobre o assunto. Portanto, a pergunta é: o que torna ou não uma consulta SQL sargable? Qualquer documentação seria muito apreciada.

Para referência: SARGable

DForck42
fonte
58
+1 para "sargable". Essa é a minha palavra do dia para hoje. :-P
BFree
1
Também devo acrescentar à resposta de Adam que as montanhas de informações são, na maioria dos casos, extremamente particulares a cada mecanismo de banco de dados.
28909 Hoagie
30
SARG = Pesquisar ARGument. O engraçado é que "SARG" em alemão significa "caixão", então eu sempre tenho que sorrir quando as pessoas falam sobre SARGABLE - capaz de ser colocado em um caixão? :-)
marc_s
A sargabilidade depende do seu ambiente. O MySQL está documentado aqui: dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Frank Farmer
Ter campos de texto livre em vez de "tabelas de pesquisa" também contraria o espírito de tornar uma consulta sargável. Os usuários cometem erros de ortografia ao inserir texto livre (por exemplo, nome da cidade), enquanto as tabelas de pesquisa forçam os usuários a escolher uma entrada com ortografia correta. Vale a pena o pequeno problema extra, porque isso pode ser indexado corretamente em vez de usar LIKE '% ...%' no predicado.
Engenheiro Reverso

Respostas:

256

A coisa mais comum que tornará uma consulta não sargável é incluir um campo dentro de uma função na cláusula where:

SELECT ... FROM ...
WHERE Year(myDate) = 2008

O otimizador de SQL não pode usar um índice no myDate, mesmo que exista. Ele literalmente terá que avaliar essa função para cada linha da tabela. Muito melhor para usar:

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

Alguns outros exemplos:

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 
BradC
fonte
7
A inclusão de uma função dentro de GROUP BYfará com que uma consulta se torne não sargável?
Mike Bailey
1
Alguns mecanismos de banco de dados (Oracle, PostgreSQL) suportam índices de expressões, não sabe?
Craig
3
Seria uma versão ainda melhor do WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))be SELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULL? Certa vez, um cara de otimização me disse que o uso de OR na cláusula where pode cancelar a consulta ..?
High Plains Grifter
2
@HighPlainsGrifter você deve usar um UNION ALL nessa consulta - sindicato tem um implícito distinta, que faz uma consulta muito mais caro do que ele precisa ser quando você tem que conjuntos de dados mutuamente exclusivos
Devin Lamothe
1
@BradC No MSSQL 2016, não há diferença no plano de execução entre Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'e Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL)). Ambos usam o índice em Nome completo e fazem uma busca por índice.
CEGRD 19/09/18
79

Não faça isso:

WHERE Field LIKE '%blah%'

Isso causa uma varredura de tabela / índice, porque o valor LIKE começa com um caractere curinga.

Não faça isso:

WHERE FUNCTION(Field) = 'BLAH'

Isso causa uma verificação de tabela / índice.

O servidor de banco de dados precisará avaliar FUNCTION () em todas as linhas da tabela e compará-lo com 'BLAH'.

Se possível, faça o contrário:

WHERE Field = INVERSE_FUNCTION('BLAH')

Isso executará INVERSE_FUNCTION () no parâmetro uma vez e ainda permitirá o uso do índice.

de praia
fonte
5
Sua sugestão com o lançamento da função realmente funcionaria apenas quando a função contornasse os dados (o que significa que f (f (n)) = n).
23620 Adam Robinson
5
Verdade. Considerei adicionar INVERSE_FUNCTION, mas não queria ser confuso. Eu vou mudar isso.
praia
9

Nesta resposta, presumo que o banco de dados tenha índices de cobertura suficientes. Há perguntas suficientes sobre esse tópico .

Muitas vezes a sargabilidade de uma consulta é determinada pelo ponto de inflexão dos índices relacionados. O ponto de inflexão define a diferença entre procurar e digitalizar um índice ao ingressar em uma tabela ou conjunto de resultados em outra. É claro que uma busca é muito mais rápida do que varrer uma tabela inteira, mas quando você precisa procurar muitas linhas, uma varredura pode fazer mais sentido.

Portanto, entre outras coisas, uma instrução SQL é mais sargável quando o otimizador espera que o número de linhas resultantes de uma tabela seja menor que o ponto de inflexão de um possível índice na tabela a seguir.

Você pode encontrar uma postagem e um exemplo detalhados aqui .

Dries Van Hansewijck
fonte
4

Para que uma operação seja considerada sargável, não basta apenas poder usar um índice existente. No exemplo acima, adicionar uma chamada de função a uma coluna indexada na cláusula where provavelmente ainda tiraria alguma vantagem do índice definido. Ele irá "varrer", ou seja, recuperar todos os valores dessa coluna (índice) e, em seguida, eliminar os que não corresponderem ao valor de filtro fornecido. Ainda não é eficiente o suficiente para tabelas com alto número de linhas. O que realmente define sargability é a capacidade de consulta para percorrer o índice da árvore b usando o método de pesquisa binária que depende da eliminação de meio conjunto para a matriz de itens classificados. No SQL, ele seria exibido no plano de execução como uma "busca de índice".

user2011845
fonte