La requête simple suivante prend une très longue période (plusieurs minutes) à exécuter.
J'ai un index: P>
SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem] FROM [fctWMAUA] (NOLOCK) AS [t0] WHERE SourceSystemKey = 1 GROUP BY [t0].[SourceSystemKey] UNION SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem] FROM [fctWMAUA] (NOLOCK) AS [t0] WHERE SourceSystemKey = 2 GROUP BY [t0].[SourceSystemKey] UNION SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem] FROM [fctWMAUA] (NOLOCK) AS [t0] WHERE SourceSystemKey = 3 GROUP BY [t0].[SourceSystemKey] /* AND SO ON TO 9 */
Prendre exactement la même requête et la reformatant comme suit me donne ces statistiques: p>
Il faut 31MS pour exécuter. P>
create index IX on [fctWMAUA] (SourceSystemKey, AsAtDateKey)
6 Réponses :
Essayez de dire à SQL Server d'utiliser l'index:
select cur.SourceSystemKey, cur.date from fctWMAUA cur left join fctWMAUA next on next.SourceSystemKey = next.SourceSystemKey and next.date > cur.date where next.SourceSystemKey is null and cur.SourceSystemKey in (1,2,3,4,5,6,7,8,9)
Essayé toutes vos suggestions. Toujours très lent. Union est toujours rapide.
Je réinscrit également les champs de l'index et cela ne change pas.
En regardant le plan, il a un peu de sens. Cette recherche initiale va trouver tous les enregistrements. Il n'y a que neuf systèmes source, et il cherche le lot.
L'ajout "option (groupe de hash)" ou "option (groupe de commandes)" à la fin de la requête a-t-elle une différence?
Salut Andomar, bonne suggestion. Le groupe Hash l'a amené à environ quinze secondes, ce qui est acceptable si je cache les résultats. Il est toujours étrange que je puisse avoir 32 ms de la version de l'Union et que rien ne se ferme sur le groupe par la version. La version de l'Union est une recherche et un sommet (1) pour chacune des requêtes super rapides. L'index ne peut sembler dupliquer cela.
J'ai restructuré la requête pour interroger les systèmes source, puis effectuer une requête interne à chacune des dates max. Cela utilise parfaitement l'index et prend environ 7 ms. Beaucoup plus rapide que le groupe, et aussi plus rapide que l'union. Sélectionnez SourceSystems.Sourcesystemkey (Sélectionnez Max (AsatDateDateKey) de FCTWMAUA où FCTWMAUA.SOURCESYKEY = SOURCESSYSTS.SOURCESSYKEY GROUPE DE FCTWMAUA.SOURCESSYKEY) MaxData de Sourceystems
WHERE SourceSystemKey >= 1 AND SourceSystemKey <= 9
Qu'entendez-vous par «Vous n'avez pas besoin de grouper par un champ fixe»? Il cherche la date maximale.
J'ai essayé les entre les deux et ça n'a rien changé. Il utilise l'index et l'index initial recherche de 665 millions de lignes. En utilisant l'Union, il cherche une ligne (Top 1) pour chaque MAX commandé correctement et son «super rapide. Sans l'Union, il cherche 665 millions de rangées et attire le lot. C'est fou. Les deux requêtes utilisent définitivement les mêmes index du plan.
Andomar: J'ai parlé du groupe en parlé parce que si vous mettez "où SourceSystemkey = 3", je ne peux voir aucun sens dans "groupe par SourceSystemkey" car il n'y a qu'un SourceSystemey. Il n'y a rien à regrouper, vous recherchez la valeur maximale absolue qui passe le filtre. Mais de toute façon l'optimiseur le sait et ne devrait pas être un problème. (Edit: Parler de la deuxième commande. Dans le premier cas, le groupe par est OK, évidemment)
@ j.a.estevan: SQL Server nécessite un groupe avant de vous permettre d'utiliser des agrégats comme max ()
Il n'est pas requis dans ce scénario. En général, il n'est pas nécessaire si vous n'avez pas besoin de grouper des données. Just Essayez (par exemple): Sélectionnez Max (Object_id) à partir de Sys.Tables Où s'appelle '% A%' Cela fonctionne bien dans SQL Server 2005.
Vous êtes correct, le groupe par n'est pas requis dans la version syndicale de la requête. J'étais copié / coller la requête. Cela n'affecte pas cependant le plan de requête.
@ j.a.estevan: merci, ça me sauvera beaucoup de taper!
Avez-vous essayé de créer un autre index juste sur la colonne SourceSystemkey? Le nombre élevé de lectures logiques lorsque vous utilisez cette colonne dans votre clause où la clause me fait penser qu'il fait une analyse index / table. Pourriez-vous exécuter le plan d'exécution à ce sujet et voir si c'est le cas? Le plan d'exécution pourrait également proposer une suggestion d'index. P>
Son difficile à dire sans regarder un plan d'exécution, mais vous voudrez peut-être essayer ce qui suit:
SELECT * FROM ( SELECT MAX(t0.AsAtDateKey) AS [Date], t0.SourceSystemKey AS SourceSystem FROM fctWMAUA (NOLOCK) AS t0 GROUP BY t0.SourceSystemKey ) WHERE SourceSystem in (1,2,3,4,5,6,7,8,9)
Utilisez dès que, de sorte que le filtrage arrive après le regroupement a eu lieu:
SELECT MAX(AsAtDateKey) AS [Date], SourceSystemKey AS SourceSystem FROM fctWMAUA (NOLOCK) GROUP BY SourceSystemKey HAVING SourceSystemKey in (1,2,3,4,5,6,7,8,9)
J'ai trouvé que la meilleure solution est la suivante. Il imite la version syndicale de la requête et fonctionne très rapidement.
40 Lectures logiques et un temps d'exécution de 3 ms. P>
SELECT [t3].[value] FROM [dimSourceSystem] AS [t0] OUTER APPLY ( SELECT MAX([t2].[value]) AS [value] FROM ( SELECT [t1].[AsAtDateKey] AS [value], [t1].[SourceSystemKey] FROM [fctWMAUA] AS [t1] ) AS [t2] WHERE [t2].[SourceSystemKey] = ([t0].[SourceSystemKey]) ) AS [t3]
Avez-vous un index sur SourceSystemkey? Sinon, je pense que vous risquez d'induire une numérisation de table complète.
Qu'est-ce que Showplan montre? et quelles valeurs peuvent prendre SourceSystemkey?