2008-11-19 20 views
26

Stwierdziłem, że procedury przechowywane SQL są bardzo interesujące i użyteczne. Napisałem procedury przechowywane, ale chcę napisać dobrze wykonane, dobrze dostrojone i zwięzłe SPs dla każdego rodzaju wymagań, a także chciałbym dowiedzieć się o wszelkich sztuczkach lub dobrych praktyk dla procedur przechowywanych. Jak przejść od początkującego do zaawansowanego w pisaniu procedur przechowywanych?Jakie są najlepsze praktyki w pisaniu procedura przechowywana sql

Aktualizacja: Zauważyłem, że moje pytanie powinno być bardziej szczegółowe. Każdy ma jakieś sztuczki na rękawach i spodziewałem się takich sztuczek i praktyk dla SP, których używają w swoim kodzie, który odróżnia je od innych i co ważniejsze, zwiększają wydajność w pisaniu i pracy z procedurami przechowywanymi.

+2

To jest podobne do powiedzenia: "Napisałem opowiadania, ale chcę napisać dobrze wykonane, bestsellery i powieści dla wszystkich rodzajów czytelników, a także chciałbym poznać jakieś sztuczki lub dobre praktyki pisania opowiadań." Może być bardziej konkretny w tym, czego szukasz ... –

+0

Uzgodnione, bardziej szczegółowe pytania byłyby dobre. – ahockley

Odpowiedz

17

Jedyna sztuczka, której zawsze staram się użyć, to: Zawsze dołączaj przykład użycia w komentarzu u góry. Jest to również przydatne do testowania SP. Chciałbym dołączyć najczęstsze przykłady - wtedy nawet nie potrzebujesz SQL Prompt lub osobnego pliku .sql ze swoim ulubionym wywołaniem, ponieważ jest ono przechowywane na serwerze (jest to szczególnie użyteczne, jeśli masz zapisane procsy, które wyglądają sp_who wyjście dla bloków lub czegoś podobnego i weź kilka parametrów).

Coś jak:

/* 
    Usage: 
    EXEC usp_ThisProc @Param1 = 1, @Param2 = 2 
*/ 

Następnie przetestować lub uruchom SP, wystarczy podkreślić, że punkt w skrypcie i wykonać.

1

To nie jest pytanie, na które można odpowiedzieć bezpośrednio, bez dodatkowych informacji, ale kilka ogólnych zasad naprawdę ma zastosowanie.

Procedury przechowywane to po prostu kwerendy T-SQL, które są przechowywane. Dlatego lepiej zapoznać się z T-SQL i różnymi funkcjami i składniami, które naprawdę potrzebujesz. A jeszcze bardziej z punktu widzenia wydajności, musisz upewnić się, że twoje zapytania i struktury danych są zgodne w sposób, który pozwala na dobrą wydajność. IE, upewnij się, że indeksy, relacje, ograniczenia itp. Są wdrażane w razie potrzeby.

Zrozumienie, jak korzystać z wydajnością narzędzia strojenia, understaning jak działają plany wykonawcze i rzeczy tego rodzaju są jak dostać się do tego „następnego poziomu”

11

To jest bardzo ogólne pytanie, ale oto kilka Porady:

  • Konsekwentnie nazwij swoje procedury składowane. Wielu używa prefiksu do określenia, że ​​jest to procedura składowana, ale nie używaj "sp_" jako przedrostka, jak to jest wyznaczone dla danych podstawowych (w SQL Server tak)
  • Ustaw NOCOUNT na, ponieważ zmniejsza to liczbę możliwych zwracane wartości
  • Zapytania oparte na zestawie często działają lepiej niż kursory. This question wchodzi w to znacznie bardziej szczegółowo.
  • Jeśli używasz zmiennych DECLARE dla swojej procedury przechowywanej, użyj dobrych konwencji nazewnictwa tak, jak chcesz/powinien w jakimkolwiek innym rodzaju programowania.
  • Wywoływanie usług SP przy użyciu ich w pełni kwalifikowanej nazwy w celu wyeliminowania wszelkich wątpliwości co do tego, który program SP powinien zostać wywołany, oraz w celu zwiększenia wydajności programu SQL Server; to ułatwia znalezienie danego SP.

Oczywiście jest o wiele więcej.Oto link z więcej: SQL Server Stored Procedures Optimization Tips

3

W SQL Server zawsze umieszczam oświadczenie, które upuści procedurę, jeśli istnieje, więc mogę łatwo odtworzyć procedurę podczas jej tworzenia. Coś jak:

 
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'usp') AND type in (N'P', N'PC')) 
DROP PROCEDURE usp 
+2

Można uprościć ten z: IF OBJECT_ID (N'dbo.usp ') IS NOT NULL PROCEDURA DROP dbo.usp GO TWORZENIE PROCEDURY dbo.usp ... – Tom

