mysql组合索引探索
组合索引
什么是组合索引
组合索引(Compound Index)是指由多个列所组合而成的 B+树索引,这和B+ 树索引的原理完全一样,只是单列索引是对一个列排序,现在是对多个列排序。
简单来说就是有多个列组合而成的索引。
为什么要使用组合索引
首先我们先创建一个测试表,并填充一些测试数据
mysql> CREATE TABLE `test_multi_index` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`code` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`value` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`desc` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`c1` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`c2` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`c3` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`c4` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `i_test` (`name`,`code`,`value`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
使用php
进行随机数据填充
use Illuminate\Support\Str;
Route::get('/test', function() {
for ($a = 0; $a < 10; $a++) {
$data = [];
for ($i = 0; $i < 5000; $i++) {
$data[] = [
'code' => Str::random(20),
'name' => Str::random(50),
'value' => Str::random(50),
'desc' => rand(1, 10) > 2 ? Str::random(50) : null,
'c1' => rand(1, 10) > 3 ? Str::random(50) : null,
'c2' => rand(1, 10) > 4 ? Str::random(50) : null,
'c3' => rand(1, 10) > 5 ? Str::random(50) : null,
'c4' => rand(1, 10) > 6 ? Str::random(50) : null,
];
}
DB::table('test_multi_index')->insert($data);
}
});
mysql> select count(*) from test_multi_index;
+----------+
| count(*) |
+----------+
| 640001 |
+----------+
1 row in set (0.11 sec)
填充数据量在64万左右。
当我们使用单列索引的情况下,有多个where
条件列,那么会使用多个索引吗?
mysql> alter table test_multi_index add index i_name(name) using btree;
Query OK, 0 rows affected (6.30 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table test_multi_index add index i_code(code) using btree;
Query OK, 0 rows affected (4.83 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc select * from test_multi_index where name like 'a%' and code like 'b%';
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------------------------------+
| 1 | SIMPLE | test_multi_index | NULL | range | i_name,i_code | i_code | 1022 | NULL | 43198 | 7.03 | Using index condition; Using where; Using MRR |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> select * from test_multi_index where name like 'a%' and code like 'b%' limit 1;
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
| id | name | code | value | desc | c1 | c2 | c3 | c4 |
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
| 51 | AM5Z9acnOkUuyJ8G2b2wFc4tpqpkkGZRjWRJcmQuA1sRKNYo8D | BfEn0r2omxocCrtVH6an | 46X2iZUHkggp5AX4Cd54903Hwsp23viBuOqhPNjRLSNdeSsb73 | f44udNYtLILvC3GI5QiMrfJiUSxP9KLHVQ6aHBnJlDHgCvBhwr | NULL | RiTjKkuKXA3yPEjZNwxuw3HZVzH6Sq1jVDdMdP1ebbbuFflI44 | 54E3XCTcpLO2WgAAx1sN5hj6L4vtmYeUcFVjkGDU3qq5b7n6g8 | y0XyQ0VutrVKwIXrp1UW30TUw34IZLd9ZWkaPRxh2nOe4I5TVp |
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
692 rows in set (1.93 sec)
mysql> alter table test_multi_index drop index i_name;
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table test_multi_index drop index i_code;
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table test_multi_index add index i_test(name,code);
Query OK, 0 rows affected (7.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc select * from test_multi_index where name like 'a%' and code like 'b%';
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+
| 1 | SIMPLE | test_multi_index | NULL | range | i_test | i_test | 2044 | NULL | 40226 | 11.11 | Using index condition; Using MRR |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> select * from test_multi_index where name like 'a%' and code like 'b%' limit 1;
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
| id | name | code | value | desc | c1 | c2 | c3 | c4 |
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
| 51 | AM5Z9acnOkUuyJ8G2b2wFc4tpqpkkGZRjWRJcmQuA1sRKNYo8D | BfEn0r2omxocCrtVH6an | 46X2iZUHkggp5AX4Cd54903Hwsp23viBuOqhPNjRLSNdeSsb73 | f44udNYtLILvC3GI5QiMrfJiUSxP9KLHVQ6aHBnJlDHgCvBhwr | NULL | RiTjKkuKXA3yPEjZNwxuw3HZVzH6Sq1jVDdMdP1ebbbuFflI44 | 54E3XCTcpLO2WgAAx1sN5hj6L4vtmYeUcFVjkGDU3qq5b7n6g8 | y0XyQ0VutrVKwIXrp1UW30TUw34IZLd9ZWkaPRxh2nOe4I5TVp |
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
692 rows in set (0.55 sec)
可以看出这里分析的时候是有用到两个索索引,但是执行sql的时候只使用了
i_code
索引,猜测是因为使用i_code
命中的行数比i_name
多。mysql
自动优化,选择使用了i_code
索引。稍后再进行验证。
稍微设计下验证方法,再创建两个索引,分别使用where name like 'a%'
和where code like 'b%'
查看影响的行数。在sql
中强制使用i_name
、i_code
查看查询耗时。
mysql> alter table test_multi_index add index i_name(name) using btree;
Query OK, 0 rows affected (6.84 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table test_multi_index add index i_code(code) using btree;
Query OK, 0 rows affected (4.71 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table test_multi_index drop index i_test;
Query OK, 0 rows affected (0.11 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc select * from test_multi_index where name like 'a%';
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+
| 1 | SIMPLE | test_multi_index | NULL | range | i_name | i_name | 1022 | NULL | 43820 | 100.00 | Using index condition; Using MRR |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> desc select * from test_multi_index where code like 'b%';
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+
| 1 | SIMPLE | test_multi_index | NULL | range | i_code | i_code | 1022 | NULL | 43198 | 100.00 | Using index condition; Using MRR |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+----------------------------------+
1 row in set, 1 warning (0.01 sec)
mysql> desc select * from test_multi_index force index(i_name) where name like 'a%' and code like 'b%';
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------------------------------+
| 1 | SIMPLE | test_multi_index | NULL | range | i_name | i_name | 1022 | NULL | 43820 | 11.11 | Using index condition; Using where; Using MRR |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> desc select * from test_multi_index force index(i_code) where name like 'a%' and code like 'b%';
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------------------------------+
| 1 | SIMPLE | test_multi_index | NULL | range | i_code | i_code | 1022 | NULL | 43198 | 11.11 | Using index condition; Using where; Using MRR |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------------------------------+
1 row in set, 1 warning (0.01 sec)
mysql> select * from test_multi_index force index(i_name) where name like 'a%' and code like 'b%';
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
| id | name | code | value | desc | c1 | c2 | c3 | c4 |
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
| 51 | AM5Z9acnOkUuyJ8G2b2wFc4tpqpkkGZRjWRJcmQuA1sRKNYo8D | BfEn0r2omxocCrtVH6an | 46X2iZUHkggp5AX4Cd54903Hwsp23viBuOqhPNjRLSNdeSsb73 | f44udNYtLILvC3GI5QiMrfJiUSxP9KLHVQ6aHBnJlDHgCvBhwr | NULL | RiTjKkuKXA3yPEjZNwxuw3HZVzH6Sq1jVDdMdP1ebbbuFflI44 | 54E3XCTcpLO2WgAAx1sN5hj6L4vtmYeUcFVjkGDU3qq5b7n6g8 | y0XyQ0VutrVKwIXrp1UW30TUw34IZLd9ZWkaPRxh2nOe4I5TVp |
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
692 rows in set (1.86 sec)
mysql> select * from test_multi_index force index(i_code) where name like 'a%' and code like 'b%';
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
| id | name | code | value | desc | c1 | c2 | c3 | c4 |
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
| 51 | AM5Z9acnOkUuyJ8G2b2wFc4tpqpkkGZRjWRJcmQuA1sRKNYo8D | BfEn0r2omxocCrtVH6an | 46X2iZUHkggp5AX4Cd54903Hwsp23viBuOqhPNjRLSNdeSsb73 | f44udNYtLILvC3GI5QiMrfJiUSxP9KLHVQ6aHBnJlDHgCvBhwr | NULL | RiTjKkuKXA3yPEjZNwxuw3HZVzH6Sq1jVDdMdP1ebbbuFflI44 | 54E3XCTcpLO2WgAAx1sN5hj6L4vtmYeUcFVjkGDU3qq5b7n6g8 | y0XyQ0VutrVKwIXrp1UW30TUw34IZLd9ZWkaPRxh2nOe4I5TVp |
+----+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
692 rows in set (0.39 sec)
可以看出验证结果和我们猜测相反,这是因为我们刚才思路出现问题,当命中行数越多时,需要排查的行数越多。只有命中行数越少,排除错误行数的时间就会越少,才能更有效的节约资源,降低查询时间。
创建组合索引
mysql> ALTER TABLE `test_multi_index` ADD INDEX `i_test`(`name`, `code`, `value`) USING BTREE;
Query OK, 0 rows affected (9.54 sec)
Records: 0 Duplicates: 0 Warnings: 0
删除组合索引
mysql> ALTER TABLE `xiuxian`.`test_multi_index` DROP INDEX `i_test`;
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
如何判别索引是否生效
通过mysql
的执行计划分析sql
语句,当 key
字段值为 i_test
即你创建的索引名称时,说明当前 sql
使用了组合索引。
mysql> desc
-> select * from test_multi_index where `name` like 'a%' and `code` like 'b%';
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------+
| 1 | SIMPLE | test_multi_index | NULL | range | i_test | i_test | 2044 | NULL | 44582 | 11.11 | Using index condition |
+----+-------------+------------------+------------+-------+---------------+--------+---------+------+-------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)
mysql> desc
-> select * from test_multi_index where `code` like 'b%';
+----+-------------+------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| 1 | SIMPLE | test_multi_index | NULL | ALL | NULL | NULL | NULL | NULL | 623523 | 11.11 | Using where |
+----+-------------+------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
性能对比
mysql> select * from test_multi_index where `name` like 'a%' and `code` like 'b%';
+--------+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+
| id | name | code | value | desc | c1 | c2 | c3 | c4 |
+--------+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+
| 142627 | a00sr37rcgaVwDQ2ADPFMVXzqXqjLmpIUNNcBsnE6nxyerDOMf | bfO5wEfO7UKGEju1FkVU | t7V4CnCkgGOH3v3jNybpoRrNJjMeO7Y68reLBGf53QaHwOKdQg | DUwPlLHOxr8VtJ5R24TXWN4OsUCIma9IT62lkUrpHTkD58M5bf | TlCnUXFYda6KJIsSs6SfpcHK3DcUjxdGOgnCMts8Qupj7yJnFo | SvJK7sT7Z9rbVqUIJ7UpeubCfwcLHqBBonHWUxkssk2Nk3vQdY | NULL | tX0mW4jw7vvzfdABnwPqMq68DqZsa8Acxqq9iDYXotJU19YqD8 |
+--------+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+
692 rows in set (2.26 sec)
mysql> ALTER TABLE `test_multi_index` ADD INDEX `i_test`(`name`, `code`, `value`) USING BTREE;
Query OK, 0 rows affected (7.88 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> select * from test_multi_index where `name` like 'a%' and `code` like 'b%';
+--------+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+
| id | name | code | value | desc | c1 | c2 | c3 | c4 |
+--------+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+
| 142627 | a00sr37rcgaVwDQ2ADPFMVXzqXqjLmpIUNNcBsnE6nxyerDOMf | bfO5wEfO7UKGEju1FkVU | t7V4CnCkgGOH3v3jNybpoRrNJjMeO7Y68reLBGf53QaHwOKdQg | DUwPlLHOxr8VtJ5R24TXWN4OsUCIma9IT62lkUrpHTkD58M5bf | TlCnUXFYda6KJIsSs6SfpcHK3DcUjxdGOgnCMts8Qupj7yJnFo | SvJK7sT7Z9rbVqUIJ7UpeubCfwcLHqBBonHWUxkssk2Nk3vQdY | NULL | tX0mW4jw7vvzfdABnwPqMq68DqZsa8Acxqq9iDYXotJU19YqD8 |
+--------+----------------------------------------------------+----------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+----------------------------------------------------+------+----------------------------------------------------+
692 rows in set (0.42 sec)
可以很明显的看出,有索引查询耗费时间 0.42s
没有使用索引消耗时间 2.26s
时间相差5倍多。当数据量越来越大,这个差异会更加明显。
本文作者:nonsenseLive
本文链接:https://www.cnblogs.com/venchi/articles/16470917.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步