۱۴۰۴/۰۷/۰۱ Nebular

Stored Procedure چیه؟

Stored Procedure چیست و چرا از آن استفاده می‌کنیم؟

Stored Procedure (یا به‌اختصار SP) مجموعه‌ای از دستورات SQL است که با یه نام مشخص روی سرور ذخیره می‌شه و می‌تونیم هر وقت لازم بود اجراش کنیم. مثل یه تابع تو برنامه‌نویسی: پارامتر می‌گیره، منطقی اجرا می‌کنه، و ممکنه خروجی بده یا تغییراتی تو دیتابیس ایجاد کنه.

چرا Stored Procedure؟

  • قابلیت استفاده مجدد: یه بار می‌نویسی، هر جا لازم بود صدا می‌زنی.
  • امنیت بالا: کاربر فقط می‌تونه SP رو اجرا کنه، بدون دسترسی مستقیم به جداول.
  • کارایی بهتر: پلن اجرا (Execution Plan) کش می‌شه و سرعت اجرا رو بالا می‌بره.
  • نگهداری ساده: منطق پیچیده رو تو یه جا متمرکز می‌کنه.
  • کاهش ترافیک شبکه: چند دستور SQL رو یه‌جا روی سرور اجرا می‌کنه.
  • لایه منطق تجاری: SP می‌تونه مثل یه لایه بین اپلیکیشن و دیتابیس عمل کنه و منطق تجاری (مثل محاسبه حقوق یا اعتبارسنجی) رو مدیریت کنه.

معایب

  • Parameter Sniffing: گاهی پلن اجرا برای داده‌های مختلف بهینه نیست.
  • نگهداری: تو پروژه‌های بزرگ نیاز به نسخه‌بندی داره.
  • محدودیت‌ها: برای عملیات پیچیده مثل ETL، ابزارهای دیگه (مثل SSIS) ممکنه بهتر باشن.

تفاوت با Function

  • Stored Procedure: می‌تونه داده‌ها رو تغییر بده (INSERT/UPDATE/DELETE) و چند Result Set برگردونه. نمی‌تونی مستقیم تو SELECT ازش استفاده کنی.
  • Function: معمولاً یه خروجی مشخص داره و می‌تونی تو SELECT ازش استفاده کنی.

سینتکس پایه

CREATE PROCEDURE [dbo].[ProcedureName]
    @Param1 INT,
    @Param2 VARCHAR(50) = 'default', -- مقدار پیش‌فرض
    @OutParam INT OUTPUT              -- پارامتر خروجی
AS
BEGIN
    SET NOCOUNT ON; -- حذف پیام‌های اضافی
    -- کد SQL
END;

مثال‌های کاربردی

۱. دریافت اطلاعات کارمند با ID

CREATE PROCEDURE dbo.GetEmployeeById
    @EmployeeID INT
AS
BEGIN
    SET NOCOUNT ON;
    SELECT EmployeeID, FirstName, LastName, Salary
    FROM dbo.Employees
    WHERE EmployeeID = @EmployeeID;
END;

اجرا:

EXEC dbo.GetEmployeeById 42;

۲. افزودن کارمند جدید با خروجی ID

CREATE PROCEDURE dbo.AddEmployee
    @FirstName NVARCHAR(100),
    @LastName NVARCHAR(100),
    @Salary MONEY,
    @NewEmployeeID INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    INSERT INTO dbo.Employees (FirstName, LastName, Salary)
    VALUES (@FirstName, @LastName, @Salary);
    SET @NewEmployeeID = SCOPE_IDENTITY();
END;

اجرا:

DECLARE @id INT;
EXEC dbo.AddEmployee 'Ali', 'Rezaei', 2000, @id OUTPUT;
SELECT @id AS CreatedId;

۳. تراکنش امن با TRY/CATCH

CREATE PROCEDURE dbo.TransferSalary
    @FromEmpID INT,
    @ToEmpID INT,
    @Amount MONEY
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRAN;
    BEGIN TRY
        UPDATE dbo.Employees
        SET Salary = Salary - @Amount
        WHERE EmployeeID = @FromEmpID;
        IF @@ROWCOUNT = 0
            THROW 50001, 'From employee not found', 1;

        UPDATE dbo.Employees
        SET Salary = Salary + @Amount
        WHERE EmployeeID = @ToEmpID;
        IF @@ROWCOUNT = 0
            THROW 50002, 'To employee not found', 1;

        COMMIT TRAN;
    END TRY
    BEGIN CATCH
        IF XACT_STATE() <> 0
            ROLLBACK TRAN;
        THROW;
    END CATCH;
