2010-06-19 10 views
2

Vous pouvez lire la trame de fond si vous le souhaitez, après avoir modifié mon index non cluster en un index clusterisé, les choses ont démarré beaucoup plus rapidement. Le problème avec le plan de requête initial prenant 2-3 secondes reste quand même. Cependant, l'indicateur de requête de plan de maintenance a été amélioré un peu.Mise en cache du plan de requête et performances

Backstory

J'ai un index inversé où je stocke des choses que je désire rechercher dans une implémentation simple de recherche (mais il n'y a rien de simple recherche).

Quand j'entre une requête comme celui-ci « ma br » il va créer cette SQL

SELECT EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p0 
INTERSECT 
SELECT EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p1 
[email protected] String --'ma%' 
[email protected] String --'br%' 

Pour chaque terme de recherche, il y a un autre INTERSECT et SELECT

Et pour la plupart cela fonctionne très bien . J'ai indexé la colonne Term correctement et vérifié les plans d'exécution pour les goulots d'étranglement potentiels. À l'heure actuelle, l'index contient environ 150 000 lignes et les recherches se font instantanément, comme prévu. Mais ce qui est un peu irritant, c'est que la première requête d'un certain rang prend beaucoup plus de temps à s'exécuter. Je parie que c'est parce que l'optimiseur de requête réévalue le plan d'exécution. Mais comment dois-je faire face à cela? Plus je lance de requêtes sur le serveur, moins il bloque, mais toutes les autres requêtes prennent environ 2-3 secondes de plus. Ce n'est pas un gros problème, mais parfois c'est beaucoup plus long et je ne vois pas d'où cela vient ni comment y faire face. Cela devrait être rapide comme l'éclair.

EDIT

schéma ressemble à ceci:

CREATE TABLE InvertedIndex (
    Term varchar(255) NOT NULL, 
    Ordinal tinyint NOT NULL, 
    EntityType tinyint NOT NULL, 
    EntityID int NOT NULL 
) 

Les deux indices sont les suivants:

CREATE NONCLUSTERED INDEX IX_InvertedIndex ON InvertedIndex (Term) 
INCLUDE (Ordinal, EntityType, EntityID) 

CREATE NONCLUSTERED INDEX IX_InvertedIndex_Reverse ON InvertedIndex (EntityType, EntityID) 

Cette substance reste, ce qui se passe, des besoins d'insertion et de suppression lorsque l'index (index inversé) Pour être mis à jour et, par conséquent, une reconstruction complète, cela affectera-t-il l'utilisation d'un PLAN D'INTERROGATION?

Voici un exemple de la requête complète c'est vraiment lent atm, 3-5 secondes et je ne peux pas comprendre pourquoi ... La clause ORDER BY est destinée à donner des mots qui correspondent à une certaine position ordre de tri plus élevé (se produire d'abord dans le jeu de résultats), cependant, ceci est devenu exponentiellement plus lent pour chaque terme de recherche.

WITH Search AS (
    SELECT EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p0 
    INTERSECT 
    SELECT EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p1 
    INTERSECT 
    SELECT EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p2 
) 
SELECT p.PersonID 
, p.FullName 
, p.Email 
, p.MobilePhone 
, p.HomeAddress 
, p.HomeCity 
FROM Search AS s 
INNER JOIN Person AS p ON p.PersonID = s.EntityID AND s.EntityType = @pPersonEntityType 
ORDER BY (CASE WHEN @p3 IN (SELECT Ordinal FROM InvertedIndex WHERE Term LIKE @p0 AND EntityID = s.EntityID AND EntityType = s.EntityType) THEN 0 ELSE 1 END) + (CASE WHEN @p4 IN (SELECT Ordinal FROM InvertedIndex WHERE Term LIKE @p1 AND EntityID = s.EntityID AND EntityType = s.EntityType) THEN 0 ELSE 1 END) + (CASE WHEN @p5 IN (SELECT Ordinal FROM InvertedIndex WHERE Term LIKE @p2 AND EntityID = s.EntityID AND EntityType = s.EntityType) THEN 0 ELSE 1 END) 
@p0 String --'ma%' 
@p1 String --'br%' 
@p2 String --'mi%' 
@p3 Int32 --1 
@p4 Int32 --2 
@p5 Int32 --3 

