困っていること
MySQL5.7環境で、where句にユーザ定義変数を使うと、インデックスが効きません。
具体的には以下のような実装となります。
set @code = 'XXX'
select * from test where code = @code
code列は文字列型で、プライマリーキーです。レコード件数は100万件を超えています。
体感で3~5秒程度のレスポンスとなっています。
@codeの位置に直接文字リテラル'XXX'を記載すると、一瞬で処理が終わります。
explainでも変数の場合は全件走査、文字リテラル直接指定だとインデックスが有効と
なる結果が返ってきます。
** explain 変数利用時 **
|id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra|
|:--|:--|:--|
|1|SIMPLE|test||ALL|||||1756058|100|Using where|
** explain 文字リテラル直接指定時 **
|id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra|
|:--|:--|:--|
|1|SIMPLE|test||const|PRIMARY|PRIMARY|152|const|1|100||
原因として考えられることがあれば、どなたか助言のほどよろしくお願いします。
そもそもの経緯
上記は要約した形で記載しておりますが、元々はストアドプロシージャ内で発生した事象になります。
- cursorを定義(testテーブル)
- select結果を入れる変数を定義
- cursorをオープンしてフェッチ(2の変数に代入しながらループ)
- 任意の処理(データ加工など)
- testテーブルをcodeを指定してupdate ※ここでSQLが遅延
別のセッションからshow processlistで見ると「5」がプライマリーキー指定にも
かかわらず5秒程度時間がかかっていることが発覚。
固定文字に置き換えると再現しなくなったので、変数を条件にしていることが
原因と予想し、最初に記載した内容で検証したところ同様の事象が発生。
補足情報
MySQLのバージョンは5.7.31です。
元々はインデックスが有効となっていたはずなのですが、別件でDBが破損したことにより
再構築をしてから、当該事象が発生するようになりました。。
環境周りの設定を疑い、以前の状態と比較したのですが、それらしい設定での相違は
見当たりませんでした...。打つ手がない状況です。
2020.10.21追記
検証中に、利用しているDBツール(HeidiSQL)で以下の警告が表示されました。(昨日までは出ていなかったんですけど...)
Warnings from last query: Warning: Cannot use ref access on index 'code' due to type or collation conversion on field 'code'
対象フィールドの型と、変数の方が不一致なので暗黙的な型変換がされてるよ。っていう感じのこと…?
確かに変数には型指定していない(できない)ので、納得できるような気もしますが…。
回答2件
あなたの回答
tips
プレビュー