Je teste différentes architectures pour de grandes tables et une suggestion que j'ai vue est d'utiliser une vue partitionnée, par laquelle une grande table est divisée en une série de tables plus petites et "partitionnées".
En testant cette approche, j'ai découvert quelque chose qui n'a pas beaucoup de sens pour moi. Lorsque je filtre sur "colonne de partitionnement" sur la vue des faits, l'optimiseur ne recherche que sur les tables pertinentes. De plus, si je filtre sur cette colonne de la table de dimension, l'optimiseur élimine les tables inutiles.
Cependant, si je filtre sur un autre aspect de la dimension que l'optimiseur recherche sur le PK / CI de chaque table de base.
Voici les requêtes en question:
select
od.[Year],
AvgValue = avg(ObservationValue)
from dbo.v_Observation o
join dbo.ObservationDates od
on o.ObservationDateKey = od.DateKey
where o.ObservationDateKey >= 20000101
and o.ObservationDateKey <= 20051231
group by od.[Year];
select
od.[Year],
AvgValue = avg(ObservationValue)
from dbo.v_Observation o
join dbo.ObservationDates od
on o.ObservationDateKey = od.DateKey
where od.DateKey >= 20000101
and od.DateKey <= 20051231
group by od.[Year];
select
od.[Year],
AvgValue = avg(ObservationValue)
from dbo.v_Observation o
join dbo.ObservationDates od
on o.ObservationDateKey = od.DateKey
where od.[Year] >= 2000 and od.[Year] < 2006
group by od.[Year];
Voici un lien vers la session SQL Sentry Plan Explorer.
Je travaille sur le partitionnement de la plus grande table pour voir si j'obtiens l'élimination de la partition pour répondre de la même manière.
J'obtiens l'élimination de partition pour la requête (simple) qui filtre sur un aspect de la dimension.
En attendant, voici une copie uniquement statistique de la base de données:
https://gist.github.com/swasheck/9a22bf8a580995d3b2aa
L'estimateur de cardinalité «ancien» obtient un plan moins cher, mais c'est à cause des estimations de cardinalité plus faibles pour chacun des indices (inutiles) recherchés.
Je voudrais savoir s'il existe un moyen pour que l'optimiseur utilise la colonne clé lors du filtrage par un autre aspect de la dimension afin qu'il puisse éliminer les recherches sur les tables non pertinentes.
Version de SQL Server:
Microsoft SQL Server 2014 - 12.0.2000.8 (X64)
Feb 20 2014 20:04:26
Copyright (c) Microsoft Corporation
Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)
la source
CREATE STATISTICS [_WA_Sys_00000008_2FCF1A8A] ON [dbo].[Observation_2010]([StationStateCode]) WITH STATS_STREAM = 0x01000000010000000000000000000000D4531EDB00000000D5080000000000009508000000000000AF030000AF000000020000000000000008D000340000000007000000E65DE0007DA5000076F9780000000000867704000000000000000000ABAAAA3C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
ObservationDates
tableau. Je ne reçois pas le même plan que Paul, même avec 4199, et je pense que c'est pourquoi.ObservationDates
. J'ai fini par courirUPDATE STATISTICS ObservationDates WITH ROWCOUNT = 10000
manuellement afin d'obtenir le plan que Paul a démontré.ObservationDates
donc je ne suis pas sûr de ce qui se passe avec ça. De plus, je ne peux pas non plus générer le plan généré par Paul. je vais essayer la mise à jour pour voir.Réponses:
Activez l'indicateur de trace 4199.
J'ai également dû émettre:
pour obtenir les plans indiqués ci-dessous. Les statistiques de ce tableau étaient manquantes lors du téléchargement. Le chiffre 73 049 provient des informations de cardinalité de la table dans la pièce jointe Plan Explorer. J'ai utilisé SQL Server 2014 SP1 CU4 (build 12.0.4436) avec deux processeurs logiques, une mémoire maximale définie sur 2048 Mo et aucun indicateur de trace en dehors de 4199.
Vous devriez ensuite obtenir un plan d'exécution qui comprend l'élimination dynamique des partitions:
Fragment de plan:
Cela peut sembler pire, mais les filtres sont tous des filtres de démarrage . Un exemple de prédicat est:
Par itération de la boucle, le prédicat de démarrage est testé, et ce n'est que s'il renvoie vrai que la recherche d'index cluster en dessous est exécutée. Par conséquent, élimination de partition dynamique.
Ceci est peut - être pas tout à fait aussi efficace que l' élimination statique, en particulier si le plan est parallèle.
Vous devrez peut-être essayer des astuces comme
MAXDOP 1
,FAST 1
ouFORCESEEK
sur la vue pour obtenir le même plan. Les choix de coût de l'optimiseur avec des vues partitionnées (comme les tables partitionnées) peuvent être délicats.Le fait est que vous avez besoin d'un plan qui comporte des filtres de démarrage pour obtenir l'élimination dynamique des partitions avec des vues partitionnées.
Requêtes avec des
USE PLAN
conseils intégrés : (via gist.github.com):la source
Mon observation a toujours été que vous devez spécifier explicitement la valeur (ou la plage de valeurs) pour la colonne de partition dans la requête afin d'obtenir "l'élimination de la table" dans une vue partitionnée. Ceci est basé sur l'expérience d'utilisation des vues partitionnées dans la production de SQL Server 2000 à SQL Server 2014.
SQL Server n'a pas de concept d'opérateur de jointure de boucle dans lequel le moteur peut viser dynamiquement la recherche directement sur la table appropriée sur le côté intérieur de la boucle en fonction de la valeur de la ligne sur le côté extérieur de la boucle. Cependant, comme l'explique la réponse de Paul , il existe la possibilité d'un plan avec des filtres de démarrage afin de sauter dynamiquement des tables non pertinentes sur le côté intérieur de la boucle en temps constant (par opposition à logarithmique en effectuant réellement la recherche).
Notez que pour les tables partitionnées, ce type de recherche (vers une partition spécifique) est pris en charge.
Si vous êtes déterminé à utiliser des vues partitionnées, une autre option consiste à diviser votre requête en plusieurs requêtes, telles que:
Cela donne le plan suivant. Il y a maintenant une requête supplémentaire qui frappe la table de dimension, mais la requête sur la table de faits (probablement beaucoup plus grande) est optimisée.
la source
20000101
et20051231
au lieu des variables (ou faire quelque chose de similaire via deux requêtes distinctes dans votre application), alors oui, le même effet serait obtenu sans utiliser les variables.