2025年10月28日火曜日

SQL Server ストアドプロシージャの応用と最適化|トランザクション・動的SQL・パフォーマンスチューニング

応用的なプロシージャ活用で実務の生産性を高めよう

SQL Serverのストアドプロシージャ(Stored Procedure)は、単なるSQLの集合ではなく、トランザクション管理やエラーハンドリング、動的クエリ生成、パフォーマンスチューニングなど多くの応用機能を備えています。
本記事では、トランザクション制御・動的SQL・実行計画キャッシュ最適化・EXECUTE AS権限制御を中心に、実務で役立つ応用技術を紹介します。

目次

トランザクション制御とエラーハンドリング

複数のテーブルを同時に更新する場合、途中でエラーが発生してもデータを整合的に保つ必要があります。
SQL Serverでは、BEGIN TRAN/COMMIT/ROLLBACKでトランザクションを制御します。

CREATE PROCEDURE dbo.UpdateOrderAndStock
    @OrderID INT,
    @ProductID INT,
    @Quantity INT
AS
BEGIN
    BEGIN TRY
        BEGIN TRAN;
            UPDATE dbo.Orders
            SET Status = 'Completed'
            WHERE OrderID = @OrderID;

            UPDATE dbo.Products
            SET Stock = Stock - @Quantity
            WHERE ProductID = @ProductID;

        COMMIT TRAN;
    END TRY
    BEGIN CATCH
        ROLLBACK TRAN;
        PRINT 'エラーが発生したため処理をロールバックしました。';
        PRINT ERROR_MESSAGE();
    END CATCH
END;
GO

この構文により、途中で失敗してもトランザクション全体が取り消されます。
エラーハンドリングを組み合わせることで、業務システムでも安全な更新処理が実現できます。

動的SQLとsp_executesqlの活用

実務では「検索条件が可変」「カラムを選択的に指定」といった柔軟性が求められます。
このような場合に使うのが動的SQLです。

単純な方法としてEXEC()で文字列を実行できますが、パラメータを安全に扱うならsp_executesqlを使うのが推奨です。

CREATE PROCEDURE dbo.SearchOrders
    @CustomerName NVARCHAR(50) = NULL,
    @MinAmount DECIMAL(10,2) = NULL
AS
BEGIN
    DECLARE @sql NVARCHAR(MAX);
    SET @sql = N'SELECT OrderID, CustomerName, Amount FROM dbo.Orders WHERE 1=1';

    IF @CustomerName IS NOT NULL
        SET @sql += N' AND CustomerName = @CustName';

    IF @MinAmount IS NOT NULL
        SET @sql += N' AND Amount >= @MinAmt';

    EXEC sp_executesql @sql,
        N'@CustName NVARCHAR(50), @MinAmt DECIMAL(10,2)',
        @CustName = @CustomerName, @MinAmt = @MinAmount;
END;
GO

sp_executesqlを使うことで、SQLインジェクションを防ぎつつ実行計画キャッシュも活用できます。
動的SQLは、検索画面や帳票などの条件可変クエリで特に有効です。

パラメータスニッフィングと実行計画キャッシュ

SQL Serverは、初回実行時のパラメータ値を基に実行計画をキャッシュします。
これが特定条件に最適化されすぎて他の条件で性能が低下する現象を、パラメータスニッフィング(Parameter Sniffing)と呼びます。

以下は対策の一例です。

CREATE PROCEDURE dbo.GetSalesByRegion
    @Region NVARCHAR(50)
AS
BEGIN
    DECLARE @tmp NVARCHAR(50) = @Region;  -- ローカル変数に再代入
    SELECT * FROM dbo.Sales WHERE Region = @tmp;
END;
GO

ローカル変数に代入することで、SQL Serverが毎回最適な実行計画を生成します。
また、OPTION(RECOMPILE)やWITH RECOMPILEを使う方法もあります。

WITH RECOMPILEとパフォーマンス調整

プロシージャにWITH RECOMPILEを付けると、毎回実行計画を再生成します。

CREATE PROCEDURE dbo.GetTopOrders
    @Year INT
WITH RECOMPILE
AS
BEGIN
    SELECT TOP 10 * FROM dbo.Orders
    WHERE YEAR(OrderDate) = @Year
    ORDER BY Amount DESC;
END;
GO

これにより、異なる条件でも安定した性能を維持できますが、コンパイルコストが増加する点には注意が必要です。
一時的な調整には「EXEC dbo.GetTopOrders @Year = 2024 WITH RECOMPILE;」のように実行時指定も可能です。

セキュリティと権限実行(EXECUTE AS)

プロシージャは特定の権限で実行されるため、セキュリティ設計の一部として活用できます。
EXECUTE AS句を使うと、他のユーザー権限で一時的に実行できます。

CREATE PROCEDURE dbo.ViewSensitiveData
WITH EXECUTE AS 'Auditor'
AS
BEGIN
    SELECT * FROM dbo.ConfidentialLogs;
END;
GO

これにより、呼び出し元が直接テーブルにアクセスできなくても、監査専用ユーザー権限で安全に閲覧が可能です。
さらに厳密なセキュリティが必要な場合は「署名付きプロシージャ(SIGNED PROCEDURE)」を検討します。

管理・チューニングのベストプラクティス

ストアドプロシージャを長期的に運用するには、定期的な統計更新・再コンパイル・依存関係確認が欠かせません。

  • 統計情報の更新:UPDATE STATISTICS dbo.Sales;
  • 断片化対策:ALTER INDEX ALL ON dbo.Sales REBUILD;
  • 実行統計確認:sys.dm_exec_procedure_statsを使用
  • 依存関係追跡:sys.sql_expression_dependenciesで管理
  • ソース管理:Git等で定義SQLをバージョン管理する

プロシージャのパフォーマンスを定期的にモニタリングすることで、運用中のボトルネックを早期に検出できます。

まとめ:応用テクニックで安定したSQL運用を実現

本記事では、ストアドプロシージャの応用機能を実務目線で整理しました。
トランザクション制御によるデータ整合性、動的SQLの柔軟性、EXECUTE ASによる安全性、パラメータスニッフィング対策による安定性能。
これらを理解し組み合わせることで、SQL Serverの運用はより効率的かつ堅牢になります。
プロシージャは「書いて終わり」ではなく、「最適化・監視・改善」を通じて真価を発揮します。

参考リンク(公式ドキュメント)

SQL Server 解説用イメージ

0 件のコメント:

コメントを投稿