Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Kiedy lepiej pisać ad hoc sql a procedury składowane?

SQL Server buforuje plany wykonania dla zapytań ad-hoc, więc (z pominięciem czasu zajętego przez pierwsze wywołanie) oba podejścia będą identyczne pod względem szybkości.

Ogólnie rzecz biorąc, użycie procedur składowanych oznacza pobranie części kodu potrzebnej aplikacji (zapytania T-SQL) i umieszczenie jej w miejscu, które nie jest pod kontrolą źródła (może być, ale zwykle nie jest ) i gdzie mogą być zmieniane przez innych bez Twojej wiedzy.

Umieszczenie zapytań w centralnym miejscu, takim jak to może być dobrą rzeczą, w zależności od tego, ile różnych aplikacji potrzebuje dostępu do danych, które reprezentują. Ogólnie uważam, że znacznie łatwiej jest przechowywać zapytania używane przez aplikację w samym kodzie aplikacji.

W połowie lat dziewięćdziesiątych konwencjonalna mądrość mówiła, że ​​procedury składowane w SQL Server były drogą do rozwiązania w sytuacjach krytycznych dla wydajności i w tamtych czasach zdecydowanie tak było. Jednak powody stojące za tym CW nie były aktualne przez długi czas.

Aktualizacja: Ponadto, często w debatach na temat wykonalności procedur składowanych, potrzeba zapobiegania wstrzykiwaniu SQL jest przywoływana w obronie proc. Z pewnością nikt przy zdrowych zmysłach nie myśli, że łączenie zapytań ad hoc poprzez łączenie ciągów jest właściwą rzeczą (chociaż narazi Cię to na atak typu SQL injection tylko wtedy, gdy łączysz dane wejściowe użytkownika ). Oczywiście zapytania ad hoc powinny być sparametryzowane, nie tylko po to, aby zapobiec atakom typu „wstrzyknięcie sql”, ale także po to, aby ułatwić sobie życie jako programisty (chyba że lubisz zastanawiać się, kiedy użyć pojedynczych cudzysłowy wokół Twoich wartości).

Aktualizacja 2: Zrobiłem więcej badań. Na podstawie tego oficjalnego dokumentu MSDN , wygląda na to, że odpowiedź zależy dokładnie od tego, co rozumiesz przez „ad hoc” w swoich zapytaniach. Na przykład proste zapytanie takie jak to:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5

... będzie mieć swój plan wykonania w pamięci podręcznej. Co więcej, ponieważ zapytanie nie zawiera pewnych elementów dyskwalifikujących (jak prawie nic innego niż prosty SELECT z jednej tabeli), SQL Server faktycznie „sparametryzuje” zapytanie i zastąpi dosłowną stałą „5” parametrem i pamięcią podręczną plan wykonania sparametryzowanej wersji. Oznacza to, że jeśli następnie wykonasz to zapytanie ad hoc:

SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 23

... będzie mógł korzystać z buforowanego planu wykonania.

Niestety lista dyskwalifikujących elementów zapytania do autoparametryzacji jest długa (na przykład zapomnij o używaniu DISTINCT , TOP , UNION , GROUP BY , OR itp.), więc naprawdę nie możesz liczyć na to, jeśli chodzi o wydajność.

Jeśli masz „super złożone” zapytanie, które nie będzie automatycznie sparametryzowane, na przykład:

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

... nadal będzie buforowany przez dokładny tekst zapytania, więc jeśli Twoja aplikacja wywołuje to zapytanie wielokrotnie z tymi samymi literami „zakodowanymi na sztywno” wartościami, każde zapytanie po pierwszym będzie ponownie wykorzystywać buforowany plan wykonania (i więc być tak szybki jak przechowywany proces).

Jeśli zmienią się wartości literalne (na podstawie działań użytkownika, na przykład takich jak filtrowanie lub sortowanie przeglądanych danych), zapytania nie będą korzystać z buforowania (z wyjątkiem sytuacji, gdy przypadkowo przypadkowo pasują do ostatniego zapytania).

Sposobem na czerpanie korzyści z buforowania za pomocą zapytań „ad-hoc” jest ich parametryzacja. Tworzenie zapytania w locie w C# w ten sposób:

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

jest nieprawidłowe. Prawidłowy sposób (przy użyciu ADO.Net) byłby taki:

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();
}

Zapytanie nie zawiera żadnych literałów i jest już w pełni sparametryzowane, więc kolejne zapytania korzystające z identycznej sparametryzowanej instrukcji będą korzystać z buforowanego planu (nawet jeśli są wywoływane z różnymi wartościami parametrów). Zwróć uwagę, że kod tutaj jest praktycznie taki sam, jak kod, którego i tak użyłbyś do wywołania procedury składowanej (jedyną różnicą jest CommandType i CommandText), więc nieco sprowadza się do miejsca, w którym chcesz, aby tekst tego zapytania „na żywo” " (w kodzie aplikacji lub w procedurze składowanej).

Na koniec, jeśli przez zapytania „ad-hoc” masz na myśli dynamiczne konstruowanie zapytań z różnymi kolumnami, tabelami, parametrami filtrowania i innymi rzeczami, na przykład może te:

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

... to prawie nie możesz zrób to za pomocą procedur składowanych (bez EXEC hack, o którym nie można mówić w grzecznym społeczeństwie), więc sprawa jest dyskusyjna.

Aktualizacja 3: Oto jedyny naprawdę dobry związany z wydajnością powód (który i tak mogę wymyślić) do korzystania z procedury składowanej. Jeśli zapytanie jest długotrwałe, a proces kompilowania planu wykonania trwa znacznie dłużej niż rzeczywiste wykonanie, a zapytanie jest wywoływane rzadko (na przykład raport miesięczny), umieszczenie go w procedurze składowanej może sprawiają, że SQL Server przechowuje skompilowany plan w pamięci podręcznej na tyle długo, aby nadal był dostępny w przyszłym miesiącu. Jednak bije mnie, jeśli to prawda, czy nie.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak uzyskać losowe wiersze z tabeli SQL Server — samouczek SQL Server / TSQL część 117

  2. Jak usunąć puste wiersze z wyniku zapytania sql?

  3. Jak zmienić kolumnę z wartości Null na Not Null w SQL Server

  4. Pyodbc:Błąd przekroczenia limitu czasu logowania

  5. SQLServer IDENTITY Kolumna z tekstem