- 单表索引优化案例
1)表结构
DROP TABLE IF EXISTS `article`; CREATE TABLE IF NOT EXISTS `article`( `id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '主键', `author_id` INT (10) UNSIGNED NOT NULL COMMENT '作者ID', `category_id` INT(10) UNSIGNED NOT NULL COMMENT '分类ID', `views` INT(10) UNSIGNED NOT NULL COMMENT '被查看次数', `comments` INT(10) UNSIGNED NOT NULL COMMENT '回帖的备注', `title` VARBINARY(255) NOT NULL COMMENT '文章主题', `content` TEXT NOT NULL COMMENT '文章内容' ); 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;
2)需求
查询category_id为1且comments大于1的情况下,views最多的article_d
3)开始使用的sql
SELECT id, author_id FROM article WHERE category_id = 1 and comments > 1 ORDER BY views DESC LIMIT 1;
4)使用explain查看sql的执行计划
可以发现type为ALL这个是全表扫描,而且在Extra中存在Using filesort这个也是最坏的情况,现在数据量小,后面一旦数据量上来,就会出现问题了,所以优化是必须的。
5)开始创建索引进行sql优化
a:根据where后面的条件创建组合索引
b:查看索引CREATE INDEX idx_article_ccv on article(category_id,comments,views);
6)再次执行sql计划看一下效果
通过执行计划我们发现key中使用到了我们刚刚建立的索引了,并且type也变成了range,解决了全表扫描的问题,但是Extra
中还是存在Using filesort问题,这个是为什么呢?
7)问题分析
因为上面我们建立的索引是三个字段category_id,comments,views。而条件1是category_id等于一个常量,那么我们使用
上了索引,而我们的第二个字段comments却是一个范围的条件,范围的条件会导致索引的失效,从而导致mysql内部产生一个
内部排序,最后导致后面的索引失效
8)解决办法
a:删除之前的索引
b:上面的问题是因为comments的条件是一个范围,从而导致后面的索引都失效了,那么我们现在可以将comments这个字段
的索引去掉,只留category_id和views两个字段的索引即可
c:最后看一下效果
可以发现不仅解决了Using filesort的问题,type也变成了ref级别,变得更快了。 - 双表索引优化案例
1)表结构
CREATE TABLE IF NOT EXISTS `class`( `id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', `card` INT (10) UNSIGNED NOT NULL COMMENT '分类card' ); CREATE TABLE IF NOT EXISTS `book`( `bookid` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', `card` INT (10) UNSIGNED NOT NULL COMMENT '分类card' ); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
2)需求
使用class表左连接book表关联查询
3)sql语句
SELECT * FROM class c left join book b on c.card = b.card
4)执行计划效果
我们发现出现了全表扫描的问题。
5)尝试先为book表的card字段添加索引试试
在看执行效果:
我们发现book表以及使用了索引,但是class表还是全表扫描。但是比上面的两个表都是全表扫描要好很多了。
6)我们再尝试将book的索引去掉,在class的card字段上加上索引试试。
查看执行结果:
可以发现type由ref变为了index,说明效果不如将索引加在book表的card字段上好,而且这个效果的rows两张表
都是20,效果比上面加在book表时的一个20,一个1的效果也要差。
这是为什么呢?
7)分析,为什么左连接时,索引加在右边的表比加在左边的表效果好呢?
这个是由左连接的特性决定的,left join 条件用于确定如何从右表搜索行,而左边一定都有。所以右边是我们的关键点,
右表一定要建立索引。所以我们还是要将当前的class表索引删掉,将book表的索引加上
8)所以目前我们将索引建立在book这个右表上的效果是
9)结论:
左连接时,索引建立在右表,右连接时索引建立在左表。
注意:上面的例子为什么不两张表都加上索引呢?因为这个是左连接,左表的表时查询所有数据,加不加没有意义。 - 三表索引优化案例
1)表结构是在上面两张表的基础上加上一张phone表
CREATE TABLE IF NOT EXISTS `phone`( `phoneid` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, `card` INT (10) UNSIGNED NOT NULL )ENGINE = INNODB; INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20))); INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
2) 需求sql
SELECT * FROM class c left join book b on c.card = b.card left join phone p on b.card = p.card;
3)建立索引,在后面book表以及phone表的关联字段上建立索引
4)执行sql计划,查看效果
可以发现后两行的type都是ref,且rows都优化的很好。
5)总结
mysql的索引使用的案例
最新推荐文章于 2024-05-30 09:50:34 发布