到这一篇文章,我就已经默认你阅读完了前面的MySQL文章。你可能已经知道了索引本质就是一种数据结构,来加快查询效率的。可是索引要怎么设计呢?这就是这一篇文章的目的。web
网上有不少博客会讲到最佳实践,好比单表索引数不能超过5个,联合索引中的字段不能超过5个等等。我只能说这些都是扯淡,任何实践都要放在特定的场景才能生效,因此接下来咱们来聊聊索引设计吧。算法
索引本质上就是一种数据结构,然而咱们能够把索引映射到现实生活中,就比如是《深刻浅出MySQL》这本书前面的目录。难不成咱们说目录的章节不能超过5个吗?显然不能够的,在这么一个前提下,给一个索引增长一个上限值是不恰当的。因此涉及到慢查询的时候该加索引就加索引,不要给它们设置一个上限就行了。sql
可是咱们也不能在设计索引的时候滥用索引,在数据库表增长太多无用的索引也是会带来一些反作用的,好比DML语句会变得很慢。数据库
这条在绝大部分状况下是对的,可是也不彻底对。由于没有对应到场景上,因此不能说彻底对,下面咱们举例来讲明一下。数据结构
假如你设计了一个APP用来发送消息的模块,因为发送的消息太多,表中已经有1亿的数据量。为了提升发送消息的速度,领导要求你开发一个功能,给发送消息未成功的用户再尝试发送一次消息。svg
这样咱们就能够设计发送的状态status,这个status有三个值,0表明未发送,1表明已经发送,2表明发送失败。优化
相关的SQL语句以下:编码
select * from messages where status = 2;
正常状况下,你们都是发送成功的,发送失败的几率很是低。spa
而后咱们从数据库表中作一个统计:设计
select status, count(*) from messages group by status; | status | count(*) | | 0 | 1000 | | 1 | 99999000 | | 2 | 24 |
这种状况称之为数据的倾斜度高。
在这种状况下,咱们只须要查找status的值为2的状况便可,只要咱们不统计status=1的状况,就不用在高频字段加上索引。因此在这个场景下,给高频字段加索引是不对的。
咱们已经知道了SQL的执行计划(explain),那么SQL的执行顺序呢?是否是跟Java代码同样,按照编码的顺序来执行的,让咱们来看看吧。
在SQL语言中,执行顺序是按照一个固定的规则来执行的:
8、 SELECT 9、 DISTINCT <select_list> 1、 FROM <left_table> 3、 <join_type> JOIN <right_table> 2、 ON <join_condition> 4、 WHERE <where_condition> 5、 GROUP BY <group_by_list> 6、 WITH {CUBE|ROLLUP} 7、 HAVING <having_condition> 10、ORDER BY <order_by_condition> 11、LIMIT <limit_number>
从上面的规则得知,SQL执行顺序是11个步骤,最早执行的是FROM子句,最后执行的是LIMIT子句。
在SQL执行过程当中,每个步骤都会产生一个虚拟表(Virtual Table,简称VT),用来保存SQL的执行结果。下面分析一下SQL执行的整个过程:
所以,咱们在进行SQL调优时,要按照SQL语句执行的顺序进行优化,重点处理执行成本比较高的部分:
如今的关系型数据库,基本都使用了基于成本的优化器
如今估算成本的代价就是CPU代价+IO代价。在《数据库查询优化器的艺术》这本书讲到,MySQL数据库在有GROUP BY或者ORDER BY的操做下,没有索引的状况下会先走WHERE而后走GROUP BY和ORDER BY。反过来就是有索引的状况下,查询优化器会先走GROUP BY和ORDER BY再走WHERE。
由于数据库优化器会认为GROUP BY和ORDER BY不走索引的代价会大于WHERE不走索引的代价,因此在有索引的状况下,优化器会先优化给GROUP BY和ORDER BY走索引操做。
再深刻的知识就要等大家本身去看书才能慢慢理解到了。