SQL Server cachelagrar exekveringsplanerna för ad-hoc-frågor, så (räknat på tiden som det första anropet tar) kommer de två tillvägagångssätten att vara identiska när det gäller hastighet.
Generellt sett innebär användningen av lagrade procedurer att du tar en del av koden som behövs för din applikation (T-SQL-frågorna) och placerar den på en plats som inte är under källkontroll (det kan vara, men vanligtvis är det inte ) och där den kan ändras av andra utan din vetskap.
Att ha frågorna på en central plats som denna kan vara en bra sak, beroende på hur många olika applikationer som behöver tillgång till den data de representerar. Jag tycker i allmänhet att det är mycket lättare att behålla de frågor som används av en applikationsbosatt i själva applikationskoden.
I mitten av 1990-talet sa den konventionella visdomen att lagrade procedurer i SQL Server var rätt väg att gå i prestandakritiska situationer, och det var de definitivt vid den tiden. Skälen bakom denna CW har dock inte varit giltiga på länge.
Uppdatering: Dessutom, ofta i debatter om viabiliteten av lagrade procedurer, åberopas behovet av att förhindra SQL-injektion till försvar av processer. Säkert, ingen med sitt fulla sinne tror att sammansättning av ad hoc-frågor genom strängsammansättning är det rätta att göra (även om detta bara kommer att exponera dig för en SQL-injektionsattack om du sammanfogar användarinmatning ). Uppenbarligen bör ad hoc-frågor parametriseras, inte bara för att förhindra monster-under-bädden av en sql-injektionsattack, utan också bara för att göra ditt liv som programmerare generellt enklare (såvida du inte tycker om att behöva ta reda på när du ska använda singel citat kring dina värderingar).
Uppdatering 2: Jag har gjort mer forskning. Baserat på denna MSDN-vitbok , det verkar som att svaret beror på vad du menar med "ad-hoc" med dina frågor, exakt. Till exempel en enkel fråga som denna:
SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5
... kommer ha sin exekveringsplan cachad. Dessutom, eftersom frågan inte innehåller vissa diskvalificerande element (som nästan allt annat än en enkel SELECT från en tabell), kommer SQL Server faktiskt att "autoparameterisera" frågan och ersätta den bokstavliga konstanten "5" med en parameter och cache utförandeplanen för den parametrerade versionen. Det betyder att om du sedan kör detta ad-hoc-fråga:
SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 23
... den kommer att kunna använda den cachade exekveringsplanen.
Tyvärr är listan över diskvalificerande frågeelement för autoparameterisering lång (glöm till exempel att använda DISTINCT
, TOP
, UNION
, GROUP BY
, OR
etc.), så du kan verkligen inte räkna med detta för prestanda.
Om du har en "superkomplex" fråga som inte kommer att parametreras automatiskt, som:
SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5 OR ITEM_COUNT < 23
... den kommer fortfarande att cachelagras av den exakta texten i frågan, så om din applikation anropar den här frågan med samma bokstavliga "hårdkodade" värden upprepade gånger, kommer varje fråga efter den första att återanvända den cachade exekveringsplanen (och alltså vara lika snabb som en lagrad proc).
Om de bokstavliga värdena ändras (baserat på användaråtgärder, till exempel som filtrering eller sortering av visade data), kommer frågorna inte att dra nytta av cachelagring (förutom ibland när de av misstag matchar en ny fråga exakt).
Sättet att dra nytta av cachelagring med "ad-hoc"-frågor är att parametrisera dem. Skapa en fråga i farten i C# så här:
int itemCount = 5;
string query = "DELETE FROM tblSTUFF WHERE ITEM_COUNT > " +
itemCount.ToString();
är inkorrekt. Det korrekta sättet (med ADO.Net) skulle vara ungefär så här:
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();
}
Frågan innehåller inga bokstaver och är redan helt parametriserad, så efterföljande frågor som använder den identiska parametriserade satsen skulle använda den cachade planen (även om de anropades med olika parametervärden). Observera att koden här är praktiskt taget densamma som koden du skulle använda för att anropa en lagrad procedur ändå (den enda skillnaden är CommandType och CommandText), så det beror lite på var du vill att texten i den frågan ska "leva " (i din ansökningskod eller i en lagrad procedur).
Slutligen, om du med "ad-hoc"-frågor menar att du dynamiskt konstruerar frågor med olika kolumner, tabeller, filtreringsparametrar och annat, som kanske dessa:
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
... då kan du i stort sett inte gör detta med lagrade procedurer (utan EXEC
). hack som inte är att tala om i det artiga samhället), så poängen är omtvistad.
Uppdatering 3: Här är den enda riktigt bra prestandarelaterade anledning (som jag kan komma på i alla fall) för att använda en lagrad procedur. Om din fråga är en långvarig fråga där processen att kompilera exekveringsplanen tar betydligt längre tid än den faktiska exekveringen, och frågan bara anropas sällan (som en månadsrapport, till exempel), kan det hända att du lägger den i en lagrad procedur få SQL Server att behålla den kompilerade planen i cachen tillräckligt länge för att den fortfarande ska finnas kvar nästa månad. Det slår mig om det är sant eller inte.