【MySQL】テーブル作成時に自動生成されるIndexたち
はじめに
MySQLでインデックスを使用しているかを尋ねられる機会がありました.
PRIMARY KEYやFOREIGN KEYを用いての検索がほとんどだったので大丈夫だという認識でしたが,明示的に設定していないだけで自動生成されていたのかな,,,と疑問が湧いたので実際にSHOW INDEX
で確認しました.
携わったサービスでは,mysql:8.0
を使用しており,mysqldefを用いてschema.sql
でスキーマを管理していました.
調査結果
今回の調査では,
- PRIMARY KEY制約
- UNIQUE制約
- FOREIGN KEY制約
でindexが自動生成されるを確認しました!
また,公式ドキュメントでは,全文検索に用いられるFULLTEXT
でも生成されることが示されていました.
ほとんどの MySQL インデックス (PRIMARY KEY、UNIQUE、INDEX、および FULLTEXT) は B ツリーに格納されます。 例外: 空間データ型のインデックスは R ツリーを使用します。MEMORY テーブルはハッシュインデックスもサポートします。InnoDB は FULLTEXT インデックスの逆のリストを使用します。
調査内容
1. 何も制約をつけない
はじめに定義したスキーマはこちらです.
CREATE TABLE `users` (
`id` int
) ENGINE=InnoDB;
結果
MySQL root@127.0.0.1:example> SHOW INDEX FROM users
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
0 rows in set
当然何も表示されませんでしたネ.
2. PRIMARY KEY制約
id
を主キーに設定しました.
CREATE TABLE `users` (
`id` int NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
結果
MySQL root@127.0.0.1:example> SHOW INDEX FROM users
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| users | 0 | PRIMARY | 1 | id | A | 0 | <null> | <null> | | BTREE | | | YES | <null> |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
1 row in set
PRIMARY KEYを設定した場合は,indexが自動生成されました!
3. UNIQUE制約
UNIQUE制約をつけたfirebase_uid
カラムを追加しました.
CREATE TABLE `users` (
`id` int NOT NULL,
`firebase_uid` varchar(255) UNIQUE,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
結果
MySQL root@127.0.0.1:example> SHOW INDEX FROM users
+-------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| users | 0 | PRIMARY | 1 | id | A | 0 | <null> | <null> | | BTREE | | | YES | <null> |
| users | 0 | firebase_uid | 1 | firebase_uid | A | 0 | <null> | <null> | YES | BTREE | | | YES | <null> |
+-------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set
UNIQUE制約でも,indexが自動生成されました!
3. FOREIGN KEY制約
新たにitems
テーブルを追加し,user_id
カラムにusers
テーブルのid
のFOREIGN KEY制約を設定しました.
CREATE TABLE `users` (
`id` int NOT NULL,
`firebase_uid` varchar(255) UNIQUE,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `items` (
`id` int NOT NULL,
`user_id` int NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_items_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB;
結果
MySQL root@127.0.0.1:example> SHOW INDEX FROM items
+-------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| items | 0 | PRIMARY | 1 | id | A | 0 | <null> | <null> | | BTREE | | | YES | <null> |
| items | 1 | fk_items_user_id | 1 | user_id | A | 0 | <null> | <null> | | BTREE | | | YES | <null> |
+-------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set
FOREIGN KEY制約でも,indexが自動生成されました!
おわりに
「PRIMARY KEYやFOREIGN KEYを使ってるからエエやろ」のなんとなくの理解が,ちゃんとindexの恩恵を授かっていたことを理解できて勉強になりました!
また,今回携わったサービスでは,複合インデックス等,パフォーマンスを見てのチューニングは行っていなかったのですが,サービスのグロースに伴って必ず必要になるところなので,意識して設計しないとなと自分を戒める良い機会になりました.
ちなみに,チューニングを行っていなかった理由としては,スロークエリログで致命的に遅いクエリがなかった,パフォーマンス的に気になるとこまでデータ増えなかったためタスクとしての優先度が低かったため(あと面倒)でした.
サービスが成長しないと技術的にも成長しないんやなと思いましたネ(悲しい)
今後,とりあえずやってみようということで,EXPLAIN
等用いながら手元でパフォーマンスチューニングやってみようと思います!
Discussion