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

Kdy je lepší psát ad hoc sql vs uložené procedury

SQL Server ukládá prováděcí plány pro dotazy ad-hoc do mezipaměti, takže (s přihlédnutím k času, který zabere první volání), budou oba přístupy z hlediska rychlosti identické.

Obecně použití uložených procedur znamená vzít část kódu potřebného pro vaši aplikaci (dotazy T-SQL) a umístit ji na místo, které není pod kontrolou zdroje (může být, ale obvykle není ) a kde jej mohou ostatní bez vašeho vědomí změnit.

Mít dotazy na centrálním místě, jako je toto, může být dobrá věc, v závislosti na tom, kolik různých aplikací potřebuje přístup k datům, která představují. Obecně považuji za mnohem jednodušší ponechat dotazy používané aplikací rezidentní v samotném kódu aplikace.

V polovině 90. let konvenční moudrost říkala, že uložené procedury v SQL Serveru byly cestou v situacích kritických pro výkon, a v té době tomu tak rozhodně bylo. Důvody tohoto CW však již dlouho neplatí.

Aktualizace: V debatách o životaschopnosti uložených procedur se také často objevuje potřeba zabránit vkládání SQL na obranu procesů. Nikdo se zdravým rozumem si jistě nemyslí, že sestavení ad hoc dotazů pomocí řetězení řetězců je správná věc (ačkoli vás to vystaví útoku SQL injection pouze v případě, že zřetězujete uživatelský vstup ). Je zřejmé, že ad hoc dotazy by měly být parametrizovány, a to nejen proto, aby se zabránilo monstrum-under-the-bed útoku sql injection, ale také jen proto, aby byl váš život jako programátor obecně jednodušší (pokud vás nebaví zjišťovat, kdy použít single uvozovky kolem vašich hodnot).

Aktualizace 2: Udělal jsem další výzkum. Na základě této bílé knihy MSDN , zdá se, že odpověď závisí na tom, co přesně máte na mysli pod pojmem "ad-hoc" se svými dotazy. Například jednoduchý dotaz, jako je tento:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5

... bude mít jeho plán provádění uložený v mezipaměti. Navíc, protože dotaz neobsahuje určité diskvalifikační prvky (jako téměř cokoli jiného než jednoduchý SELECT z jedné tabulky), SQL Server ve skutečnosti dotaz „automaticky parametrizuje“ a nahradí doslovnou konstantu „5“ parametrem a mezipamětí. prováděcí plán pro parametrizovanou verzi. To znamená, že pokud potom provedete toto ad-hoc dotaz:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 23

... bude moci používat plán provádění uložený v mezipaměti.

Bohužel seznam diskvalifikujících prvků dotazu pro automatickou parametrizaci je dlouhý (například zapomeňte na použití DISTINCT , TOP , UNION , GROUP BY , OR atd.), takže s tímto výkonem opravdu nemůžete počítat.

Pokud máte „super složitý“ dotaz, který nebude automaticky parametrizován, například:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5 OR ITEM_COUNT < 23

... bude stále uložen do mezipaměti podle přesného textu dotazu, takže pokud vaše aplikace opakovaně volá tento dotaz se stejnými doslovnými „pevně zakódovanými“ hodnotami, každý dotaz po prvním znovu použije plán provádění v mezipaměti (a být tak rychlý jako uložený proces).

Pokud se doslovné hodnoty změní (na základě akcí uživatele, například filtrování nebo řazení zobrazených dat), pak dotazy nebudou mít z ukládání do mezipaměti prospěch (s výjimkou příležitostí, kdy se náhodně přesně shodují s nedávným dotazem).

Způsob, jak využít ukládání do mezipaměti s „ad-hoc“ dotazy, je jejich parametrizace. Vytvoření dotazu za chodu v C# takto:

int itemCount = 5;
string query = "DELETE FROM tblSTUFF WHERE ITEM_COUNT > " + 
        itemCount.ToString();

je nesprávné. Správný způsob (pomocí ADO.Net) by byl něco takového:

using (SqlConnection conn = new SqlConnection(connStr))
{
    SqlCommand com = new SqlCommand(conn);
    com.CommandType = CommandType.Text;
    com.CommandText = 
        "DELETE FROM tblSTUFF WHERE ITEM_COUNT > @ITEM_COUNT";
    int itemCount = 5;
    com.Parameters.AddWithValue("@ITEM_COUNT", itemCount);
    com.Prepare();
    com.ExecuteNonQuery();
}

Dotaz neobsahuje žádné literály a je již plně parametrizovaný, takže následné dotazy pomocí identického parametrizovaného příkazu by použily plán uložený v mezipaměti (i když by byly volány s různými hodnotami parametrů). Všimněte si, že kód je zde prakticky stejný jako kód, který byste stejně použili pro volání uložené procedury (jediným rozdílem je CommandType a CommandText), takže trochu jde o to, kde chcete, aby text tohoto dotazu „žil“. " (v kódu aplikace nebo v uložené proceduře).

A konečně, pokud „ad-hoc“ dotazy myslíte, že dynamicky vytváříte dotazy s různými sloupci, tabulkami, parametry filtrování a podobně, jako třeba tyto:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5

SELECT ID, FIRSTNAME, LASTNAME FROM tblPEEPS 
    WHERE AGE >= 18 AND LASTNAME LIKE '%What the`

SELECT ID, FIRSTNAME, LASTNAME FROM tblPEEPS 
    WHERE AGE >= 18 AND LASTNAME LIKE '%What the`
    ORDER BY LASTNAME DESC

... pak do velké míry nemůžete udělejte to s uloženými procedurami (bez EXEC hack, o kterém se ve zdvořilé společnosti nesmí mluvit), takže jde o diskutabilní.

Aktualizace 3: Zde je jediná opravdu dobrá související s výkonem důvod (který mě každopádně napadá) pro použití uložené procedury. Pokud je váš dotaz dlouhodobý, kde proces kompilace prováděcího plánu trvá výrazně déle než skutečné provedení a dotaz je volán jen zřídka (například měsíční sestava), pak jeho vložení do uložené procedury může zajistěte, aby SQL Server uchovával zkompilovaný plán v mezipaměti dostatečně dlouho, aby mohl být ještě příští měsíc. Poráží mě, jestli je to pravda nebo ne.



  1. sql Optimizer pro velkou tabulku DB

  2. Nahraný soubor csv nefunguje

  3. Náhrada podřetězce UPDATE PostgreSQL

  4. Jak sčítat a ODČÍTAT pomocí SQL?