Ajout: SQL Server 2012 montre des performances améliorées dans ce domaine mais ne semble pas résoudre les problèmes spécifiques mentionnés ci-dessous. Cela devrait apparemment être corrigé dans la prochaine version majeure après
SQL Server 2012!
Votre plan montre que les insertions simples utilisent des procédures paramétrées (éventuellement auto-paramétrées), donc le temps d'analyse / compilation pour ceux-ci doit être minimal.
J'ai pensé que j'examinerais un peu plus cela, alors configurez une boucle ( script ) et essayez d'ajuster le nombre de VALUES
clauses et d'enregistrer le temps de compilation.
J'ai ensuite divisé le temps de compilation par le nombre de lignes pour obtenir le temps de compilation moyen par clause. Les résultats sont ci-dessous
Jusqu'à 250 VALUES
clauses présentes, le temps de compilation / le nombre de clauses a une légère tendance à la hausse mais rien de trop dramatique.
Mais ensuite, il y a un changement soudain.
Cette section des données est présentée ci-dessous.
+------+----------------+-------------+---------------+---------------+
| Rows | CachedPlanSize | CompileTime | CompileMemory | Duration/Rows |
+------+----------------+-------------+---------------+---------------+
| 245 | 528 | 41 | 2400 | 0.167346939 |
| 246 | 528 | 40 | 2416 | 0.162601626 |
| 247 | 528 | 38 | 2416 | 0.153846154 |
| 248 | 528 | 39 | 2432 | 0.157258065 |
| 249 | 528 | 39 | 2432 | 0.156626506 |
| 250 | 528 | 40 | 2448 | 0.16 |
| 251 | 400 | 273 | 3488 | 1.087649402 |
| 252 | 400 | 274 | 3496 | 1.087301587 |
| 253 | 400 | 282 | 3520 | 1.114624506 |
| 254 | 408 | 279 | 3544 | 1.098425197 |
| 255 | 408 | 290 | 3552 | 1.137254902 |
+------+----------------+-------------+---------------+---------------+
La taille du plan mis en cache, qui avait augmenté de manière linéaire, diminue soudainement, mais CompileTime augmente de 7 fois et CompileMemory augmente. C'est le point de coupure entre un plan paramétré automatiquement (avec 1000 paramètres) et un plan non paramétré. Par la suite, il semble devenir linéairement moins efficace (en termes de nombre de clauses de valeur traitées dans un temps donné).
Je ne sais pas pourquoi cela devrait être. Vraisemblablement, lorsqu'il compile un plan pour des valeurs littérales spécifiques, il doit effectuer une activité qui ne se met pas à l'échelle de manière linéaire (comme le tri).
Cela ne semble pas affecter la taille du plan de requête mis en cache lorsque j'ai essayé une requête composée entièrement de lignes en double et ni l'un ni l'autre n'affecte l'ordre de sortie de la table des constantes (et que vous insérez dans un tas de temps passé à trier serait de toute façon inutile même si c'était le cas).
De plus, si un index clusterisé est ajouté à la table, le plan affiche toujours une étape de tri explicite afin qu'il ne semble pas trier au moment de la compilation pour éviter un tri au moment de l'exécution.
J'ai essayé de regarder cela dans un débogueur mais les symboles publics de ma version de SQL Server 2008 ne semblent pas être disponibles, alors j'ai dû regarder la UNION ALL
construction équivalente dans SQL Server 2005.
Une trace de pile typique est ci-dessous
sqlservr.exe!FastDBCSToUnicode() + 0xac bytes
sqlservr.exe!nls_sqlhilo() + 0x35 bytes
sqlservr.exe!CXVariant::CmpCompareStr() + 0x2b bytes
sqlservr.exe!CXVariantPerformCompare<167,167>::Compare() + 0x18 bytes
sqlservr.exe!CXVariant::CmpCompare() + 0x11f67d bytes
sqlservr.exe!CConstraintItvl::PcnstrItvlUnion() + 0xe2 bytes
sqlservr.exe!CConstraintProp::PcnstrUnion() + 0x35e bytes
sqlservr.exe!CLogOp_BaseSetOp::PcnstrDerive() + 0x11a bytes
sqlservr.exe!CLogOpArg::PcnstrDeriveHandler() + 0x18f bytes
sqlservr.exe!CLogOpArg::DeriveGroupProperties() + 0xa9 bytes
sqlservr.exe!COpArg::DeriveNormalizedGroupProperties() + 0x40 bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x18a bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x146 bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x146 bytes
sqlservr.exe!COptExpr::DeriveGroupProperties() + 0x146 bytes
sqlservr.exe!CQuery::PqoBuild() + 0x3cb bytes
sqlservr.exe!CStmtQuery::InitQuery() + 0x167 bytes
sqlservr.exe!CStmtDML::InitNormal() + 0xf0 bytes
sqlservr.exe!CStmtDML::Init() + 0x1b bytes
sqlservr.exe!CCompPlan::FCompileStep() + 0x176 bytes
sqlservr.exe!CSQLSource::FCompile() + 0x741 bytes
sqlservr.exe!CSQLSource::FCompWrapper() + 0x922be bytes
sqlservr.exe!CSQLSource::Transform() + 0x120431 bytes
sqlservr.exe!CSQLSource::Compile() + 0x2ff bytes
Donc, en supprimant les noms dans la trace de la pile, il semble passer beaucoup de temps à comparer les chaînes.
Cet article de la base deDeriveNormalizedGroupProperties
connaissances indique qu'il est associé à ce que l'on appelait auparavant l' étape de normalisation du traitement des requêtes
Cette étape est maintenant appelée liaison ou algébrizing et elle prend la sortie de l'arbre d'analyse d'expression de l'étape d'analyse précédente et produit un arbre d'expression algébriqué (arbre du processeur de requête) pour aller de l'avant à l'optimisation (optimisation de plan trivial dans ce cas) [ref] .
J'ai essayé une autre expérience ( Script ) qui consistait à réexécuter le test d'origine mais en examinant trois cas différents.
- Prénom et nom Chaînes de 10 caractères sans doublons.
- Prénom et nom Chaînes de 50 caractères sans doublon.
- Prénom et nom Chaînes de 10 caractères avec tous les doublons.
On peut clairement voir que plus les chaînes sont longues, plus les choses se détériorent et qu'à l'inverse, plus il y a de doublons, meilleures sont les choses. Comme mentionné précédemment, les doublons n'affectent pas la taille du plan mis en cache, donc je suppose qu'il doit y avoir un processus d'identification des doublons lors de la construction de l'arbre d'expression algébriqué lui-même.
Éditer
Un endroit où ces informations sont exploitées est montré par @Lieven ici
SELECT *
FROM (VALUES ('Lieven1', 1),
('Lieven2', 2),
('Lieven3', 3))Test (name, ID)
ORDER BY name, 1/ (ID - ID)
Parce qu'au moment de la compilation, il peut déterminer que la Name
colonne n'a pas de doublons, il ignore 1/ (ID - ID)
le tri par expression secondaire au moment de l'exécution (le tri dans le plan n'a qu'une seule ORDER BY
colonne) et aucune erreur de division par zéro n'est déclenchée. Si des doublons sont ajoutés à la table, l'opérateur de tri affiche deux ordre par colonnes et l'erreur attendue est générée.