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

Problémy s výkonem parametrů tabulky

Pokud jsou TVP "znatelně pomalejší" než ostatní možnosti, pak je s největší pravděpodobností neimplementujete správně.

  1. Neměli byste používat DataTable, pokud to vaše aplikace nepoužívá mimo odesílání hodnot do TVP. Pomocí IEnumerable<SqlDataRecord> rozhraní je rychlejší a využívá méně paměti, protože neduplikujete kolekci v paměti pouze za účelem jejího odeslání do DB. Mám to zdokumentované na následujících místech:
  2. Neměli byste používat AddWithValue pro SqlParameter, i když to pravděpodobně není problém s výkonem. Ale přesto by to mělo být:

    SqlParameter tvp = com.Parameters.Add("data", SqlDbType.Structured);
    tvp.Value = MethodThatReturnsIEnumerable<SqlDataRecord>(MyCollection);
    
  3. TVP jsou proměnné tabulky a jako takové nevedou statistiky. To znamená, že mají pouze 1 řádek pro optimalizaci dotazů. Takže ve vašem procesu buď:
    • Použijte rekompilaci na úrovni příkazů pro jakékoli dotazy pomocí TVP pro cokoli jiného než jednoduchý SELECT:OPTION (RECOMPILE)
    • Vytvořte místní dočasnou tabulku (tj. jeden # ) a zkopírujte obsah TVP do dočasné tabulky
    • Můžete zkusit přidat seskupený primární klíč do uživatelem definovaného typu tabulky
    • Pokud používáte SQL Server 2014 nebo novější, můžete zkusit použít In-Memory OLTP / tabulky optimalizované pro paměť. Viz:Rychlejší dočasná tabulka a proměnná tabulky pomocí optimalizace paměti

O tom, proč se vám zobrazuje:

insert into @data ( ... fields ... ) values ( ... values ... )
-- for each row
insert into @data ( ... fields ... ) values ( ... values ... )

místo:

insert into @data ( ... fields ... ) 
values ( ... values ... ),
       ( ... values ... ),

POKUD se to skutečně děje, pak:

  • Pokud se vkládání provádí v rámci transakce, neexistuje žádný skutečný rozdíl ve výkonu
  • Novější syntaxe seznamu hodnot (tj. VALUES (row1), (row2), (row3) ) je omezena na něco jako 1000 řádků, a proto není životaschopnou možností pro TVP, které tento limit nemají. OVŠEM to není pravděpodobně důvod, proč se používají jednotlivé vložky, vzhledem k tomu, že neexistuje žádné omezení při provádění INSERT INTO @data (fields) SELECT tab.[col] FROM (VALUES (), (), ...) tab([col]) , kterou jsem zdokumentoval zde:Maximální počet řádků pro konstruktor hodnot tabulky . Místo toho...
  • Důvodem je s největší pravděpodobností to, že provádění jednotlivých vložení umožňuje streamování hodnot z kódu aplikace na SQL Server:
    1. pomocí iterátoru (tj. IEnumerable<SqlDataRecord> jak je uvedeno v bodě 1 výše), kód aplikace odešle každý řádek tak, jak je vrácen z metody, a
    2. vytváření VALUES (), (), ... seznam, i když provedete INSERT INTO ... SELECT FROM (VALUES ...) přístup (který není omezen na 1000 řádků), který by stále vyžadoval vytvoření celého VALUES seznam před odesláním jakéhokoli dat na SQL Server. Pokud existuje mnoho dat, vytvoření superdlouhého řetězce by trvalo déle a zabralo by to mnohem více paměti.

Podívejte se také na tento dokument od poradenského týmu pro zákazníky SQL Server:Maximalizace propustnosti pomocí TVP



  1. Připojte se k více databázím v CakePHP 3

  2. MySQL:Kdy jsou skutečně potřebná oprávnění Flush v MySQL?

  3. Získání počtu dvou různých sad řádků v tabulce a jejich rozdělení

  4. Převést pole datum a čas na pouhé datum v SQL (Oracle)