Requête SQL Server lente lorsqu'elle est paginée

14

Je constate un comportement étrange avec la requête T-SQL suivante dans SQL Server 2012:

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

L'exécution de cette requête seule me donne environ 1 300 résultats en moins de deux secondes (il y a un index en texte intégral sur Name)

Cependant, lorsque je change la requête en ceci:

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

Il me faut plus de 20 secondes pour me donner 10 résultats.

La requête suivante est encore pire:

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

Il faut plus de 1,5 minutes pour terminer!

Des idées?

Plan lent

Lent

Plan rapide

Vite

vrs
la source
Que se passe-t-il si vous modifiez votre deuxième requête en SELECT TOP 10 * .... ORDER BY Name?
Lamak
Sur quelles colonnes l'index IX_PersonSearch ... est-il créé? Vous obtenez une recherche de clé car vous sélectionnez * dans la table et l'index utilisé ne contient pas toutes les colonnes de sortie. Je pense que vous devez sélectionner uniquement les colonnes dont vous avez besoin, puis les inclure dans l'index non groupé en tant que colonnes incluses, pas les colonnes d'index.
Marcel N.
Pouvez-vous publier vos index sur la table (créer un script)?
3
L'ID est toujours inclus dans chaque index non cluster. C'est ainsi que SQL Server est capable de rechercher des clés (par ID).
usr
1
Ce que j'ai oublié de mentionner: quand je fais la même requête avec LIKE au lieu de CONTAINS, c'est aussi rapide. (Paginé ou non)

Réponses:

7

Comme vous voulez juste que le TOP 10nom soit ordonné, il pense qu'il sera plus rapide de descendre l'index namedans l'ordre et de voir si chaque ligne correspond au CONTAINS(Name, '"John" AND "Smith"') )prédicat.

Vraisemblablement, il faut beaucoup plus de lignes pour trouver les 10 correspondances requises, puis il s'attend et ce problème de cardinalité est aggravé par le nombre de recherches de clés.

Un hack pour l' arrêter à l' aide de ce plan serait de changer ORDER BYà ORDER BY Name + ''bien que l' utilisation CONTAINSTABLEen conjonction avec FORCE ORDERdevrait également fonctionner.

Martin Smith
la source
3

Cela ressemble à une mauvaise estimation de la sélectivité classique. Je ne sais pas ce qui peut être fait à ce sujet car le "pilote" de la requête est une recherche plein texte que vous ne pouvez pas augmenter avec des statistiques.

Essayez de réécrire le where containsprédicat dans un inner join containstable( CONTAINSTABLE ) et appliquez des conseils d'ordre de jointure pour forcer la forme du plan.

Ce n'est pas une solution parfaite car il a des problèmes de maintenance, mais je ne vois pas d'autre façon.

usr
la source
Merci pour votre réponse, je l'ai essayé. Même résultat cependant: lorsque vous n'utilisez pas la pagination, la requête est très rapide. Lors de la pagination, cela redevient soudainement très lent: /
Ok pouvez-vous publier le plan sous forme d'image et votre requête? Je suppose que nous n'avons pas encore réussi à générer la forme souhaitée.
usr
3

J'ai réussi à résoudre le problème:

Comme je l'ai dit dans la question, il y avait des indizes sur toutes les colonnes + statistiques pour chaque colonne. (En raison des requêtes LIKE héritées), j'ai supprimé toutes les statistiques et les statistiques, ajouté la recherche en texte intégral et voilà, la requête est devenue très rapide.

Il semble que les indicateurs aient conduit à un plan d'exécution différent.

Merci beaucoup à tous pour votre aide!

vrs
la source
1
Eh bien, la suppression complète de l'index est un moyen de l'empêcher d'être utilisé, je suppose!
Martin Smith