+0

nie jest to, co jest dla ALTER. .. – dotjoe

+3

tak alter może zrobić to samo cienkie, ale jeśli napiszesz to jako alter i pójdziesz umieścić go na serwerze po raz pierwszy to się nie powiedzie. Ten proces będzie działał niezależnie od tego, czy proces istnieje, czy nie. – HLGEM

0

podstawowe rzeczy:

posiadać politykę obsługi błędów i pułapek na wszystkich błędów SQL.
Wybierz strategię stosowania kontroli kodu źródłowego dla procedur składowanych.
Dołącz komentarz do nagłówka z użytkownikiem, datą/czasem i celem sp.
Jawnie zwraca 0 (sukces) dla pomyślnego wykonania, coś innego.
Dla nietrywialnych procedur należy uwzględnić przypadek testowy (lub sprawy) i opis oczekiwanego wyniku.
Nabierz nawyku sprawdzania wydajności. W przypadku przypadków tekstowych przynajmniej czas wykonania rekordu.
Zapoznaj się z jawnymi transakcjami i użyj ich.
Prawie nigdy nie należy wywoływać SP z SP. Wielokrotność użycia to inna gra w piłkę z SQL.

+0

dlaczego nie zadzwonić do SPs z SP? Robię to cały czas z konieczności; jeśli nie naruszam zasady DRY ...? –

+0

DRY dotyczy kodu proceduralnego, a nie deklaratywnego. Jeśli jest to logika proceduralna w sp, proponuję przenieść ją na inny poziom, gdzie z pewnością ma to sens. – dkretz

+1

Kolejny silny czynnik zniechęcający. Wielopoziomowe TRANNY ROLLBACK są * tak * wkręcane. – dkretz

1

To zależy w dużej mierze od tego, co robisz w przechowywanych procach. Jednak dobrym pomysłem jest użycie transakcji, jeśli wykonujesz wiele wstawień/aktualizacji lub usuwasz w jednym proc. W ten sposób, jeśli jedna część się nie powiedzie, pozostałe części zostaną wycofane, pozostawiając bazę danych w spójnym stanie.

Dwie najważniejsze kwestie, które należy wziąć pod uwagę podczas zapisu do bazy danych (a więc podczas korzystania z przechowywanego procesu, który wykonuje działanie inne niż wybrane), to integralność i wydajność danych. Bez integralności danych, masz tylko bazę danych, która zawiera śmieci i jest bezużyteczna. Bez performacne nie będziesz miał użytkowników (jeśli są poza klientami) lub nieszczęśliwych użytkowników (jeśli są upoważnieni do korzystania z twojego produktu, zwykle użytkownicy wewnętrzni, którzy nie mają wyboru, aby pójść gdzie indziej). Żadne z nich nie jest dobre dla twojej kariery. Tak więc, pisząc przechowywany proc, upewnij się, że najpierw upewnisz się, że dane zostaną poprawnie wprowadzone do bazy danych i że zawiedzie, jeśli wystąpi problem w jednej części akcji.

W razie potrzeby sprawdź, czy Twój wynik końcowy jest poprawny. Jestem specjalistą od ETL i zawsze piszę swoje procenty, aby dane zostały wyczyszczone i znormalizowane, zanim spróbuję zaimportować je do moich tabel. Jeśli robisz różne rzeczy z poziomu interfejsu użytkownika, może to nie być tak ważne, aby zrobić inthe proc, chociaż chciałbym, aby inteface użytkownika wykonał kontrole przed uruchomieniem procesu, aby upewnić się, że dane są dobre dla wstawki (rzeczy takie jak sprawdzanie, aby upewnić się, że pole daty zawiera rzeczywistą datę, że wszystkie wymagane pola mają wartości itd.)

Jeśli piszesz procsy, aby umieścić duże ilości danych w tabelach, najlepiej jest mieć sposób na przetestowanie tych wyników przed ich sfinalizowaniem . Byłbyś zaskoczony śmieciami, które otrzymasz od klientów i dostawców w celu importu danych. Piszemy wszystkie nasze procenty importu z flagą testową. W ten sposób możesz zwrócić wybrane dane zamiast wykonać akcję, dzięki czemu możesz zobaczyć z wyprzedzeniem dokładnie to, na co miałbyś wpływ.

Nie jestem fanem dynamicznego SQL i wolę nie używać go w przechowywanych procach. Jeśli utkniesz w dynamicznym SQl w istniejących procach, wstaw flagę debugowania, która pozwoli ci wydrukować SQL zamiast go wykonać. Następnie umieść w komentarzach najbardziej typowe przypadki, które trzeba będzie uruchomić. Przekonasz się, że możesz utrzymać proces znacznie lepiej, jeśli to zrobisz.