END;

۴. Dynamic SQL امن

CREATE PROCEDURE dbo.SearchEmployees
    @ColumnName SYSNAME,
    @SearchText NVARCHAR(100)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @sql NVARCHAR(MAX);
    SET @sql = N'SELECT EmployeeID, FirstName, LastName
                 FROM dbo.Employees
                 WHERE ' + QUOTENAME(@ColumnName) + N' LIKE @p';
    EXEC sp_executesql @sql, N'@p NVARCHAR(100)', @p = N'%' + @SearchText + '%';
END;

۵. استفاده از Table-Valued Parameter

CREATE TYPE dbo.IdList AS TABLE (Id INT PRIMARY KEY);

CREATE PROCEDURE dbo.GetEmployeesByIds
    @Ids dbo.IdList READONLY
AS
BEGIN
    SET NOCOUNT ON;
    SELECT e.EmployeeID, e.FirstName, e.LastName
    FROM dbo.Employees e
    JOIN @Ids i ON e.EmployeeID = i.Id;
END;

اجرا:

DECLARE @t dbo.IdList;
INSERT INTO @t (Id) VALUES (1), (5), (7);
EXEC dbo.GetEmployeesByIds @t;

مقایسه با SELECT مستقیم

ویژگیStored ProcedureSELECT مستقیم
کاراییپلن اجرا کش می‌شه، سرعت بیشترهر بار ممکنه پلن جدید ساخته بشه
امنیتدسترسی فقط به SP با GRANT EXECUTE، کاهش ریسک SQL Injectionنیاز به دسترسی مستقیم به جدول، ریسک امنیتی بیشتر
نگهداریتغییر تو یه جا، مدیریت سادهتغییر تو همه کدها، پیچیده‌تر
استفاده مجددیه‌بار تعریف، بارها استفادهتکرار کدها تو جاهای مختلف
لایه منطق تجاریمنطق (مثل محاسبه یا اعتبارسنجی) تو SP متمرکزهمنطق پخش تو اپلیکیشن

امنیت

  • SELECT مستقیم: کاربر باید دسترسی مستقیم به جدول داشته باشه (مثل SELECT روی Employees). این باعث افزایش سطح دسترسی و ریسک SQL Injection می‌شه.
  • Stored Procedure: می‌تونی فقط اجازه اجرای SP رو بدی (مثل GRANT EXECUTE ON dbo.GetEmployeeById TO SomeUser;). اینطوری کاربر بدون دسترسی به جدول‌ها، فقط SP رو اجرا می‌کنه و امنیت خیلی بالاتر می‌ره.

نگهداری و توسعه

  • SELECT مستقیم: اگه کوئری‌ها تو اپلیکیشن پخش باشن، برای هر تغییر باید همه‌جا رو اصلاح کنی.
  • Stored Procedure: منطق تو یه SP متمرکزه. تغییر فقط تو SP اعمال می‌شه و همه‌جا به‌روز می‌شه.

قابلیت استفاده مجدد

  • SELECT مستقیم: باید همون کوئری رو بارها تو جاهای مختلف بنویسی.
  • Stored Procedure: یه‌بار تعریف می‌شه و هر جا لازم باشه صدا زده می‌شه.

لایه منطق تجاری (Business Logic Layer)

SPها می‌تونن به‌عنوان یه لایه بین دیتابیس و اپلیکیشن عمل کنن:

  • فقط SPها به داده‌ها دسترسی دارن.
  • منطق تجاری (مثل محاسبه حقوق، گزارش‌گیری، یا اعتبارسنجی) تو SP نوشته می‌شه.
  • اپلیکیشن فقط از طریق SP با دیتابیس ارتباط برقراره، که کنترل و مدیریت رو ساده‌تر می‌کنه.

نکات حرفه‌ای

  • همیشه SET NOCOUNT ON رو بذار تا پیام‌های اضافی حذف بشن.
  • برای مدیریت خطاها از TRY/CATCH و THROW استفاده کن.
  • تو Dynamic SQL از sp_executesql و QUOTENAME استفاده کن تا از SQL Injection جلوگیری بشه.
  • دسترسی‌ها رو محدود کن: فقط GRANT EXECUTE به کاربر بده.
  • مراقب Parameter Sniffing باش و در صورت نیاز از OPTION (RECOMPILE) استفاده کن.
  • SPها رو تو پروژه‌های بزرگ نسخه‌بندی و تست کن.
Accept Cookies
Accept Cookies
[your-shortcode]