Consulta do SQL Server lenta quando paginada

14

Estou vendo algum comportamento estranho com a seguinte consulta T-SQL no SQL Server 2012:

SELECT Id 
FROM dbo.Person 
WHERE CONTAINS(Name, '"John" AND "Smith"')
ORDER BY Name

Somente a execução dessa consulta fornece cerca de 1.300 resultados em menos de dois segundos (existe um índice de texto completo Name)

No entanto, quando altero a consulta para isso:

SELECT Id 
FROM dbo.Person 
WHERE CONTAINS(Name, '"John" AND "Smith"')
ORDER BY Name
OFFSET 0 rows
FETCH NEXT 10 ROWS ONLY

Demora mais de 20 segundos para me dar 10 resultados.

A seguinte consulta é ainda pior:

SELECT Id 
FROM ( 
    SELECT ROW_NUMBER() OVER (ORDER BY Name) AS RowNum, Id 
    FROM dbo.Person
    WHERE CONTAINS(Name, '"John" AND "Smith"') ) AS RowConstrainedResult 
WHERE RowNum >= 0 AND RowNum < 11 
ORDER BY RowNum

Demora mais de 1,5 minutos para concluir!

Alguma ideia?

Plano lento

Lento

Plano rápido

Rápido

vrs
fonte
O que acontece se você alterar sua segunda consulta para SELECT TOP 10 * .... ORDER BY Name?
Lamak 4/12/12
Em que colunas é feito o índice IX_PersonSearch ...? Você está procurando uma chave porque está selecionando * da tabela e o índice usado não contém todas as colunas de saída. Eu acho que você deve selecionar apenas as colunas necessárias e incluí-las no índice não agrupado como colunas incluídas, não colunas de índice.
Marcel N.
Você pode postar seus índices na tabela (criar script)?
3
O ID é sempre incluído em todos os índices não clusterizados. É dessa maneira que o SQL Server é capaz de realizar pesquisas de chave (por ID).
usr
1
O que eu esqueci de mencionar: Quando eu faço a mesma consulta com LIKE em vez de CONTAINS, é rápido também. (Paginado ou não)

Respostas:

7

Como você deseja apenas o TOP 10ordenado pelo nome, ele acha que será mais rápido trabalhar com o índice nameem ordem e verificar se cada linha corresponde ao CONTAINS(Name, '"John" AND "Smith"') )predicado.

Presumivelmente, são necessárias muitas outras linhas para encontrar as 10 correspondências necessárias e, em seguida, o esperado e esse problema de cardinalidade é agravado pelo número de pesquisas principais.

Um truque rápido para interrompê-lo usando esse plano seria alterar o ORDER BYpara, ORDER BY Name + ''embora o uso CONTAINSTABLEem conjunto com FORCE ORDERtambém deva funcionar.

Martin Smith
fonte
3

Parece uma estimativa errada de seletividade clássica. Não sei ao certo o que pode ser feito, pois o "driver" da consulta é a pesquisa de texto completo, que você não pode aumentar com as estatísticas.

Tente reescrever o where containspredicado em um inner join containstable( CONTAINSTABLE ) e aplique dicas de ordem de junção para forçar a forma do plano.

Essa não é uma solução perfeita porque tem problemas de manutenção, mas não vejo outra maneira.

usr
fonte
Obrigado pela sua resposta, eu tentei. Mesmo resultado: quando não estiver usando paginação, a consulta é realmente rápida. Ao paginar, de repente se torna realmente lento novamente: /
Ok, você pode postar o plano como uma imagem e sua consulta? Meu palpite é que ainda não conseguimos gerar a forma desejada.
usr
3

Consegui resolver o problema:

Como eu disse na pergunta, havia indizes em todas as colunas + estatísticas para cada coluna. (Por causa das consultas LIKE herdadas), removi todos os indicadores e estatísticas, adicionei a pesquisa de texto completo e pronto, a consulta se tornou muito rápida.

Parece que os índices levaram a um plano de execução diferente.

Muito obrigado a todos pela ajuda!

vrs
fonte
1
Bem, excluir o índice completamente é uma maneira de impedir que ele seja usado, eu acho!
Martin Smith