建表
create table 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,
titles varchar(255) not null,
content text not null
);
插入数据
insert into article (`author_id`, `category_id`, `views`, `comments`, `titles`, `content`) values('1', '1', '1', '1', '1', '1'),('2', '2', '2', '2', '2', '2'),('1', '1', '3', '3', '3', '3');
+----+-----------+-------------+-------+----------+--------+---------+
| id | author_id | category_id | views | comments | titles | content |
+----+-----------+-------------+-------+----------+--------+---------+
| 3 | 1 | 1 | 1 | 1 | 1 | 1 |
| 4 | 2 | 2 | 2 | 2 | 2 | 2 |
| 5 | 1 | 1 | 3 | 3 | 3 | 3 |
+----+-----------+-------------+-------+----------+--------+---------+
3 rows in set (0.00 sec)
案例分析
- 查询出category_id为1 且comments大于1 的情况下views最多的zrticle
select id,author_id from article where category_id=1 and comments>1 order by views limit 1;
+----+-----------+
| id | author_id |
+----+-----------+
| 5 | 1 |
+----+-----------+
我们通过之前学习的explain 来分析一下
mysql> explain select id,author_id from article where category_id=1 and comments>1 order by views limit 1;
+----+-------------+---------+------+---------------+------+---------+------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-----------------------------+
| 1 | SIMPLE | article | ALL | NULL | NULL | NULL | NULL | 3 | Using where; Using filesort |
+----+-------------+---------+------+---------------+------+---------+------+------+-----------------------------+
1 row in set (0.02 sec)
改善:
1.我们发现 type为ALL 说明使用了全表扫描 这样就非常的不好我们查询一下索引
mysql> show index from article;
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| article | 0 | PRIMARY | 1 | id | A | 3 | NULL | NULL | | BTREE | | |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
我们看以看到只有一个主键,所以我们要新建索引,我们在where 后面的条件字段建立符合索引
create index idx_article_ccv on article(category_id,comments,views);
mysql> show index from article;
+---------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| article | 0 | PRIMARY | 1 | id | A | 3 | NULL | NULL | | BTREE | | |
| article | 1 | idx_article_ccv | 1 | category_id | A | 3 | NULL | NULL | | BTREE | | |
| article | 1 | idx_article_ccv | 2 | comments | A | 3 | NULL | NULL | | BTREE | | |
| article | 1 | idx_article_ccv | 3 | views | A | 3 | NULL | NULL | | BTREE | | |
+---------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (0.00 sec)
可以看到我们成功的建立了索引,所以我们在查询一次
mysql> explain select id,author_id from article where category_id=1 and comments>1 order by views limit 1;
+----+-------------+---------+-------+-----------------+-----------------+---------+------+------+---------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+-----------------+-----------------+---------+------+------+---------------------------------------+
| 1 | SIMPLE | article | range | idx_article_ccv | idx_article_ccv | 8 | NULL | 1 | Using index condition; Using filesort |
+----+-------------+---------+-------+-----------------+-----------------+---------+------+------+---------------------------------------+
1 row in set (0.00 sec)
观察我们的key 说明我们已经用到了索引,再看type已经变成了range,但是我们看extra出现了"文件排序" 之后我们会学习 order by 索引失效的问题 这样就说明了我们建立的索引不是很合适
删除我们的索引
mysql> drop index idx_article_ccv on article;
Query OK, 0 rows affected (0.11 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain select id,author_id from article where category_id=1 and comments>1 order by views limit 1;
+----+-------------+---------+------+---------------+------+---------+------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-----------------------------+
| 1 | SIMPLE | article | ALL | NULL | NULL | NULL | NULL | 3 | Using where; Using filesort |
+----+-------------+---------+------+---------------+------+---------+------+------+-----------------------------+
1 row in set (0.00 sec)
我们发现type 又变成了全表扫描,也证明我们成功的删除了索引
结论
type变成了range是可以忍受的,但是extra里使用Using fukesort 文件排序是无法接受的,但是我们已经建立了索引.为什么会出现索引失效呢?
先看BTree工作原理:
我们先排序category_id索引,在进行查找当我们找到了category_id=1时
我们在排序comments 在进行查找符合的值,但**该条件是一个范围值(所谓的range)**也就造成了后面的views索引无法在进行检索.
重点:即range类型查询字段的索引无效
所以我们吸取上面的教训,再次建立索引,不在建立comments索引,绕过它去.
mysql> create index idx_article_cv on article(category_id,views);
Query OK, 0 rows affected (0.39 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show index from article;
+---------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| article | 0 | PRIMARY | 1 | id | A | 3 | NULL | NULL | | BTREE | | |
| article | 1 | idx_article_cv | 1 | category_id | A | 3 | NULL | NULL | | BTREE | | |
| article | 1 | idx_article_cv | 2 | views | A | 3 | NULL | NULL | | BTREE | | |
+---------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
我们在运行一下 explain
mysql> explain select id,author_id from article where category_id=1 and comments>1 order by views limit 1;
+----+-------------+---------+------+----------------+----------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+----------------+----------------+---------+-------+------+-------------+
| 1 | SIMPLE | article | ref | idx_article_cv | idx_article_cv | 4 | const | 2 | Using where |
+----+-------------+---------+------+----------------+----------------+---------+-------+------+-------------+
1 row in set (0.02 sec)
大功告成
哈哈 我们type不仅变成了ref 也没有了文件排序