同じ職場の人から、こんな話を聞きました。AI agent (Claude Code) に本番データベースの調査をさせたら、投げたクエリが30分ほど止まらなかったそうです。それ以来、その人は AI にデータベースを引かせるのをやめた、ということでした。
調査なので読み取りの query だったこと、重めの table を引いたということ以外、どんな SQL だったかは私も知りません。ただ、結果として取ることになった行動の形が気になりました。今日はその話です。
羹に懲りて膾を吹く
熱い汁物で口を焼いた人が、冷たい酢の物まで吹いて冷ます、という喩えです。一度の失敗に懲りて、害の無いものまで警戒することを言います。
口を焼いたのは重いクエリです。封じたのは、軽いクエリも含めた、AI による調査の全部です。焼いたものと封じたものが一致していないので、この形に見えました。同じ事故は AI からは起きなくなりますが、同じ query を人が書けば同じだけ止まります。そして調査はまた人が手で書くことになります。安全になったのではなく、AI に調査を任せるという手段を放棄しただけです。
ただ、これは人の話です。自分ならどう書くかと思って、うちの AI に「他山の石として、本番で重い query を投げないための規則を書いて」と頼みました。
最初の版も、同じ形をしていた
AIが出してきた最初の版は、こういうものでした。
- 数十万行を超える table には query を投げない
- 実行時間の上限は30秒
- 本番に投げる前に、開発環境で先に試す
読んでいて、これもいかがなものか、と思いました。
数十万行程度の SELECT なら、DB には大した負荷はないでしょう。複雑な JOIN とかあれば別でしょうけれど。そういう行数を基準にするのは筋が悪い、とまず思いました。
また、30秒の上限は、短すぎると思いました。それでは恐らく、本当に知りたいことを知れないでしょうし、ともすると引っかかってしまう、閾値が低すぎる、と。
開発環境で先に試すのも、入っている data の量が本番環境とではそもそも違うので、これも基準にはなり得ません。
直した版
そう反論したら、AI は直した版を返してきました。index の効く条件なら数十万行は数秒で終わる、30分級になるのは index の無い結合で、70万行と7千行なら比較は50億回になる、あとは絞り込む前の大きな集合への GROUP BY や ORDER BY で、一時 table と並べ替えが走る場合、だから判断は行数ではなく実行計画の形で、と。
規則はこうなりました。
- 本番に投げる前に
EXPLAIN を見る。実行計画を出すだけで table は走査しないので、本番で打っても重くなりません (実際に実行する EXPLAIN ANALYZE は別です)。table の規模は information_schema の概算行数で先に見れます。
- 投げてよいかは計画の形で決める。単一 table で index が効いていれば、行数の多寡にかかわらず投げてよい。結合の内側が全走査で、Extra列に hash 結合も出ておらず、両 table の行数の積が大きいなら投げない。
Using temporary や Using filesort の対象が rows の推定で数十万行を超えるなら投げない。
- 実行時間の上限を query 自体に埋める。
SELECT /*+ MAX_EXECUTION_TIME(300000) */ ... で、単位はミリ秒なので5分です。client 側の timeout では、server の中で走っている query は止まりません。この hint は SELECT にしか効きませんが、調査で投げるのは SELECT だけです。
- 調査の query には
LIMIT を付ける。並べ替えは軽くなりませんが、返す行数と転送量に天井ができます。
- 月初や定時 batch の時間帯は重めの調査を避ける。これは機序ではなく、共用の database で他の処理を巻き込まないための話です。
上限時間は残っていますが、判断の代わりではなく、判断が外れた時の天井です。5分は、事故の30分より十分に短く、調査の query なら普通に収まる長さです。
この規則を守るのは AI です。計画の形の判断は EXPLAIN の表示で決まり、時間の上限は hint を埋めれば server が守ります。埋め忘れを機械で防ぐ仕組みはまだありません。
これを書いてからは日が浅く、効いているかどうか、まではまだ分かりません。
線を引く場所
可逆性で線を引く話を以前に書きました。あの線は、この事故を通します。止まったのは読み取りの query で、何も変えていないからです。別の線が要る、ということです。共通しているのは線を引く場所で、「AI に触らせる・触らせない」という道具の側ではなく、「元に戻せるか」「実行計画の形」という操作の性質の側に引いています。道具や行数のように、事故と相関はあっても因果の無いところに線を引くと、安全にならないまま不便だけが残ります。
なので、30分止まったから AI にはもう引かせない、という判断は、この AI の時代、間違いだと思います。止まった原因は query の形にあって、道具にはありません。指を切るから包丁を使いませんか? 人を轢き殺すから車に乗りませんか? まぁ、乗らないかもしれませんけど。墜落するから飛行機には乗りませんか? 乗らない人もいますか… 道具を遠ざけても同じ query は同じだけ止まりますし、調査の速さだけが失われます。やるべきは原因を調べることで、そこから出てくる規則は「引かない」ではなく「引き方を決める」です。
(下書きはうちのAIが書き、文責は私にあります)