「SELECT文は実行できたが、取得結果が本当に正しいか自信がない」
「UPDATE文を本番で実行する前に、何を確認すればよいのだろう」
SQLは、開発・保守の現場で日常的に使う技術です。データ調査、障害対応、テストデータの作成、プログラム修正など、さまざまな場面で必要になります。
一方で、SQLは実行できれば十分というものではありません。検索条件が足りなければ誤った結論につながり、更新条件を間違えれば大量のデータを変更してしまいます。処理結果が正しくても、実行計画によってはシステム全体の性能へ影響する可能性もあります。
私も銀行システムの開発・保守に25年以上関わるなかで、SQLを慎重に扱うことの大切さを何度も感じてきました。特に本番環境では、「実行できるか」ではなく、「対象を説明でき、結果を検証でき、問題時に戻せるか」まで考える必要があります。
この記事では、現場で使うSQLの基本を次の3つに分けて解説します。
- SELECTで必要なデータを正確に確認する
- UPDATEを安全な手順で実行する
- 実行計画でSQLの処理方法を確認する
SQLで大切なのは「対象・件数・結果」を説明できること
SQLを実行するときは、構文が正しいだけでなく、どのデータを対象にし、何件に影響し、実行後にどうなるかを説明できる状態にします。
| 確認項目 | 確認内容 | 例 |
|---|---|---|
| 対象 | どの条件のデータを扱うか | 処理日と取引番号で特定 |
| 件数 | 何件取得・更新されるか | 想定1件、事前SELECTも1件 |
| 内容 | 現在値と変更後の値 | ステータス01を02へ変更 |
| 影響 | 後続処理や関連テーブルへの影響 | 夜間バッチの抽出対象になる |
| 復旧 | 誤りがあった場合に戻せるか | 更新前データと戻しSQLを用意 |
この確認は、SQLレビューや作業承認を受けるときにも役立ちます。「このSQLで大丈夫です」ではなく、対象条件と想定件数、検証方法を示せると、確認する側も判断しやすくなります。
1.SELECTで必要なデータを正確に確認する
SELECTはデータを変更しないため安全に見えますが、結果の読み違いや高負荷な検索には注意が必要です。まず、取得したいデータの定義を日本語で整理してからSQLへ落とし込みます。
主キーや業務キーで対象を絞る
調査対象を特定するときは、主キー、取引番号、処理日、利用者IDなどを組み合わせます。名称やステータスだけでは複数件に一致しやすく、別のデータを見てしまうことがあります。
SELECT
transaction_id,
process_date,
status,
update_timestamp
FROM
transaction_table
WHERE
transaction_id = :transaction_id
AND process_date = :process_date;
SELECT *は手軽ですが、必要な列が明確な場合は列名を指定します。取得項目の意味が分かりやすくなり、不要なデータや機密情報を表示するリスクも抑えられます。
NULL、日付、文字列の条件に注意する
- NULLの判定には
IS NULLまたはIS NOT NULLを使う - 日時は時分秒を含むか確認し、日付だけのつもりで等価条件を使わない
- 文字列の前後空白、全角・半角、大文字・小文字を確認する
- 暗黙の型変換に頼らず、列のデータ型に合わせる
検索結果が0件だった場合も、「データが存在しない」とすぐ判断せず、条件の誤り、参照スキーマ、接続環境、時刻範囲などを確認します。
集計結果は明細でも裏付ける
COUNTやSUMで件数・金額を確認した場合は、必要に応じて明細も抽出します。集計値だけでは、重複結合や条件漏れに気付きにくいためです。結合前後の件数を比較すると、意図しない件数増加を検出しやすくなります。
2.UPDATEを安全な手順で実行する
UPDATEは、WHERE句を誤ると広い範囲を変更します。本番作業では、SQL本文だけでなく、事前確認、実行、事後確認、復旧までを一つの手順として準備します。
同じWHERE句で事前SELECTを実行する
更新前に、UPDATEと同じWHERE句を使ったSELECTで対象件数と現在値を確認します。
-- 事前確認
SELECT
transaction_id,
status,
update_timestamp
FROM
transaction_table
WHERE
transaction_id = :transaction_id
AND status = '01';
-- 更新
UPDATE transaction_table
SET
status = '02',
update_timestamp = CURRENT_TIMESTAMP
WHERE
transaction_id = :transaction_id
AND status = '01';
更新前の状態もWHERE句に含めると、想定外の状態にあるデータを誤って更新するリスクを下げられます。事前SELECTの件数が想定と違う場合は、UPDATEを実行せずに中断します。
COMMIT前に更新件数と内容を確認する
- 接続先の環境、データベース、スキーマを確認する
- 事前SELECTで対象件数と更新前データを保存する
- UPDATEを実行し、更新件数を確認する
- 同一セッションで事後SELECTを実行する
- 問題がなければCOMMITし、問題があればROLLBACKする
- 別セッションや業務画面から反映結果を確認する
実際の手順は、利用するツールや組織の運用ルールに従います。自動コミットが有効なツールでは、実行直後に確定する場合があるため、事前に設定を確認してください。
戻しSQLと関連影響を準備する
更新値を元へ戻すSQLだけでなく、更新によって後続バッチや外部連携が動くかも確認します。すでに後続処理が実行された場合、対象テーブルを戻すだけでは整合性が回復しないことがあります。
3.実行計画でSQLの処理方法を確認する
実行計画は、データベースがSQLをどの順番・方法で処理するかを示します。SQLの結果が正しくても、全表走査や大量の結合が発生すると、応答時間や他処理へ影響する可能性があります。
まずアクセス方法と件数見積もりを見る
| 確認項目 | 見るポイント |
|---|---|
| TABLE ACCESS FULL | 大規模テーブルを全件走査していないか |
| INDEX SCAN | 適切な索引が利用されているか |
| 結合方法 | NESTED LOOPS、HASH JOINなどが件数に合っているか |
| Rows | 見積件数と実際の件数が大きくずれていないか |
| Cost | 変更前後で大幅に増えていないか |
全表走査が常に悪いわけではありません。小さなテーブルや多数の行を取得するSQLでは、索引より効率的な場合もあります。表示された単語だけで良し悪しを決めず、テーブル規模、取得件数、実行頻度と合わせて判断します。
テストデータ量だけで判断しない
開発環境ではデータが少なく、どのSQLも速く見えることがあります。本番相当のデータ量、データの偏り、同時実行数を考慮し、必要に応じて実測値も確認します。
実行計画が想定と違う場合、すぐにヒント句や索引追加へ進むのではなく、統計情報、検索条件、型変換、結合条件、データ分布を確認します。変更はDBAや性能担当者と相談し、他SQLへの影響も評価します。
SQLで避けたい3つの失敗
1.本番環境でSQLを直接書きながら試す
入力途中のSQLや条件漏れを実行するリスクがあります。検証環境で確認し、レビュー済みのSQLを作業手順へ固定します。
2.更新件数だけを見て内容を確認しない
想定どおり1件でも、別の1件を更新している可能性があります。主キーと更新前後の値を確認します。
3.速い・遅いを一度の実行だけで判断する
キャッシュ、同時処理、データ量によって実行時間は変わります。実行計画と複数回の計測、実行条件を合わせて評価します。
SQL作業メモのテンプレート
【目的】 確認・更新する理由: 【接続先】 環境: データベース・スキーマ: 【対象】 検索条件: 想定件数: 関連する後続処理: 【実行前】 事前SELECT結果: 更新前データの保存先: レビュー・承認: 【実行後】 実行時刻: 更新件数: 事後SELECT結果: COMMIT/ROLLBACK: 【復旧】 戻しSQL: 復旧確認方法:
若手SE向けSQLチェックリスト
- 対象データを日本語で説明できる
- 主キーや業務キーで条件を絞った
- 事前SELECTで件数と現在値を確認した
- 接続先の環境とスキーマを確認した
- COMMIT前に更新件数と更新後データを確認した
- 戻しSQLと後続処理への影響を確認した
- 実行計画をデータ量や実行頻度と合わせて確認した
まとめ:SQLは実行前後の確認までが一つの作業
現場でSQLを扱うときは、構文だけでなく、対象、件数、結果、影響を確認することが大切です。
- SELECTは条件とデータ型を確認し、集計結果を明細で裏付ける
- UPDATEは事前SELECT、更新、事後確認、COMMIT、復旧を一つの手順にする
- 実行計画はアクセス方法、件数、データ量を合わせて読む
特に本番データを変更する作業では、少し慎重すぎるくらいがちょうどよいものです。分からない点があれば、実行前に先輩、責任者、DBAへ確認しましょう。



コメント