Nie rób rzeczy po kursie, tylko dlatego, że chcesz ponownie użyć innego zapisanego procesu, który działa tylko na jednej płycie w danym momencie. Ponowne użycie kodu, które powoduje problemy z wydajnością, jeśli coś złego.

Jeśli używasz instrukcji case lub instrukcji, upewnij się, że wykonałeś test, który trafi w każdą możliwą gałąź. Ten, którego nie przetestujesz, nie zawiedzie.

35

Oto moja procedura obsługi błędów przechowywanych procedur.

  • połączeń każda procedura przechowywana przy użyciu jego nazwy pełną celu zwiększenia wydajności: to nazwa serwera, nazwa bazy danych, schematu (właściciel) imię i nazwisko procedura.
  • W skrypcie, który tworzy każdą procedurę składowaną, należy wyraźnie określić, które role mogą wykonywać procedurę, np. Publiczną lub inną.
  • Użyj sysmessage, sp_addmessage i symboli zastępczych zamiast zakodowanych na stałe komunikatów o błędach.
  • Używając sp_addmessage i sysmessages, zawsze używaj numeru komunikatu o błędzie 50001 lub wyższego.
  • W przypadku RAISERROR zawsze podawaj poziom ważności < = 10 dla komunikatów ostrzegawczych.
  • W przypadku RAISERROR zawsze podawaj poziom istotności między 11 a 16 dla komunikatów o błędach.
  • Należy pamiętać, że użycie funkcji RAISERROR nie zawsze powoduje przerwanie dowolnej partii w toku, nawet w kontekście wyzwalacza.
  • Zapisz @@error na zmienną lokalną przed użyciem lub przesłuchaniem.
  • Zapisz @@ rowcount do zmiennej lokalnej przed użyciem lub przesłuchaniem.
  • Dla procedury składowanej użyj wartości zwracanej, aby wskazać tylko powodzenie/niepowodzenie, a nie inne/dodatkowe informacje.
  • Wartość powrotna procedury przechowywanej powinna być ustawiona na 0, aby wskazać powodzenie, niezerową dla wskazania niepowodzenia.
  • Ustaw ANSI_WARNINGS na ON - wykrywa wartości null w dowolnym zagregowanym przydziale i każde zadanie przekraczające maksymalną długość znaku lub kolumny binarnej.
  • Ustaw NOCOUNT na wiele różnych powodów.
  • Zastanów się dobrze, czy chcesz XACT_ABORT ON or OFF. Niezależnie od tego, w którą stronę pójdziesz, bądź konsekwentny.
  • Wyjdź z pierwszego błędu - implementuje model KISS.
  • Podczas wykonywania procedury składowanej zawsze sprawdź zarówno błąd @@, jak i wartość zwracaną. Na przykład:

    EXEC @err = AnyStoredProc @value 
    SET @save_error = @@error 
    -- NULLIF says that if @err is 0, this is the same as null 
    -- COALESCE returns the first non-null value in its arguments 
    SELECT @err = COALESCE(NULLIF(@err, 0), @save_error) 
    IF @err <> 0 BEGIN 
        -- Because stored proc may have started a tran it didn't commit 
        ROLLBACK TRANSACTION 
        RETURN @err 
    END 
    
  • Przy wykonywaniu lokalną procedurę przechowywaną, która powoduje błąd, zrobić rollback, ponieważ jest możliwe, że procedura zaczęli transakcję że nie zatwierdzenia lub wycofania.
  • Nie zakładaj, że tylko dlatego, że nie rozpocząłeś transakcji, nie ma żadnej aktywnej transakcji - dzwoniący mógł ją uruchomić.
  • Najlepiej, aby uniknąć wycofywania transakcji, która została rozpoczęta przez dzwoniącego - sprawdź więc, czy @@ transcount.
  • Ale w wyzwalaczu zawsze cofnij, ponieważ nie wiesz, czy wywołujący zainicjował aktywną transakcję (ponieważ wartość @@ transcount jest zawsze> = 1).
  • zawsze przechowywać i sprawdzić @@ błąd po następujących stwierdzeń:

    INSERT, DELETE, UPDATE 
    SELECT INTO 
    Invocation of stored procedures 
    invocation of dynamic SQL 
    COMMIT TRANSACTION 
    DECLARE and OPEN CURSOR 
    FETCH from cursor 
    WRITETEXT and UPDATETEXT 
    
  • Jeśli DECLARE CURSOR na nie kursorem na proces globalnego (domyślnie), wyda oświadczenie deallocate kursora.
  • Uważaj na błąd w UDF. Gdy wystąpi błąd w UDF, wykonanie funkcji jest natychmiast przerywane, podobnie jak zapytanie, które wywołało UDF - ale błąd @@ wynosi 0! W takich okolicznościach możesz chcieć uruchomić SET SET XACT_ABORT ON.
  • Jeśli chcesz używać dynamicznego SQL, spróbuj mieć tylko jedno WYBIERANIE w każdej partii, ponieważ błąd @@ ma tylko status ostatniego wykonanego polecenia. Najbardziej prawdopodobne błędy z partii dynamicznego SQL są błędami składni i nie są one obsługiwane przez SET XACT_ABORT ON.
