カーソルは、SQLにおいてデータセットを行単位で反復処理し、各レコードに対して特定のアクションを実行することができるため、プログラミングにおける反復処理に類似しています。これにより、SQLの1つのクエリでは不可能な複雑なステップロジックを扱うことができます(例えば、外部状態の変化を伴う段階的な計算など)。
カーソルの例:
DECLARE my_cursor CURSOR FOR SELECT id, balance FROM Accounts WHERE isActive = 1; OPEN my_cursor; DECLARE @id INT, @bal DECIMAL(10,2); FETCH NEXT FROM my_cursor INTO @id, @bal; WHILE @@FETCH_STATUS = 0 BEGIN UPDATE Accounts SET balance = @bal * 1.05 WHERE id = @id; FETCH NEXT FROM my_cursor INTO @id, @bal; END CLOSE my_cursor; DEALLOCATE my_cursor;
利点:
欠点と落とし穴:
トリガー内でカーソルを使用できますか?それはデータベースのパフォーマンスにどのような影響を与える可能性がありますか?
回答と例: トリガー内でカーソルを使用することは可能ですが、非常に推奨されません。各DML操作は影響を受けた各行についてカーソルを起動する可能性があり、これによりクエリとロックの急増が発生します。
CREATE TRIGGER UpdateBalance ON Accounts AFTER INSERT AS DECLARE c CURSOR FOR SELECT id FROM inserted; -- 悪い! OPEN c; -- ...
歴史
プロジェクト:小売業の注文集計。 不良品が見つかった場合に在庫をカウントする必要があり、次のロットは割引の更新を通じて手動で再計算する必要がありました。ロットを走査するためにカーソルを使用しました。後に、何度も実行するとスレッドが数時間ロックされ、サーバーへの負荷が指数的に増加し、ロック競合によって障害が発生することが判明しました。
歴史
プロジェクト:ERP、データ移行。 インポート処理の手続きにカーソルを使用してエラーハンドリングを追加しました。500万行では、カーソルがset-based UPDATE + CASEを使用した類似のバッチ処理よりも40倍遅くなることを考慮していませんでした。遅い移行のために締切がずれました。
歴史
プロジェクト:金融会社の請求。 資金移動テーブルの更新トリガーにカーソルを追加し、新しい集約残高を計算しました。本番環境では「STOP THE WORLD」に至り、一行の挿入すらサービスの動作を遅らせました。その理由は、多くの行に対してネストされたカーソルが起動されたためです。