Le point de la requête ci-dessus est de rechercher tous les termes dans le InvertedIndex, puis, pour chaque terme de recherche il y a une Intersect, c'est le conjuction logique que je souhaite utiliser pour limiter la recherche. L'ordinal représente la position originale du mot quand il a été indexé. Chaque entrée dans InvertedIndex représente un tuple et si le terme de recherche correspond à un élément de ce n-uplet, il est considéré comme une meilleure correspondance. C'est pourquoi j'ai besoin de faire cet ordre génial avec des sous-requêtes. Mais c'est vraiment lent.

RÉPONSE

Si je change IX_InvertedIndex à un index ordonné en clusters il améliore la vitesse de requête par un ordre de grandeur (je ne sais pas pourquoi si):

CREATE CLUSTERED INDEX IX_InvertedIndex ON InvertedIndex (Term) 
+0

ça dépend ... Qu'est-ce que la table défintion et wha t les index sont définis? –

+0

Vous avez une clé primaire et un index cluster unique? – gbn

+0

Non, je n'en ai pas besoin. Au moins, je pars du principe qu'il n'y a aucune raison d'ajouter cela ici. Je me trompe? –

Répondre

2

Si vous apposent clauses INTERSECT alors chaque requête sera différente de. Je soupçonne (sur la base de ce que vous avez dit) que vous avez finalement un plan en cache pour chaque nombre de clauses INTERSECT. Une fois que vous avez le plan en cache, il fonctionne correctement.

Vous pouvez essayer plan guides, un pour chaque nombre de clauses INTERSECT. Dans le cas contraire, vous pouvez toujours avoir un seul résultat de sélection et de spool dans une table temporaire et une auto-jointure. Je ne sais pas comment cela fonctionnerait si ou si c'est une bonne idée.

Votre index devrait être mis sur INCLUDE terme avec pour EntityType, EntityID à couvrir trop

Modifier, après commentaire.

Vous pouvez essayer KEEP PLAN ou plan forcing too étant donné la relative simplicité pour aider à éviter ce qui ressemble à des recompilations.

Si c'était SQL Server 2008, je vous suggère OPTIMISE FOR UNKNOWN

Enfin, une autre pensée: faire match de types de données à travers le conseil d'administration?

Edit: Vous devez modifier l'index (Term, EntityType, Ordinal, EntityID) sans COMPREND Vous utilisez toutes colonnes dans les jointures ou les filtres

Vous devez également une clé primaire (terme ordinal) qui devrait être unqiue et en cluster.? aussi ,. il n'y a aucun avantage à ne pas avoir une part de mauvaises performances et les données fragmentées

et changer la requête à ceci:!

WITH Search AS 
(
    SELECT Ordinal, EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p0 AND EntityType = @pPersonEntityType 
    INTERSECT 
    SELECT Ordinal, EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p1 AND EntityType = @pPersonEntityType 
    INTERSECT 
    SELECT Ordinal, EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p2 AND EntityType = @pPersonEntityType 
) 
SELECT 
    p.PersonID, p.FullName, p.Email, p.MobilePhone, p.HomeAddress, p.HomeCity 
FROM 
    Search AS s 
    INNER JOIN 
    Person AS p ON p.PersonID = s.EntityID 
    LEFT JOIN 
    (SELECT 0 AS Ranking, @p3 AS RankOrdinal) O3 
    LEFT JOIN 
    (SELECT 0 AS Ranking, @p4 AS RankOrdinal) O4 
    LEFT JOIN 
    (SELECT 0 AS Ranking, @p5 AS RankOrdinal) O5 
ORDER BY --although, I can't see why you are doing + 
    ISNULL(O3.Ranking, 1) + 
    ISNULL(O4.Ranking, 1) + 
    ISNULL(O5.Ranking, 1) 
+0

L'index inclut EntityType, EntityID. Mais merci de le signaler. Je ne savais pas à ce sujet le mois dernier. Je vais enquêter sur les guides de plan. Bien que je veuille ajouter que le plan d'exécution semble changer plus souvent que cela. Juste changer les valeurs de recherche, toujours le même nombre, mais des valeurs différentes, peut provoquer cet arrêt brutal. –

+0

@ John Leidegren: Je voulais dire des plans de forçage pas des plans, désolé. Les guides de plan sont pour quand vous ne pouvez pas changer le SQL. Le forçage est quelque chose qui ajoute un indice de requête. – gbn

+0

J'ai essayé OPTIMIZE FOR UNKNOWN mais j'ai couru dans un mur quand c'était une fonctionnalité de SQL 2008. Je vais essayer MAINTENIR PLAN suivant. Je devrais éviter les guides de plan alors? N'a pas encore essayé ... –

Questions connexes