SQL Server で起きた怖い話
自己紹介
こんにちは、いいじまと申します。
今までは Java での Web 開発を主にやっておりましたが、ここ1年ほどは ASP .NET MVC とお付き合いしております。LINQ って素敵だね!
さて本日はその中で遭遇したちょっと怖いお話。
それは検索処理が遅いことから始まりました
データベースに接続して検索するなんて Web システムではよくある話ですよね。
ある日、ちょっとした検索処理を作成したら検索処理が遅いのです。
こういう場合の定石は
- テーブル設計:検索対象のカラムにインデックスを作成する
- クエリ:IN句を EXISTS 句に変更する
あたりでしょうか。
……おやおかしいな、検索対象カラムにも、テーブルの結合条件であるカラムにもインデックスが作成されている。クエリに IN 句は使われてない。
全件検索なら一瞬なのに……?
調べてみると、全件を取得するときは一瞬で結果が出るのです。
ところが「先頭100件」という方法で取得すると遅延する。
つまり
SELECT * FROM TABLE_NAME ORDER BY COLUMN_NAME
は問題なく、
SELECT TOP(100) * FROM TABLE_NAME ORDER BY COLUMN_NAME
は遅延する。
しかも信じがたいことに、 TOP の数字がある値を下回ると遅延が発生するのです。
さらに信じがたいことに、その閾値とでもいうべき値はテーブルのレコード件数によって変動している気配がある。
求む、ゴーストバスター
この現象が発生したのは SQL Server 2012 。
残念なことに原因や対処法はおろか、再現条件さえ私はまだ見つけられておりません。
当座の対処として
- クエリでは遅延が起きないように十分に大きい値を取得件数として指定する
- 取得した後にプログラム側で必要な件数に絞り込む
なんてことは考えましたが根本的解決ではありませんしね。
解決できていない問題をここに書くのは恥ずかしいことかもしれませんが、SQL Serverで同様の現象に遭遇した方がいらしたら「TOPの値を変えれば一時しのぎになる」とお伝えしたくてこの記事を書かせてもらいました。
TOPの遅延というお化けを退治できるゴーストバスターを、私は切にお待ちしております。