CREATE TABLE IF NOT EXISTS `article` (
`id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`author_id` INT(10) UNSIGNED NOT NULL,
`category_id` INT(10) UNSIGNED NOT NULL,
`views` INT(10) UNSIGNED NOT NULL,
`comments` INT(10) UNSIGNED NOT NULL,
`title` VARBINARY(255) NOT NULL,
`content` TEXT NOT NULL
);
INSERT INTO `article`(`author_id`, `category_id`, `views`, `comments`, `title`, `content`) VALUES
(1, 1, 1, 1, '1', '1'),
(2, 2, 2, 2, '2', '2'),
(1, 1, 3, 3, '3', '3');
SELECT * FROM article;
查询 category_id 为1 且 comments 等于 1 的情况下,views 等于1 article_id
EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND comments =1 AND views = 1;
查询的执行结果为
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | article | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
我们可以看到他的执行计划,type为all,也就是全表扫描
这个时候我们新建一个索引
CREATE INDEX idx_article_ccv ON article(category_id,comments,views);
再次执行
EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND comments =1 AND views = 1;
执行计划为
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------------------+------+----------+-------+
| 1 | SIMPLE | article | NULL | ref | idx_article_ccv | idx_article_ccv | 12 | const,const,const | 1 | 100.00 | NULL |
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------------------+------+----------+-------+
我们可以看到这次的type是ref,走的索引为idx_article_ccv
,也就是我们刚刚新建的索引,索引的长度为 12
我们把执行的sql改为
EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND views = 1 AND comments =1 ;
我们可以发现他的执行计划一点没有变,也就是说与and的顺序无关
我们去掉查询字段views,执行sql语句
EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND comments =1;
执行计划如下
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------------+------+----------+-------+
| 1 | SIMPLE | article | NULL | ref | idx_article_ccv | idx_article_ccv | 8 | const,const | 1 | 100.00 | NULL |
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------------+------+----------+-------+
我们可以看到结果key_len变成了8,没有全部走索引的列,能得出view的key_len为4
EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 ;
执行计划为
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | article | NULL | ref | idx_article_ccv | idx_article_ccv | 4 | const | 2 | 100.00 | NULL |
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
我们会发现他的key_len变成了4,也就是说能得出view的key_len为4,comments的key_len为4,category_id key_len也为4
上面的查询完全根据最左前缀,没有跳过索引中的列
以例题一为基础,我们跳过一个索引列,
跳过comments
的这个列进行查询
EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND views = 1;
执行计划如下
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------+------+----------+-----------------------+
| 1 | SIMPLE | article | NULL | ref | idx_article_ccv | idx_article_ccv | 4 | const | 2 | 33.33 | Using index condition |
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------+------+----------+-----------------------+
我们会发现他的key_len为4,也就是说只走了最左列的category_id 这个索引列
跳过category_id
查询,我们运行下面的sql
EXPLAIN SELECT id,author_id FROM article WHERE comments =1 AND views = 1;
执行计划为
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | article | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
我们会发现他完全再走全表扫描
范围查询,以例题一为基础,查询comments大于1的
EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND views = 1 AND comments > 1 ;
执行计划如下
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | article | NULL | range | idx_article_ccv | idx_article_ccv | 8 | NULL | 1 | 33.33 | Using index condition |
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+-----------------------+
我们会发现他的key_len为8,views的索引列失效了,这个范围查询导致了索引的失效,但是我们只要把>加上一个等号,就会发现views索引可以使用了
EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND views = 1 AND comments >= 1
执行计划如下
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | article | NULL | range | idx_article_ccv | idx_article_ccv | 12 | NULL | 2 | 33.33 | Using index condition |
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+-----------------------+
数据库中的索引是以Btree来进行存放的,其特点是定位高效、利用率高、自我平衡,特别适用于高基数字段,定位单条或小范围数据非常高效。
理论上,使用Btree在亿条数据与100条数据中定位记录的花销相同。
如下为插入数据的过程