Aggiunta: SQL Server 2012 mostra alcune prestazioni migliorate in quest'area ma non sembra affrontare i problemi specifici indicati di seguito. Apparentemente questo dovrebbe essere risolto nella prossima versione principale dopo
SQL Server 2012!
Il tuo piano mostra che i singoli inserti utilizzano procedure parametrizzate (possibilmente parametrizzate automaticamente), quindi il tempo di analisi / compilazione per questi dovrebbe essere minimo.
Ho pensato di esaminarlo un po 'di più, quindi ho impostato un ciclo ( script ) e ho provato a regolare il numero di VALUES
clausole e registrare il tempo di compilazione.
Ho quindi diviso il tempo di compilazione per il numero di righe per ottenere il tempo di compilazione medio per clausola. I risultati sono di seguito
Fino a 250 VALUES
clausole presenti il tempo di compilazione / numero di clausole ha una leggera tendenza al rialzo ma niente di troppo drammatico.
Ma poi c'è un cambiamento improvviso.
Quella sezione dei dati è mostrata di seguito.
+------+----------------+-------------+---------------+---------------+
| 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 dimensione del piano memorizzato nella cache che era cresciuta in modo lineare diminuisce improvvisamente, ma CompileTime aumenta di 7 volte e CompileMemory spara. Questo è il punto di separazione tra il piano che è un piano auto parametrizzato (con 1.000 parametri) e uno non parametrizzato. Successivamente sembra diventare linearmente meno efficiente (in termini di numero di clausole di valore elaborate in un dato tempo).
Non sono sicuro del motivo per cui dovrebbe essere. Presumibilmente, quando compila un piano per valori letterali specifici, deve eseguire alcune attività che non vengono ridimensionate in modo lineare (come l'ordinamento).
Non sembra influenzare la dimensione del piano di query memorizzato nella cache quando ho provato una query composta interamente da righe duplicate e né influisce sull'ordine dell'output della tabella delle costanti (e mentre stai inserendo in un heap il tempo impiegato per l'ordinamento sarebbe comunque inutile anche se lo facesse).
Inoltre, se un indice cluster viene aggiunto alla tabella, il piano mostra ancora un passaggio di ordinamento esplicito, quindi non sembra essere l'ordinamento in fase di compilazione per evitare un ordinamento in fase di esecuzione.
Ho provato a guardarlo in un debugger ma i simboli pubblici per la mia versione di SQL Server 2008 non sembrano essere disponibili, quindi ho dovuto guardare la UNION ALL
costruzione equivalente in SQL Server 2005.
Di seguito è riportata una tipica traccia dello stack
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
Quindi, escludendo i nomi nella traccia dello stack, sembra che passi molto tempo a confrontare le stringhe.
Questo articolo della Knowledge Base indica che DeriveNormalizedGroupProperties
è associato a quella che veniva chiamata la fase di normalizzazione dell'elaborazione delle query
Questa fase è ora chiamata associazione o algebrizzazione e prende l'output dell'albero di analisi dell'espressione dalla fase di analisi precedente e genera un albero delle espressioni algebrizzato (albero del processore di query) per passare all'ottimizzazione (ottimizzazione del piano banale in questo caso) [ref] .
Ho provato un altro esperimento ( Script ) che era di rieseguire il test originale ma esaminando tre casi diversi.
- Stringhe di nome e cognome di 10 caratteri senza duplicati.
- Stringhe di nome e cognome di 50 caratteri senza duplicati.
- Stringhe di nome e cognome di 10 caratteri con tutti i duplicati.
Si può chiaramente vedere che più lunghe sono le stringhe, peggiori sono le cose e che viceversa più duplicati si ottengono le cose migliori. Come accennato in precedenza, i duplicati non influiscono sulla dimensione del piano memorizzato nella cache, quindi presumo che ci debba essere un processo di identificazione dei duplicati durante la costruzione dell'albero delle espressioni algebrizzato stesso.
modificare
Un punto in cui queste informazioni vengono sfruttate è mostrato da @Lieven qui
SELECT *
FROM (VALUES ('Lieven1', 1),
('Lieven2', 2),
('Lieven3', 3))Test (name, ID)
ORDER BY name, 1/ (ID - ID)
Poiché in fase di compilazione può determinare che la Name
colonna non ha duplicati, salta l'ordinamento in base 1/ (ID - ID)
all'espressione secondaria in fase di esecuzione (l'ordinamento nel piano ha solo una ORDER BY
colonna) e non viene generato alcun errore di divisione per zero. Se vengono aggiunti duplicati alla tabella, l'operatore di ordinamento mostra due ordini per colonne e viene generato l'errore previsto.