mysqlインデックス上書きのインスタンスについて

2962 ワード

ところで、こんな表があります.
CREATE TABLE `user_group` (
  `id` int(11) NOT NULL auto_increment,
  `uid` int(11) NOT NULL,
  `group_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `uid` (`uid`),
  KEY `group_id` (`group_id`),
) ENGINE=InnoDB AUTO_INCREMENT=750366 DEFAULT CHARSET=utf8

AUTO_を見るINCREMENTはデータが多くないことを知っていて、75万件です.次に、簡単なクエリーが表示されます.
SELECT SQL_NO_CACHE uid FROM user_group WHERE group_id = 245;

簡単でしょ?奇妙な点は、
MyISAMに切り替えてストレージエンジンを作る場合、クエリにかかる時間は0.01 s、InnoDBでは0.15 s程度です
これだけの差なら大したことではありませんが、実際のビジネスニーズはこれより複雑で、差も大きいです.MyISAMは0.12 sしか必要ありません.InnoDBは2.2 sが必要です.最終的に問題の結末に位置付けたのはこのSQLです.
Explainの結果は次のとおりです.
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
| id | select_type | table      | type | possible_keys | key      | key_len | ref   | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+
|  1 | SIMPLE      | user_group | ref  | group_id      | group_id | 4       | const | 5544 |       |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+

インデックスが使用されているように見えますが、このSQL文は最適化できないほど簡単です.最後に前の同僚を呼ぶ
Gastonは診断して、彼はデータの分布の上で、group_idは同じものが多く、uidハッシュは比較的均一で、インデックスを付ける効果は一般的ですが、マルチカラムインデックスを追加してみることをお勧めします.
ALTER TABLE user_group ADD INDEX group_id_uid (group_id, uid);

そして、不思議なことに……というSQLクエリのパフォーマンスが飛躍的に向上し、なんと0.00 sくらいまで走ることができました.最適化されたSQLは、実際のビジネスニーズと組み合わせて、2.2 sから0.05 sに低下しました.
もう一度Explain:
+----+-------------+------------+------+-----------------------+--------------+---------+-------+------+-------------+
| id | select_type | table      | type | possible_keys         | key          | key_len | ref   | rows | Extra       |
+----+-------------+------------+------+-----------------------+--------------+---------+-------+------+-------------+
|  1 | SIMPLE      | user_group | ref  | group_id,group_id_uid | group_id_uid | 4       | const | 5378 | Using index |
+----+-------------+------------+------+-----------------------+--------------+---------+-------+------+-------------+

元々はカバーインデックス(covering index)と呼ばれていましたが、MySQLはインデックスを通じてクエリーに必要なデータを返すだけで、インデックスを調べてからデータをクエリーする必要はありませんので、それはかなり速いです!!ただし、クエリのフィールドはインデックスで上書きする必要があります.Explainの場合、出力されるExtra情報に「Using Index」があれば、このクエリが上書きインデックスを使用していることを示します.
しかし、もう一つ説明できない問題は、インデックスを上書きしない場合、なぜMyISAMを使うのがそんなに速く、InnoDBを使うのがこんなに遅いのかということです.真実を求めて...
答え:myisamのインデックスとデータは別々なのでgroup_idにインデックスが作成されている場合、インデックスがkeybufferにすでに存在する場合、その文はディスクに記録されている場所を直接位置決めすることができます.
innodbのインデックスはプライマリ・キーと一緒にあります.いわゆるcluster indexです.group_idの上に建てられたのは実はsecondary indexでgroup_を使うとidを条件として検索する場合、実際にはsecondary indexのb-treeで検索して、まずプライマリ・キーのidを得て、それからプライマリ・キーのidに基づいてcluster indexのb-treeで検索して、リーフ・ノード、つまり実際のレコードを見つけて、ここでb-treeを2回検索したので、遅くなります