質問: 123456 AND T1.url like 'http://abc.jp/xxx/xxxx/xxx%' ORDER BY col1 Limit 0, 100 ``` 5:実行計画 ``` id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra 1 | SIMPLE | T1 | range | IX_col1,IX_col2,IX_col3,IX_col5_col1,IX_col6,IX_col1_col5,IX_date,IX_url | IX_col1_col5 | 8 | NULL | 1157468 | Using index condition; Using where ``` ※上記の実行計画は「http://abc.jp/xxx/xxxx/xxx%」の部分を68文字のURLを指定し、このURLだけで1件の表示になる値で実行計画を出しています。そのため、理想の実行計画としては、 refに「IX_url」が表示され、rows項目も1となる事を想定していました。 ※仮に「http://abc.jp/xxx/xxxx/xxx%」とした場合、データが存在しないため、 ref項目に「IX_url」が表示され、rows項目も1となります。 6:その他注意事項 ・URL項目に対して、Likeではなく、=による絞り込みはNGとなります。 ・URLを階層別にハッシュ化して、=による絞り込みもNGとなります。 ・URLを1文字ずつずらしてハッシュ化して、=による絞り込みはOKですが、 INDEXが最大数(64個)を超えてしまうため、出来ないと考えてます。 ・MATCH AGAINSTはOKですが、この更新型テーブルにFULLTEXT INDEXを貼って効果があるかは、現在調査中です。 ### 発生している問題・エラーメッセージ USE INDEX ( IX_url )やUSE KEY( IX_url )を利用しても、実行計画のref項目に「IX_url」は表示されず、 実際に実行してもものすごく時間がかかる(10分経っても終わらない)状況です。 これを数秒以内に結果が返ってくる形にしたいと考えています。 ### 該当のソースコード 上記SQL参照 ### 試したこと 上記説明参照 ### 補足情報(言語/FW/ツール等のバージョンなど) MySQLのバージョンは5.6.22 phpMyAdminのバージョンは4.5.1(ちょっと古い) 実行計画や速度が遅く感じると判断した際の動作環境は phpMyAdmin上での実行結果になります。 ### 追記 check table tb_test_data; を実行した場合、2時間経っても終わらないため、実施していません。 check table tb_test_data fast quick; にて、テーブルの状態を確認していますが、 statusは「Table is already up to date」の状態で、問題ない認識です。 show table status like 'tb_test_data%'; にて、断片化は確認をしていて、0.6%程度の断片化率です。 (該当テーブルのURL以外の指定における性能劣化は見られていません。) ### 追記2 検索用URL(100文字等)を作ってINDEXを貼って検索するのは、個人的には良いのですが、 仕様決定者的にはNGでした。。 ### 追記3 index(col7,col1,url(200))の追加案については、 col7での絞込件数≒実際の絞込件数(urlによる絞り込みがほとんどない) であれば、Limitが効くため、性能は良いですが、 検索結果が「1件」の場合、Limitの効果がないため、性能遅延が発生してしまいます。 index(col1,col7,url(200))の追加案については、 全体の件数≒col7での絞込件数≒実際の絞込件数(col7,urlによる絞り込みがほとんどない) であれば、Limitが効くため、性能は良いですが、 検索結果が「1件」の場合、Limitの効果がないため、性能遅延が発生してしまいます。 なお、上記2つのINDEXでは、URLのINDEXには届かないため、1件抽出する場合、即レスポンスにならないです。 INDEXさえ効けば、検索結果が1件の場合、即終わるハズなのですが、 実行計画の時点で効かない原因を知りたいです。。 ### 追記4 InnoDBについて InnoDB化した場合、300万の登録に60分経っても終わらなかったため、INDEXが効くかどうかは分かりません。 別の仕様(毎秒100件の削除・登録)が不可であるため、InnoDB化はできません。 (MyISAMであれば、300万の登録に7分で終わります) InnoDBは統計情報がきれいなはずなので、InnoDBであれば、確かに効く気はしています。 ### 追記5 INDEXが効いたSQLと効かないSQLがありましたので、情報共有いたします。 ”存在しないURL”を指定すると、基本的に、INDEXが効きいて、1秒以内のレスポンスになりました。 ただし、"存在しないURL"が50文字以上となると、INDEXが効かず、300秒くらいのレスポンスになってしまいました。。 MySQL5.6.22のバグなんじゃないかと思い始めてます。。 ### 追記6 AkiraPenguin 様の回答により、解決いたしました! ありがとうございます!!!!! なお、追記5の問題も、ちょうど50文字目が「_」となっておりました。 「_」を含むURLは300万件存在するため、「_」の後に存在しないURLを置いていても、 それはINDEXが効きません。。。当然ですね。。。 たくさんの閲覧・回答ありがとうございました!
回答: まぁ第一に1.5億データとなるとパフォーマンス的にかなり厳しいでしょう nosql系の処理に切り替えた方がよいかもしれません。 たしかtextにはインデックスって貼れないですよね? 別途textから50~100文字切り出した検索用varcharカラムを用意するなど 根本的な対策が必要じゃないでしょうか? データ容量も相当でしょうから、何らかの切り分けやグルーピングができるなら パーティショニングなどで分散管理したほうがよいかもしれません MySQL 5.6.6 以降はSELECT時のロックが該当するパーティションのみになるよう 効率化されたようです