Procedury składowane w zarządzaniu bazami danych

Procedury składowane: jak działają i jak z nich dobrze korzystać

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 informacji

Czym 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:

przedmiotZwrotyAkceptuje parametryMożliwość modyfikacji danychPlan wykonania zapisany w pamięci podręcznejNajlepsze dla:
Procedura składowanaZestawy wyników, parametry wyjściowe, kody powrotuTakTakTakZłożona logika, operacje DML, egzekwowanie zabezpieczeń
ZobaczPojedynczy zestaw wyników (jak tabela)NieNie (normalnie)CzęściowaUproszczenie zapytań SELECT, zabezpieczenia na poziomie kolumn
Funkcja skalarnaPojedyncza wartośćTakNieNieObliczenia ponownie wykorzystane na listach SELECT
Funkcja o wartościach tabelarycznychZestaw wynikówTakNieCzęściowaWidoki 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() or sp_executesql Konkatenacja 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 ON aby zablokować komunikaty o liczbie wierszy, które klienci mogą błędnie zinterpretować
  • Zastosowanie BEGIN TRY / BEGIN CATCH bloki z wyraźnymi BEGIN 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_executesql z 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_stats do 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.