sql >> Databáze >  >> RDS >> Sqlserver

Více příkazů INSERT vs. jeden příkaz INSERT s více VALUES

Dodatek: SQL Server 2012 vykazuje v této oblasti určitý zlepšený výkon, ale nezdá se, že by řešil konkrétní problémy uvedené níže. To by zřejmě mělo být opraveno v další hlavní verzi po SQL Server 2012!

Váš plán ukazuje, že jednotlivé vložky používají parametrizované procedury (možná automaticky parametrizované), takže doba jejich analýzy/kompilace by měla být minimální.

Myslel jsem, že se na to podívám trochu víc, takže jsem nastavil smyčku (skript) a zkusil upravit počet VALUES klauzule a záznam času kompilace.

Poté jsem vydělil dobu kompilace počtem řádků, abych získal průměrnou dobu kompilace na klauzuli. Výsledky jsou níže

Až do 250 VALUES klauzule představují čas kompilace / počet klauzulí má mírně rostoucí trend, ale není to příliš dramatické.

Ale pak dojde k náhlé změně.

Tato část dat je uvedena níže.

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

Velikost plánu uloženého v mezipaměti, která rostla lineárně, náhle poklesne, ale CompileTime se zvýší 7krát a CompileMemory vystřelí nahoru. Toto je hraniční bod mezi plánem, který je automaticky parametrizovaný (s 1 000 parametry) a neparametrickým plánem. Poté se zdá být lineárně méně efektivní (z hlediska počtu hodnotových klauzulí zpracovaných za daný čas).

Nejste si jisti, proč by to mělo být. Pravděpodobně při sestavování plánu pro konkrétní doslovné hodnoty musí provádět nějakou činnost, která se neškáluje lineárně (jako je třídění).

Nezdá se, že by to ovlivnilo velikost plánu dotazů uložených v mezipaměti, když jsem zkoušel dotaz sestávající výhradně z duplicitních řádků, a ani to neovlivňuje pořadí výstupu tabulky konstant (a když vkládáte do hromady čas strávený tříděním by stejně bylo zbytečné, i kdyby ano).

Navíc pokud je do tabulky přidán seskupený index, plán stále zobrazuje explicitní krok řazení, takže se nezdá, že by třídil v době kompilace, aby se zabránilo řazení za běhu.

Zkoušel jsem se na to podívat v debuggeru, ale zdá se, že veřejné symboly pro mou verzi SQL Server 2008 nejsou dostupné, takže jsem se musel podívat na ekvivalentní UNION ALL konstrukce v SQL Server 2005.

Typické trasování zásobníku je níže

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   

Takže když vynecháte názvy ve trasování zásobníku, zdá se, že strávíte spoustu času porovnáváním řetězců.

Tento článek znalostní báze uvádí, že DeriveNormalizedGroupProperties je spojen s tím, co se dříve nazývalo normalizační fáze zpracování dotazů

Tato fáze se nyní nazývá vazba nebo algebrizace a přebírá výstup stromu analýzy výrazů z předchozí fáze analýzy a vydává algebrizovaný strom výrazů (strom procesoru dotazů), aby pokračoval k optimalizaci (v tomto případě triviální optimalizace plánu) [ref].

Zkusil jsem ještě jeden experiment (Skript), který měl znovu spustit původní test, ale zkoumal jsem tři různé případy.

  1. Řetězce jména a příjmení o délce 10 znaků bez duplicit.
  2. Řetězce jména a příjmení o délce 50 znaků bez duplicit.
  3. Řetězce jména a příjmení o délce 10 znaků se všemi duplikáty.

Je jasně vidět, že čím delší struny, tím horší věci a naopak čím více duplikátů, tím lepší věci. Jak již bylo zmíněno, duplikáty neovlivňují velikost plánu uloženého v mezipaměti, takže předpokládám, že při vytváření samotného algebrizovaného stromu výrazů musí existovat proces duplicitní identifikace.

Upravit

Jedno místo, kde se tyto informace využívají, ukazuje @Lieven zde

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

Protože v době kompilace může určit, že Name sloupec nemá žádné duplikáty, přeskakuje řazení podle sekundárního 1/ (ID - ID) výraz za běhu (řazení v plánu má pouze jeden ORDER BY sloupec) a nevznikne chyba dělení nulou. Pokud jsou do tabulky přidány duplikáty, operátor řazení zobrazí dva sloupce a očekávaná chyba je vyvolána.



  1. Rekurze v Oracle

  2. Vraťte procento sady výsledků v SQL Server

  3. 4 způsoby, jak získat definici pohledu pomocí Transact-SQL

  4. Vytvářejte fyzické zálohy databází MariaDB nebo MySQL