MySQL允许在相同列上创建重复的索引,但这样做对数据库却是有害而无利的,需要定期检查此类重复索引以改善数据库性能。
可减少磁盘空间占用、减少磁盘IO、减少优化器优化查询时需要比较的索引个数、减少数据库维护冗余索引的各类开销、提高数据库性能(插入、更新、删除)
重复索引检测
pt-duplicate-key-checker:通过SHOW CREATE TABLE输出的表定义检测MySQL表中重复或者冗余的索引或外键
可以检测到的冗余/重复索引类型:若某个索引和另外某个索引以同样的顺序包含同样的列,或者该索引包含的列是另外某个索引的最左前缀列,则被认为是重复/冗余的索引。默认情况下只在同类型的索引间(如BTREE索引)进行比较,不同类型的索引即使符合上述描述也不会被认为是重复/冗余,但这一行为可以通过参数改变。除此之外,还可检测重复的外键,即引用的表和列均相同的外键。对于聚簇索引的表,在辅助索引后添加主键列的索引也被认为是冗余的,因为这种情况下,辅助索引末尾本身就包含有主键信息。
首先看我的这张表的索引结构
mysql> show indexes from curs;
- +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
- | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
- +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
- | curs | 0 | PRIMARY | 1 | id | A | 1 | NULL | NULL | | BTREE | | |
- | curs | 1 | name | 1 | name | A | 1 | NULL | NULL | | BTREE | | |
- | curs | 1 | age | 1 | age | A | 1 | NULL | NULL | | BTREE | | |
- | curs | 1 | name_age | 1 | name | A | 1 | NULL | NULL | | BTREE | | |
- | curs | 1 | name_age | 2 | age | A | 1 | NULL | NULL | | BTREE | | |
- | curs | 1 | age_name | 1 | age | A | 1 | NULL | NULL | | BTREE | | |
- | curs | 1 | age_name | 2 | name | A | 1 | NULL | NULL | | BTREE | | |
- | curs | 1 | name_1 | 1 | name | A | 1 | NULL | NULL | | BTREE | | |
- | curs | 1 | age_1 | 1 | age | A | 1 | NULL | NULL | | BTREE | | |
- +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
里面有大量的重复索引,比如name与name_age重复,也与name_1重复,这3个索引都是相同的索引。下面看下怎么使用/usr/local/bin/pt-duplicate-key-checker来检查重复的索引。
[root@localhost ~]# /usr/local/bin/pt-duplicate-key-checker --host=192.168.1.106 --user='mysql' --password='123456' --databases=test --tables=curs
- # ########################################################################
- # test.curs
- # ########################################################################
- # name is a left-prefix of name_age
- # Key definitions:
- # KEY `name` (`name`),
- # KEY `name_age` (`name`,`age`),
- # Column types:
- # `name` varchar(100) not null default ''
- # `age` smallint(3) unsigned not null default '0'
- # To remove this duplicate index, execute:
- ALTER TABLE `test`.`curs` DROP INDEX `name`;
- # name_1 is a left-prefix of name_age
- # Key definitions:
- # KEY `name_1` (`name`),
- # KEY `name_age` (`name`,`age`),
- # Column types:
- # `name` varchar(100) not null default ''
- # `age` smallint(3) unsigned not null default '0'
- # To remove this duplicate index, execute:
- ALTER TABLE `test`.`curs` DROP INDEX `name_1`;
- # age is a left-prefix of age_name
- # Key definitions:
- # KEY `age` (`age`),
- # KEY `age_name` (`age`,`name`),
- # Column types:
- # `age` smallint(3) unsigned not null default '0'
- # `name` varchar(100) not null default ''
- # To remove this duplicate index, execute:
- ALTER TABLE `test`.`curs` DROP INDEX `age`;
- # age_1 is a left-prefix of age_name
- # Key definitions:
- # KEY `age_1` (`age`)
- # KEY `age_name` (`age`,`name`),
- # Column types:
- # `age` smallint(3) unsigned not null default '0'
- # `name` varchar(100) not null default ''
- # To remove this duplicate index, execute:
- ALTER TABLE `test`.`curs` DROP INDEX `age_1`;
- # ########################################################################
- # Summary of indexes
- # ########################################################################
- # Size Duplicate Indexes 608
- # Total Duplicate Indexes 4
- # Total Indexes 7