Każda aplikacja oparta na bazie danych w końcu osiąga punkt, w którym zapytania SQL rozproszone w kodzie aplikacji stają się problemem konserwacyjnym. To samo złożone łączenie występuje w trzech różnych usługach. Logika biznesowa należąca do warstwy bazy danych przecieka do aplikacji. Zasady bezpieczeństwa, które powinny być egzekwowane na poziomie danych, są zamiast tego egzekwowane niespójnie przez kod aplikacji, który można ominąć. Procedury składowane rozwiązują ten typ problemu, przenosząc wielokrotnego użytku, wrażliwą na bezpieczeństwo i krytyczną dla wydajności logikę SQL do bazy danych, gdzie można nią zarządzać, wersjonować ją, zabezpieczać i optymalizować niezależnie od aplikacji, które ją wywołują.
Procedura składowana to nazwany, wstępnie skompilowany zestaw instrukcji SQL przechowywany w bazie danych i wykonywany jako jednostka. Akceptuje parametry, zawiera logikę i może zwracać wyniki, parametry wyjściowe lub kody statusu. W przeciwieństwie do zapytań ad hoc wysyłanych przez kod aplikacji, procedura składowana jest parsowana i kompilowana raz, a jej plan wykonania jest buforowany i ponownie wykorzystywany przy każdym kolejnym wywołaniu, co eliminuje obciążenie kompilacji związane z powtarzaniem dynamicznego SQL. Ten przewodnik omawia, czym są procedury składowane, kiedy ich używać, jak wymuszają one bezpieczeństwo, jak wpływają na wydajność oraz jak nimi zarządzać, gdy przekształcają się w zależności obejmujące całą bazę danych.
Określ zakres każdej zmiany w bazie danych przed jej uruchomieniem
SMART TS XL mapuje zależności procedur składowanych w językach SQL, COBOL, Java i Python jednocześnie.
Więcej informacjiCzym jest procedura składowana?
Procedura składowana to prekompilowana procedura przechowywana w relacyjnej bazie danych i wywoływana po nazwie z opcjonalnymi parametrami. Silnik bazy danych kompiluje ją raz, buforuje plan wykonania i ponownie wykorzystuje go przy każdym kolejnym wywołaniu, unikając cyklu analizy składniowej-kompilacji-optymalizacji, który jest wymagany w przypadku zapytań SQL ad hoc przy każdym uruchomieniu.
sql
-- SQL Server: basic stored procedure
CREATE PROCEDURE GetCustomerOrders
@CustomerId INT,
@StartDate DATE,
@EndDate DATE
AS
BEGIN
SET NOCOUNT ON;
SELECT
o.OrderId,
o.OrderDate,
o.TotalAmount,
o.Status
FROM Orders o
WHERE o.CustomerId = @CustomerId
AND o.OrderDate BETWEEN @StartDate AND @EndDate
ORDER BY o.OrderDate DESC;
END;
GO
-- Calling the procedure
EXEC GetCustomerOrders
@CustomerId = 12345,
@StartDate = '2026-01-01',
@EndDate = '2026-06-30';
Aplikacja nigdy nie pisze bezpośrednio kodu SQL. Wywołuje GetCustomerOrders z parametrami. Baza danych zajmie się resztą.
Procedura składowana kontra widok kontra funkcja
Trzy obiekty bazy danych są często mylone. Poniższa tabela je rozróżnia:
| przedmiot | Zwroty | Akceptuje parametry | Możliwość modyfikacji danych | Plan wykonania zapisany w pamięci podręcznej | Najlepsze dla: |
|---|---|---|---|---|---|
| Procedura składowana | Zestawy wyników, parametry wyjściowe, kody powrotu | Tak | Tak | Tak | Złożona logika, operacje DML, egzekwowanie zabezpieczeń |
| Zobacz | Pojedynczy zestaw wyników (jak tabela) | Nie | Nie (normalnie) | Częściowa | Uproszczenie zapytań SELECT, zabezpieczenia na poziomie kolumn |
| Funkcja skalarna | Pojedyncza wartość | Tak | Nie | Nie | Obliczenia ponownie wykorzystane na listach SELECT |
| Funkcja o wartościach tabelarycznych | Zestaw wyników | Tak | Nie | Częściowa | Widoki parametryczne, obliczenia zwracające zbiory |
Kluczowa różnica: Użyj widoku, gdy potrzebujesz abstrakcji SELECT wielokrotnego użytku. Użyj procedury składowanej, gdy potrzebujesz parametrów, logiki warunkowej, modyfikacji danych lub egzekwowania zabezpieczeń. Użyj funkcji, gdy potrzebujesz obliczenia, które zwraca wartość lub tabelę i musi być skomponowane z innym zapytaniem SQL.
Cztery podstawowe korzyści
Wydajność: kompilacja wstępna i buforowanie planu
Gdy SQL Server, PostgreSQL lub Oracle odbiera wywołanie procedury składowanej, sprawdza, czy istnieje dla niej buforowany plan wykonania. Jeśli tak, procedura jest wykonywana natychmiast. Jeśli nie, kompiluje procedurę, generuje plan wykonania, buforuje go i wykonuje. Przy każdym kolejnym wywołaniu buforowany plan jest ponownie wykorzystywany.
Zapytania SQL ad hoc, czyli zapytania łączone z ciągów znaków wysyłane z kodu aplikacji, mogą być rekompilowane przy każdym wywołaniu, w zależności od bazy danych i struktury zapytania. W przypadku zapytań o wysokiej częstotliwości, wywoływanych tysiące razy na sekundę, ten narzut kompilacji jest znaczący.
sql
-- Demonstrating plan reuse in SQL Server
-- Check if a plan exists for a procedure
SELECT
qs.execution_count,
qs.total_elapsed_time / qs.execution_count AS avg_elapsed_ms,
qs.total_logical_reads / qs.execution_count AS avg_logical_reads,
SUBSTRING(qt.text, 1, 100) AS procedure_text
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
WHERE qt.text LIKE '%GetCustomerOrders%'
ORDER BY qs.execution_count DESC;
Drugą korzyścią pod względem wydajności jest mniejszy ruch sieciowy . Zamiast wysyłać złożone, 30-wierszowe zapytanie SQL z aplikacji do bazy danych przy każdym wywołaniu, aplikacja wysyła krótkie wywołanie procedury. Obciążenie sieciowe jest minimalne. Baza danych wykonuje intensywne obliczenia po stronie serwera i zwraca jedynie zbiór wyników.
Bezpieczeństwo: Ograniczanie bezpośredniego dostępu do tabeli
To właśnie tej korzyści szukają dane SC: „jak używać procedur składowanych, aby ograniczyć bezpośredni dostęp do danych i zwiększyć bezpieczeństwo bazy danych”. Mechanizm ten jest prosty i skuteczny.
Przyznaj użytkownikom aplikacji uprawnienia do wykonywania procedur składowanych. Zabroń bezpośredniego dostępu do tabel bazowych. Użytkownik może wywołać procedurę, ale nie może bezpośrednio wykonywać zapytań, wstawiać danych, aktualizować ani usuwać danych z tabeli.
sql
-- Create a role for application users
CREATE ROLE AppReadRole;
-- Grant execute on the procedure
GRANT EXECUTE ON GetCustomerOrders TO AppReadRole;
-- Deny direct table access
DENY SELECT ON Orders TO AppReadRole;
DENY SELECT ON Customers TO AppReadRole;
-- The user can now:
-- EXEC GetCustomerOrders @CustomerId=123, ... -> works
-- SELECT * FROM Orders WHERE ... -> ACCESS DENIED
Drugą korzyścią z bezpieczeństwa jest zapobieganie atakom typu SQL injection . Procedury składowane, które wykorzystują sparametryzowane dane wejściowe zamiast dynamicznej konstrukcji SQL, są z natury chronione przed atakami typu SQL injection. Wartość parametru jest traktowana jako literał, a nie jako kod SQL.
sql
-- VULNERABLE: dynamic SQL built from user input
DECLARE @sql NVARCHAR(500);
SET @sql = 'SELECT * FROM Customers WHERE Name = ''' + @UserInput + '''';
EXEC(@sql);
-- An attacker can inject: '; DROP TABLE Customers; --
-- SAFE: parameterized stored procedure
CREATE PROCEDURE GetCustomerByName
@CustomerName NVARCHAR(100)
AS
BEGIN
SELECT CustomerId, Name, Email
FROM Customers
WHERE Name = @CustomerName; -- @CustomerName is a literal, not SQL
END;
Uważaj: Procedura składowana, która wewnętrznie buduje dynamiczny kod SQL przy użyciu
EXEC()orsp_executesqlKonkatenacja ciągów znaków wprowadzanych przez użytkownika jest równie podatna na ataki, co dynamiczny SQL na poziomie aplikacji. Parametryzacja musi obejmować każdy dynamiczny SQL skonstruowany wewnątrz procedury.
Utrzymywalność: jedna zmiana, wszystkie aplikacje zaktualizowane
Gdy logika biznesowa ulega zmianie, zasady obliczania podatków, poziomy rabatów, transformacje danych wymagane w celu zapewnienia zgodności, procedura składowana centralizuje tę logikę w jednym miejscu. Każda aplikacja, która wywołuje tę procedurę, automatycznie otrzymuje zaktualizowane zachowanie, bez konieczności ponownego wdrażania.
sql
-- Before: discount logic duplicated in three application services
-- After: centralized in one stored procedure
CREATE PROCEDURE CalculateOrderTotal
@OrderId INT,
@DiscountedTotal DECIMAL(10,2) OUTPUT
AS
BEGIN
DECLARE @Subtotal DECIMAL(10,2);
DECLARE @CustomerTier NCHAR(1);
SELECT @Subtotal = SUM(li.Quantity * li.UnitPrice),
@CustomerTier = c.Tier
FROM OrderLineItems li
JOIN Orders o ON o.OrderId = li.OrderId
JOIN Customers c ON c.CustomerId = o.CustomerId
WHERE li.OrderId = @OrderId
GROUP BY c.Tier;
-- Business rule: Gold customers get 15%, Silver get 8%, Standard get 0%
SET @DiscountedTotal = @Subtotal * CASE @CustomerTier
WHEN 'G' THEN 0.85
WHEN 'S' THEN 0.92
ELSE 1.00
END;
END;
Zmień procenty rabatów w jednym miejscu. Wszystkie trzy usługi aplikacyjne, które wywołują CalculateOrderTotal natychmiast odzwierciedlają nowe stawki.
Kapsułkowanie z parametrami wyjściowymi i obsługą błędów
Procedury składowane zwracają wiele wartości za pośrednictwem parametrów wyjściowych i przekazują stan przetwarzania za pośrednictwem kodów zwrotnych, umożliwiając bogatsze wzorce interakcji niż proste polecenie SELECT.
sql
CREATE PROCEDURE InsertOrder
@CustomerId INT,
@OrderDate DATE,
@NewOrderId INT OUTPUT,
@StatusCode INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO Orders (CustomerId, OrderDate, Status)
VALUES (@CustomerId, @OrderDate, 'PENDING');
SET @NewOrderId = SCOPE_IDENTITY();
SET @StatusCode = 0; -- success
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
SET @StatusCode = ERROR_NUMBER();
SET @NewOrderId = -1;
END CATCH;
END;
-- Usage
DECLARE @OrderId INT, @Status INT;
EXEC InsertOrder
@CustomerId = 5001,
@OrderDate = '2026-07-15',
@NewOrderId = @OrderId OUTPUT,
@StatusCode = @Status OUTPUT;
IF @Status <> 0
PRINT 'Insert failed with error: ' + CAST(@Status AS VARCHAR);
ELSE
PRINT 'Created order: ' + CAST(@OrderId AS VARCHAR);
Optymalizacja wydajności: co mówi Ci plan wykonania
Plan wykonania to zapis silnika bazy danych dotyczący sposobu wykonania zapytania, użytych indeksów, wybranego algorytmu łączenia oraz szacowanej liczby wierszy na każdym kroku. W przypadku procedury składowanej wywoływanej tysiące razy dziennie, plan wykonania jest podstawowym narzędziem diagnostycznym problemów z wydajnością.
sql
-- Enable actual execution plan in SQL Server
-- Then run:
EXEC GetCustomerOrders
@CustomerId = 12345,
@StartDate = '2026-01-01',
@EndDate = '2026-06-30';
-- Check for parameter sniffing issues
-- (cached plan was optimized for a different parameter distribution)
EXEC GetCustomerOrders
@CustomerId = 99999, -- rare customer with very few orders
@StartDate = '2026-01-01',
@EndDate = '2026-06-30'
WITH RECOMPILE; -- forces fresh plan for this call
Podsłuchiwanie parametrów (parameter sniffing) to najczęstszy problem z wydajnością procedur składowanych. SQL Server buforuje plan wykonania wygenerowany dla pierwszego zestawu parametrów, z którym wywołana jest procedura. Jeśli kolejne wywołania używają bardzo różnych wartości parametrów, np. klienta z 50 000 zamówień i klienta z 2 zamówieniami, buforowany plan może być wysoce nieoptymalny dla tych wartości.
Strategie łagodzenia: OPTIMIZE FOR wskazówka dotycząca optymalizacji pod kątem reprezentatywnej wartości parametru; WITH RECOMPILE na poziomie procedury, aby generować nowy plan przy każdym wywołaniu (kosztowne, ale skuteczne, gdy rozkłady parametrów znacznie się różnią); przypisywanie zmiennych lokalnych na początku procedury w celu zapobiegania podsłuchiwaniu:
sql
CREATE PROCEDURE GetCustomerOrders
@CustomerId INT,
@StartDate DATE,
@EndDate DATE
AS
BEGIN
-- Local variable trick: prevents parameter sniffing
DECLARE @LocalCustomerId INT = @CustomerId;
DECLARE @LocalStart DATE = @StartDate;
DECLARE @LocalEnd DATE = @EndDate;
SELECT o.OrderId, o.OrderDate, o.TotalAmount
FROM Orders o
WHERE o.CustomerId = @LocalCustomerId
AND o.OrderDate BETWEEN @LocalStart AND @LocalEnd;
END;
Najlepsze praktyki: lista kontrolna działania
Zamiast ogólnych zasad poniższe praktyki sprawiają, że procedury składowane można utrzymywać na dużą skalę:
Nazewnictwo i organizacja
- Stosuj spójną konwencję nazewnictwa:
usp_prefiks dla procedur składowanych użytkownika,sp_zarezerwowane dla procedur systemowych - Nazwij procedury używając czasownika i rzeczownika:
GetCustomerOrders,InsertPaymentRecord,UpdateInventoryCount - Grupuj procedury powiązane w schemacie:
Sales.GetCustomerOrders,Inventory.UpdateStock
Struktura kodu
- Rozpocznij każdą procedurę od
SET NOCOUNT ONaby zablokować komunikaty o liczbie wierszy, które klienci mogą błędnie zinterpretować - Zastosowanie
BEGIN TRY / BEGIN CATCHbloki z wyraźnymiBEGIN TRANSACTION / COMMIT / ROLLBACK - Unikaj kursorów w przypadku operacji na zbiorach, w miarę możliwości przepisuj kod SQL oparty na zbiorach
- Nie używaj
SELECT *, nazwij każdą kolumnę, którą zwraca procedura
Bezpieczeństwo
- Przyznaj uprawnienia do wykonywania procedur, odmów bezpośredniego dostępu do tabeli dla ról aplikacji
- Unikaj dynamicznego kodu SQL tworzonego na podstawie danych wprowadzanych przez użytkownika w ramach procedur
- Zastosowanie
sp_executesqlz zapytaniami parametrycznymi, jeśli dynamiczny SQL jest nieunikniony
Wydajność
- Sprawdź plany wykonania skanów tabel w dużych tabelach, w razie potrzeby dodaj indeksy
- Test z reprezentatywnymi wartościami parametrów dla procedur podatnych na podsłuch
- Monitorowanie
sys.dm_exec_procedure_statsdo procedur wymagających dużej liczby operacji lub długiego czasu trwania
Dokumenty
- Dodaj komentarz nagłówkowy do każdej procedury: cel, parametry, wartości zwracane, autor, ostatnia modyfikacja
- Dokumentuj reguły biznesowe zakodowane w logice procedury, nie tylko to, co robi SQL, ale także dlaczego
Zarządzanie zależnościami procedur składowanych
Procedury składowane nie istnieją w izolacji. Procedura, która odczytuje dane z pięciu tabel, wywołuje dwie inne procedury i jest wywoływana przez kilkanaście usług aplikacji, jest komponentem o złożonych zależnościach we wszystkich trzech kierunkach: od czego zależy, co od niej zależy i co dzieli z innymi procedurami.
Gdy kolumna tabeli zmienia typ, każda procedura odwołująca się do tej kolumny musi zostać przetestowana. Gdy zmienia się format wyjściowy procedury, każdy obiekt wywołujący musi zostać zweryfikowany. Gdy rozważa się modyfikację procedury, pełny zestaw obiektów wywołujących określa zakres zmiany i wymagane testy regresyjne.
Typy zależności, które mają znaczenie:
- Zależności obiektów: tabele, widoki, funkcje i inne procedury, do których odwołuje się procedura
- Zależności wywołującego: kod aplikacji, inne procedury składowane i zaplanowane zadania wywołujące tę procedurę
- Zależności schematu: definicje tabel i kolumn, do których muszą pasować typy parametrów procedury i listy SELECT
- Zależności transakcji: procedury, które współdzielą zakres transakcji ze swoimi wywołującymi lub między sobą
W małej bazie danych z dziesięcioma procedurami składowanymi, zależności te można śledzić ręcznie. W przypadku bazy danych z setkami procedur składowanych, powszechnej w środowiskach korporacyjnych, gdzie procedury składowane obejmują lata logiki biznesowej, ręczne śledzenie zależności generuje niekompletne mapy i incydenty związane ze zmianami.
W jaki sposób SMART TS XL Zarządza zależnościami procedur składowanych w skali przedsiębiorstwa
SMART TS XL'S statyczna analiza kodu Analizuje procedury składowane SQL wraz z programami COBOL, usługami Java, potokami Pythona i innymi komponentami, które oddziałują z tą samą bazą danych. Zunifikowana analiza generuje międzyjęzykowy model strukturalny: nie tylko zależności SQL-SQL w bazie danych, ale cały łańcuch od kodu aplikacji, przez procedury składowane, do tabel bazowych i z powrotem.
Funkcja mapowania zależności aplikacji tworzy kompletny graf wywołujących: które programy COBOL używają osadzonego kodu SQL odczytującego tabele należące do procedur składowanych, które usługi Java wywołują procedury składowane za pośrednictwem JDBC, które zadania wsadowe JCL wywołują narzędzia bazy danych uruchamiające procedury składowane. Gdy sygnatura lub zachowanie procedury składowanej ulegają zmianie, mapa zależności pokazuje każdego wywołującego w każdym języku, czyli pełny zakres tego, co należy przetestować przed wdrożeniem zmiany w środowisku produkcyjnym.
analiza wpływu możliwość ta sprawia, że ta mapa zależności jest użyteczna w planowaniu zmian: zaproponuj zmianę CalculateOrderTotal i otrzymuje listę enumerowaną każdego komponentu, który go wywołuje, każdej tabeli, którą odczytuje i zapisuje, oraz każdej procedury podrzędnej, którą wywołuje. To przekształca pytanie „co to zepsuje?” z ćwiczenia z wiedzy plemiennej w ustrukturyzowany, oparty na dowodach raport o zakresie.
wyszukiwanie korporacyjne możliwość ta sprawia, że cały model zależności jest możliwy do zapytania: znajdź każdą procedurę składowaną, która odczytuje z Orders, każdy dzwoniący GetCustomerOrders, każda procedura modyfikująca konkretną kolumnę w ciągu kilku sekund, w całej bazie danych dowolnej wielkości.
Dla zespołów prowadzących modernizacja dziedziczna programy, w których procedury składowane kodują dziesiątki lat logiki biznesowej, która musi zostać zachowana podczas migracji, SMART TS XLAnaliza dostarcza dokumentację strukturalną umożliwiającą wyodrębnienie logiki i zaplanowanie sekwencji migracji.
Warstwa bazy danych, która zasługuje na swoje utrzymanie
Procedury składowane nie są reliktem wcześniejszej ery baz danych. Stanowią one właściwe miejsce do umieszczania logiki właściwej dla bazy danych: egzekwowania zabezpieczeń, które muszą być spójne niezależnie od tego, która aplikacja uzyskuje dostęp do danych, zapytań wrażliwych na wydajność, które korzystają z buforowanych planów wykonania, oraz reguł biznesowych, które powinny zostać zaktualizowane raz i rozprzestrzenione wszędzie.
Pułapką jest brak użycia procedur składowanych, a raczej ich rozrost w nieudokumentowaną, niezmapowaną sieć zależności, której nikt w pełni nie rozumie. Procedura składowana, która wykonuje krytyczne obliczenie biznesowe, ale nie ma udokumentowanych wywołań, komentarza w nagłówku wyjaśniającego jej cel i analizy wpływu przed modyfikacją, jest obciążeniem, niezależnie od tego, jak dobrze została napisana. Zarządzanie grafem zależności jest równie ważne, jak zarządzanie samym SQL. Oba wymagają systematycznej analizy, a nie wiedzy plemiennej.