+0

Dobra długa lista. Dzięki za wskazówki. – Shiham

+0

Z SQL 2012 zamiast sprawdzania błędu @@, aby zdecydować, czy konieczne jest wycofanie, można użyć XACT_STATE() http://technet.microsoft.com/en-us/library/ms189797.aspx – nojetlag

10
  1. Zawsze używaj SET NOCOUNT NA
  2. Jeśli zamierzasz wykonać dwa lub więcej wkładek/aktualizacje/usuwa, proszę użyć transakcji.
  3. Nigdy nie nadawaj nazw swoim procesom "sp_". SQL Server najpierw zajrzy do głównej bazy danych, a nie znajdzie go, a następnie zajrzy do bazy danych na drugim miejscu. Jeśli zmienisz nazwę proców, SQL Server najpierw zajrzy do twojej bazy danych.

Źle:

SET NOCOUNT ON 
BEGIN TRAN 
    INSERT... 
    UPDATE... 
COMMIT 

Lepiej, ale wygląda niechlujny i poważny ból kodu:

SET NOCOUNT ON 
BEGIN TRAN 
    INSERT... 
    IF @ErrorVar <> 0 
    BEGIN 
     RAISERROR(N'Message', 16, 1) 
     GOTO QuitWithRollback 
    END 

    UPDATE... 
    IF @ErrorVar <> 0 
    BEGIN 
     RAISERROR(N'Message', 16, 1) 
     GOTO QuitWithRollback 
    END 

    EXECUTE @ReturnCode = some_proc @some_param = 123 
    IF (@@ERROR <> 0 OR @ReturnCode <> 0) 
     GOTO QuitWithRollback 
COMMIT 
GOTO EndSave    
QuitWithRollback: 
    IF (@@TRANCOUNT > 0) 
     ROLLBACK TRANSACTION 
EndSave: 

Dobre: ​​

SET NOCOUNT ON 
SET XACT_ABORT ON 
BEGIN TRY 
    BEGIN TRAN 
    INSERT... 
    UPDATE... 
    COMMIT 
END TRY 
BEGIN CATCH 
    IF (XACT_STATE()) <> 0 
     ROLLBACK 
END CATCH 

Najlepszy:

SET NOCOUNT ON 
SET XACT_ABORT ON 
BEGIN TRAN 
    INSERT... 
    UPDATE... 
COMMIT 

Więc gdzie jest obsługa błędów w "najlepszym" rozwiązaniu? Nie potrzebujesz żadnych. Zobacz SET XACT_ABORT ON, co oznacza, że ​​wykonaj automatyczne wycofywanie, jeśli wystąpią jakiekolwiek błędy. Kod jest czystszy i łatwiejszy do odczytania, łatwiejszy do napisania i mniej wadliwy. Mniejsza liczba błędów, ponieważ nie ma szans na brak błędu, ponieważ SQL Server robi to teraz za Ciebie.

+0

Drogi Simon Hughes będzie proszę podać przykład z demo wstawić oświadczenie od początku do końca pisania procedury – sidhewsar

1

Z SQL Server 2008 użyj TRY ... konstruktu CATCH, który można użyć w ramach procedur przechowywanych T-SQL, aby zapewnić bardziej zgrabny mechanizm obsługi wyjątków niż był dostępny w poprzednich wersjach SQL Server, sprawdzając @@ BŁĄD (i często użycie instrukcji GOTO) po każdym słowie SQL.

  BEGIN TRY 
      one_or_more_sql_statements 
     END TRY 
     BEGIN CATCH 
      one_or_more_sql_statements 
     END CATCH 

Kiedy w bloku CATCH, można użyć następujących funkcji błędu do przechwytywania informacji o błędzie, która wywołała bloku catch,

  ERROR_NUMBER() 
     ERROR_MESSAGE() 
     ERROR_SEVERITY() 
     ERROR_STATE() 
     ERROR_LINE() 
     ERROR_PROCEDURE() 

przeciwieństwie @@ błędu, który jest zresetowanie przez każdego rachunku która jest wykonywana, informacja o błędzie pobrana przez funkcje błędu pozostaje stała w dowolnym miejscu w zakresie bloku CATCH instrukcji TRY ... CATCH. Te funkcje mogą umożliwić modulację obsługi błędów w jednej procedurze, dzięki czemu nie trzeba powtarzać kodu obsługi błędów w każdym bloku CATCH.

Powiązane problemy