sql >> Databasteknik >  >> RDS >> Sqlserver

Flera INSERT-satser kontra enkla INSERT med flera VÄRDEN

Tillägg: SQL Server 2012 visar en viss förbättrad prestanda på detta område men verkar inte ta itu med de specifika problemen som anges nedan. Detta borde tydligen fixas i nästa större version efter SQL Server 2012!

Din plan visar att de enskilda inläggen använder parametriserade procedurer (möjligen autoparametriserade) så analys-/kompileringstiden för dessa bör vara minimal.

Jag tänkte att jag skulle undersöka det här lite mer, så skapa en loop (skript) och försökte justera antalet VALUES satser och registrera kompileringstiden.

Jag dividerade sedan kompileringstiden med antalet rader för att få den genomsnittliga kompileringstiden per klausul. Resultaten är nedan

Upp till 250 VALUES satser som presenterar kompileringstiden / antalet satser har en svag uppåtgående trend men inget för dramatiskt.

Men så sker en plötslig förändring.

Den delen av data visas nedan.

+------+----------------+-------------+---------------+---------------+
| 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   |
+------+----------------+-------------+---------------+---------------+

Den cachade planstorleken som hade vuxit linjärt sjunker plötsligt men CompileTime ökar 7 gånger och CompileMemory skjuter upp. Detta är gränsen mellan att planen är en automatisk parametriserad (med 1 000 parametrar) till en icke-parametriserad. Därefter verkar det bli linjärt mindre effektivt (i termer av antal värdeklausuler som behandlas under en given tid).

Inte säker på varför detta skulle vara. Förmodligen när den sammanställer en plan för specifika bokstavliga värden måste den utföra någon aktivitet som inte skalas linjärt (som sortering).

Det verkar inte påverka storleken på den cachade frågeplanen när jag försökte en fråga som helt bestod av dubbletter av rader och inte heller påverkar ordningen på utdata från tabellen med konstanter (och som du infogar i en hög tid för att sortera skulle ändå vara meningslöst även om det gjorde det).

Om dessutom ett klustrat index läggs till i tabellen visar planen fortfarande ett explicit sorteringssteg så att det inte verkar sortera vid kompilering för att undvika sortering vid körning.

Jag försökte titta på detta i en debugger men de offentliga symbolerna för min version av SQL Server 2008 verkar inte vara tillgängliga så istället var jag tvungen att titta på motsvarande UNION ALL konstruktion i SQL Server 2005.

En typisk stackspårning är nedan

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   

Så om man avviker från namnen i stackspåren verkar det spendera mycket tid på att jämföra strängar.

Den här KB-artikeln anger att DeriveNormalizedGroupProperties är associerat med vad som brukade kallas normaliseringsstadiet för frågebehandling

Det här steget kallas nu bindning eller algebrisering och det tar uttrycket parse tree-utdata från föregående parse-steg och matar ut ett algebriserat uttrycksträd (frågeprocessorträd) för att gå vidare till optimering (trivial planoptimering i detta fall) [ref].

Jag försökte ytterligare ett experiment (Script) som var att köra om det ursprungliga testet men titta på tre olika fall.

  1. Förnamn och efternamn Strängar med längd 10 tecken utan dubbletter.
  2. Förnamn och efternamn Strängar med längd 50 tecken utan dubbletter.
  3. Förnamn och efternamn Strängar med längd 10 tecken med alla dubbletter.

Det kan tydligt ses att ju längre strängarna desto sämre blir sakerna och att omvänt ju fler dubbletter desto bättre blir det. Som tidigare nämnts påverkar inte dubbletter den cachade planstorleken så jag antar att det måste finnas en process för dubblettidentifiering när man konstruerar själva det algebriserade uttrycksträdet.

Redigera

En plats där denna information utnyttjas visas av @Lieven här

SELECT * 
FROM (VALUES ('Lieven1', 1),
             ('Lieven2', 2),
             ('Lieven3', 3))Test (name, ID)
ORDER BY name, 1/ (ID - ID) 

Eftersom det vid kompilering kan fastställa att Name kolumnen har inga dubbletter den hoppar över beställning efter den sekundära 1/ (ID - ID) uttryck vid körning (sorteringen i planen har bara en ORDER BY kolumn) och inget divideringsfel med noll höjs. Om dubbletter läggs till i tabellen visar sorteringsoperatorn två ordningsföljder efter kolumner och det förväntade felet höjs.



  1. Tvinga Oracle att returnera de N-ÖVNA raderna med SKIP LÅST

  2. Konvertera den nya raden till XML i en Oracle Trigger

  3. Mallmönster och modifierare för formatering av datum/tid i PostgreSQL

  4. Handledning om SQL (DDL, DML) om exemplet på MS SQL Server-dialekt