💡 はじめに
データベースのパフォーマンスは、アプリケーションのユーザー体験に直結します。特に大規模なデータセットを扱う場合、冗長で非効率なSQLクエリは、システムのボトルネックとなり、開発者の時間を奪います。
本記事では、意図せず「実行時間の遅いクエリ」を書いてしまった場合を想定し、近年進化が著しいAI(特に大規模言語モデル, LLM)を活用して、クエリを 「スマートで高速なクエリ」 へと劇的に改善する具体的な手法を、サンプルコード付きで解説します。
😱 改善前の「遅いクエリ」とその問題点
今回は、商品の注文履歴から、過去90日間に注文が全くない顧客(アクティブではない顧客)のリストを取得するケースを考えます。
非効率な書き方として、サブクエリ内で大量のデータを繰り返しスキャンしてしまうようなクエリを見てみましょう。
📄 サンプルクエリ(遅い例)
-- 顧客テーブル
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name VARCHAR(100),
created_at DATETIME
);
-- 注文テーブル
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATETIME,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
-- 90日間注文がない顧客リストを取得するクエリ
SELECT
c.customer_id,
c.name
FROM
customers c
WHERE
c.customer_id NOT IN (
SELECT
o.customer_id
FROM
orders o
WHERE
o.order_date >= DATEADD(day, -90, GETDATE()) -- SQL Serverの日付関数
);
💣 このクエリのパフォーマンス上の問題点
-
NOT INの使用:-
NOT INは、内側のサブクエリが返す全データに対して外部クエリのレコードを一つずつ比較するため、処理が非常に重くなります。特に、SQL Serverでは、サブクエリがNULLを含む場合、期待しない結果(全てのレコードが除外される)を引き起こす可能性があり、非常に危険です。
-
-
インデックスの非活用:
- この形式のサブクエリでは、オプティマイザが効率的な実行計画を立てにくく、
ordersテーブルのorder_dateやcustomer_idにインデックスがあっても、その恩恵を最大限に受けられないことがあります。
- この形式のサブクエリでは、オプティマイザが効率的な実行計画を立てにくく、
-
データ量の増加に弱い:
-
customersテーブルとordersテーブルのデータ量が増えるにつれて、実行時間が二次関数的に増加する傾向があります。
-
🤖 AIによる改善提案と高速化
この遅いクエリを、開発者向けのAIツールに 「このSQL Serverのクエリの実行速度を改善したい。より効率的な書き方を提案してください。」 と入力してみましょう。
AIは、上記のパフォーマンス上の問題点を認識し、一般的にSQL Serverで推奨される高速化手法を用いたクエリを提案してくれます。
📄 AIが提案する改善クエリ(速い例)
AIは、NOT IN の代わりに LEFT JOIN と WHERE IS NULL の組み合わせ、または NOT EXISTS の利用を提案する可能性が高いです。これらはSQL Serverにおいても最も推奨されるパフォーマンス改善手法です。
1. LEFT JOIN + WHERE IS NULL による改善
-- LEFT JOINとWHERE IS NULLを使用して、注文がない顧客を見つける
SELECT
c.customer_id,
c.name
FROM
customers c
LEFT JOIN
orders o ON c.customer_id = o.customer_id
AND o.order_date >= DATEADD(day, -90, GETDATE()) -- JOIN条件でフィルタリング
WHERE
o.order_id IS NULL; -- 注文レコードが見つからなかった(=注文がない)顧客のみを選択
2. NOT EXISTSによる改善
-- NOT EXISTSを使用して、関連する注文が存在しない顧客を見つける
SELECT
c.customer_id,
c.name
FROM
customers c
WHERE
NOT EXISTS (
SELECT
1 -- 存在チェックなので列は何でも良い
FROM
orders o
WHERE
o.customer_id = c.customer_id -- 外部クエリのcustomer_idに紐づく
AND o.order_date >= DATEADD(day, -90, GETDATE())
);
✨ 改善クエリの優位性
| 改善手法 | 優位性(なぜ速いか) |
|---|---|
| LEFT JOIN + WHERE IS NULL | 結合処理はオプティマイザが最適化しやすく、インデックスも活用しやすい。データスキャンが一度で済むため、非常に高速。 |
| NOT EXISTS | 内部クエリは一致するレコードが見つかった時点でスキャンを停止する(ショートサーキット評価)。NOT INのように全件スキャンやNULL値の評価で苦しむことがない。 |
実際にSQL Server環境で、これらの改善クエリは元の NOT IN クエリと比較して 数倍から数十倍の速度向上 が見込めます。特に大規模なテーブルでは、実行計画 の違いが明確に現れます。
🛠️ AIをパフォーマンス改善に活用するステップ
AIを単なるコードジェネレータとしてではなく、優秀なデータベースエンジニアとして活用するためのステップです。
-
遅いクエリを特定する:
- まず、SQL Server Management Studio (SSMS) で実行計画や拡張イベントを確認し、実行時間がかかっているクエリを特定します。
-
AIに相談する:
- 特定したクエリと、対象テーブルのスキーマ情報(
CREATE TABLE文など)をAIに渡し、「SQL Server環境で、このクエリを高速化する、より効率的な書き方を提案してください」と依頼します。
- 特定したクエリと、対象テーブルのスキーマ情報(
-
提案されたクエリを検証する:
- AIの提案をそのまま本番環境に適用せず、必ずテスト環境で実行し、期待通りの結果を返すか、そして本当に速くなっているかを実際の実行計画(
Actual Execution Plan)で確認します。
- AIの提案をそのまま本番環境に適用せず、必ずテスト環境で実行し、期待通りの結果を返すか、そして本当に速くなっているかを実際の実行計画(
-
インデックスの提案も求める:
- AIはクエリの書き方だけでなく、「このクエリが遅い原因は、
ordersテーブルの(customer_id, order_date)に対する非クラスター化インデックスがないことかもしれません」といった、インデックス戦略の提案も行ってくれます。
- AIはクエリの書き方だけでなく、「このクエリが遅い原因は、
🎯 まとめ
AIは、私たちが気づかないSQLのアンチパターンや、特定のDBMS(SQL Serverなど)で最適な書き方といった知識を一瞬で提供してくれます。
-
SQL Serverにおいて
NOT INは 非効率であり、特にNULL値のリスクを伴います。 -
AIは、これらを
LEFT JOIN+IS NULLやNOT EXISTSといった高速かつ安全な手法に変換するのに役立ちます。 -
最も重要なのは、AIの提案を鵜呑みにせず、 SSMSで実行計画を確認し、論理的に最も速いクエリを選択する というエンジニアの姿勢です。
AIを良き相棒として、日々のクエリ改善に取り組み、快適なアプリケーション開発を目指しましょう!