使用されず役に立たないインデックスを定義するのは、
ただ実際には、
もしも万が一そのインデックスが使用されているクエリが存在するとしたら、
検証環境
今回はDockerHub上のMySQLイメージを利用して行います。バージョンは8.
$ docker run --name michibushin -v "/tmp:/tmp" -e MYSQL_ROOT_PASSWORD=my-secret-pw -d -p 3306:3306 -d mysql:8.0.18 --secure-file-priv=/tmp
上記の操作で起動して、
$ mysql -h0.0.0.0 -uroot -pmy-secret-pw
検証用のテーブルとデータ
検証用のデータとしては、
第2回と異なる点としては、
$ cat ken_all.sql CREATE DATABASE zipcode CHARACTER SET utf8mb4; CREATE TABLE zipcode.zipcode( code varchar(12) NOT NULL, old_zipcode varchar(5) NOT NULL, zip_code varchar(7) NOT NULL, prefecture_kana varchar(255) NOT NULL, city_kana varchar(255) NOT NULL, town_kana varchar(255) NOT NULL, prefecture varchar(128) NOT NULL, city varchar(128) NOT NULL, town varchar(128) NOT NULL ) DEFAULT CHARACTER SET= utf8mb4; ALTER TABLE zipcode.zipcode ADD INDEX index_zipcode_on_zip_code_and_old_zip_code(zip_code, old_zipcode); ALTER TABLE zipcode.zipcode ADD INDEX index_zipcode_on_zip_code(zip_code); $ mysql -h0.0.0.0 -uroot -pmy-secret-pw < ken_all.sql
データベースにアクセスしてみて、
$ mysql -h0.0.0.0 -uroot -pmy-secret-pw zipcode mysql> show create table zipcode; +---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | zipcode | CREATE TABLE `zipcode` ( `code` varchar(12) NOT NULL, `old_zipcode` varchar(5) NOT NULL, `zip_code` varchar(7) NOT NULL, `prefecture_kana` varchar(255) NOT NULL, `city_kana` varchar(255) NOT NULL, `town_kana` varchar(255) NOT NULL, `prefecture` varchar(128) NOT NULL, `city` varchar(128) NOT NULL, `town` varchar(128) NOT NULL, KEY `index_zipcode_on_zip_code_and_old_zip_code` (`zip_code`,`old_zipcode`), KEY `index_zipcode_on_zip_code` (`zip_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci | +---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
無駄なインデックスを特定する
現在使われていないインデックスを特定する必要があります。今回は第9回 pt-query-digestを使って遅いクエリーを発見するでも紹介したPercona Toolkitのpt-duplicate-key-checkerを使う方法と、sys.
を利用する方法を紹介したいと思います。
pt-duplicate-key-checker
こちらは以前Percona Toolkitの1つで、
というわけで実行をしてみましょう。
$ pt-duplicate-key-checker --host 0.0.0.0 --user root --password my-secret-pw --database zipcode # ######################################################################## # zipcode.zipcode # ######################################################################## # index_zipcode_on_zip_code is a left-prefix of index_zipcode_on_zip_code_and_old_zip_code # Key definitions: # KEY `index_zipcode_on_zip_code` (`zip_code`) # KEY `index_zipcode_on_zip_code_and_old_zip_code` (`zip_code`,`old_zipcode`), # Column types: # `zip_code` varchar(7) not null # `old_zipcode` varchar(5) not null # To remove this duplicate index, execute: ALTER TABLE `zipcode`.`zipcode` DROP INDEX `index_zipcode_on_zip_code`; # ######################################################################## # Summary of indexes # ######################################################################## # Size Duplicate Indexes 30 # Total Duplicate Indexes 1 # Total Indexes 2
結果の部分が2つあり、
また、
sys.schema_unused_indexes
こちらはMySQL 5.
mysql> select * from sys.schema_unused_indexes; +---------------+-------------+--------------------------------------------+ | object_schema | object_name | index_name | +---------------+-------------+--------------------------------------------+ | zipcode | zipcode | index_zipcode_on_zip_code_and_old_zip_code | | zipcode | zipcode | index_zipcode_on_zip_code | +---------------+-------------+--------------------------------------------+ 2 rows in set, 1 warning (0.00 sec)
まだクエリを一度も発行していないので、
mysql> select * from zipcode where zip_code like '105%' limit 1; +-------+-------------+----------+--------------------+--------------+-----------------------------------------------+------------+--------+--------------------------------+ | code | old_zipcode | zip_code | prefecture_kana | city_kana | town_kana | prefecture | city | town | +-------+-------------+----------+--------------------+--------------+-----------------------------------------------+------------+--------+--------------------------------+ | 13103 | 105 | 1050000 | トウキョウト | ミナトク | イカニケイサイガナイバアイ | 東京都 | 港区 | 以下に掲載がない場合 | +-------+-------------+----------+--------------------+--------------+-----------------------------------------------+------------+--------+--------------------------------+ 1 row in set (0.00 sec)
実行後再度確認をしてみると、
mysql> select * from zipcode where zip_code like '105%' limit 1; +-------+-------------+----------+--------------------+--------------+-----------------------------------------------+------------+--------+--------------------------------+ | code | old_zipcode | zip_code | prefecture_kana | city_kana | town_kana | prefecture | city | town | +-------+-------------+----------+--------------------+--------------+-----------------------------------------------+------------+--------+--------------------------------+ | 13103 | 105 | 1050000 | トウキョウト | ミナトク | イカニケイサイガナイバアイ | 東京都 | 港区 | 以下に掲載がない場合 | +-------+-------------+----------+--------------------+--------------+-----------------------------------------------+------------+--------+--------------------------------+ 1 row in set (0.01 sec)
気をつける点としては、
Invisible Indexesを試してみる
さてここまでで不要なインデックスに関して簡単に知ることができました。さぁドロップをしてみましょう!
というわけで、
mysql> explain select * from zipcode where zip_code like '105%' limit 1; +----+-------------+---------+------------+-------+----------------------------------------------------------------------+--------------------------------------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+-------+----------------------------------------------------------------------+--------------------------------------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | zipcode | NULL | range | index_zipcode_on_zip_code_and_old_zip_code,index_zipcode_on_zip_code | index_zipcode_on_zip_code_and_old_zip_code | 30 | NULL | 369 | 100.00 | Using index condition | +----+-------------+---------+------------+-------+----------------------------------------------------------------------+--------------------------------------------+---------+------+------+----------+-----------------------+ 1 row in set, 1 warning (0.00 sec)
この時点の状態では、index_
が選択されていそうという事がわかります。ここで以下のクエリを実行し、
mysql> ALTER TABLE zipcode alter index index_zipcode_on_zip_code_and_old_zip_code invisible;
この状態で再度explainを取ってみましょう。
mysql> explain select * from zipcode where zip_code like '105%' limit 1; +----+-------------+---------+------------+-------+---------------------------+---------------------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+-------+---------------------------+---------------------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | zipcode | NULL | range | index_zipcode_on_zip_code | index_zipcode_on_zip_code | 30 | NULL | 369 | 100.00 | Using index condition | +----+-------------+---------+------------+-------+---------------------------+---------------------------+---------+------+------+----------+-----------------------+ 1 row in set, 1 warning (0.00 sec)
ということでオプティマイザーから選択されない状態になりました。
続いて元に戻してみましょう。
mysql> ALTER TABLE zipcode alter index index_zipcode_on_zip_code_and_old_zip_code visible; mysql> explain select * from zipcode where zip_code like '105%' limit 1; +----+-------------+---------+------------+-------+----------------------------------------------------------------------+--------------------------------------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+-------+----------------------------------------------------------------------+--------------------------------------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | zipcode | NULL | range | index_zipcode_on_zip_code_and_old_zip_code,index_zipcode_on_zip_code | index_zipcode_on_zip_code_and_old_zip_code | 30 | NULL | 369 | 100.00 | Using index condition | +----+-------------+---------+------------+-------+----------------------------------------------------------------------+--------------------------------------------+---------+------+------+----------+-----------------------+ 1 row in set, 1 warning (0.01 sec)
元の状態に即座に直すことができました。使い方は簡単で、
さて、
mysql> ALTER TABLE zipcode alter index index_zipcode_on_zip_code_and_old_zip_code invisible;
一旦インデックスを再びinvisibleにします。その状態で、index_
を指定をしてみましょう。
mysql> explain select * from zipcode FORCE INDEX (index_zipcode_on_zip_code_and_old_zip_code) where zip_code like '105%' limit 1; ERROR 1176 (42000): Key 'index_zipcode_on_zip_code_and_old_zip_code' doesn't exist in table 'zipcode'
エラーになってしまいました。というわけで、
まとめ
今回は重複したキーやインデックスを調査し、