对mysql优化的总结暂时主要从以下三个方面进行:
一 索引的总结
二explain的总结
三 查询优化的总结
首先是索引:
1索引的基础
索引类似于书的目录一样,mysql通过索引找到的值得到数据表的地址,然后再去表中获取值,或者直接在索引中找到值。索引的结构,先讨论B+树(就是书上的B-树)结构的索引,关于B+树的结构,网上很多资料可以查询,总的来说就是,数据都是按顺序存储,从根节点到叶节点,数据是只存储在叶节点的,而每一个叶节点都包含指向下一个叶节点的指针。同时,如果存储引擎是InnoDB,除了指向下一个叶子节点的指针之外,还会包含指向主键索引的指针,因为在当前索引中还会存在一个主键值,通过这个主键可以指向主键索引,如果没有主键会自动选择唯一索引替代,如果依旧没有则隐式选择替代。InnoDB主键索引按照聚簇的方式进行索引(聚簇索引),将全部列的数据一起和主键索引放一起,无需回到数据表查找数据。因此索引查找顺序为从当前索引到主键,主键聚簇数据返回。如果存储引擎是MyISAM,除了指向下一个叶子节点的指针之外,当前叶子会指向索引对应的数据表行(没有聚簇)。
2最左前缀原则
根据B+树的结构,如果当前存在联合索引(a,b,c),按照最左前缀原则,则可以使用到索引的组合为:(a)(a,b) (a,b,c) , 同时对于任何索引,like 'a%'这样的格式是可以匹配索引。联合索引可以匹配范围值,但是范围值之后的内容是不会使用索引的,这里指的是,联合索引比如a使用了范围值,则b和c不会被使用到。不是说where条件里面的位置处于范围之后的列不会使用索引,这是不对的,因为mysql优化器会对 顺序进行自动的调整,这和结构有关。如果要实现a,c这样的调用可以使用索引的话,可以对b进行常量补充,也就是说填坑。如果使用以什么结尾的,这样的类型是不会使用索引的。
3索引的优点
既然使用索引,当然会有优点。主要有三:
(1)索引可以大大减少了服务器需要扫描的数据量
(2)索引可以帮助服务器避免排序和临时表,特别在orderby和groupby的时候
(3)索引可以将随机的I/O变为顺序的I/O
4如何正确创建和使用高性能的索引
当然不是说使用索引一定是正确的,对于小型的表来说,全表扫描有的时候反而比索引更快,对于中大型的表来说,索引是可以提高效率,对于特大的表来说,可以使用分区(填坑)、
(1)独立的列
独立的列是指索引列不能是表达式的一部分,也不能是函数的参数,这种情况下索引是使用不到的。
(2)索引的选择性(选择比)
索引的选择性=不重复的索引值/数据表的记录总数。
所以索引的选择性分布在0到1之间。其实就是说索引建立的辛辛苦苦,那么就要让他有用到的地方,不然,比如选择性趋近为0的时候。这个时候建立那么多索引,但是实际上呢,根本不需要索引,因为表中数据基本是一样的。这样是没有什么效果的。所以应该在选择性比较高的时候使用索引,这样可以过滤比较多的数据行,才能体现索引的价值。
这里的一个应用就是,对于文本的类型的字段建立前缀索引的时候就可以通过选择性的高低去判断多长的前缀是比较合适的(这里先埋坑,有空回来整理下什么字段类型需要建立前缀索引和选择性结合 的例子)。
注意:orderby和groupby是无法使用前缀索引进行排序的,同时覆盖索引也无法使用前缀索引(想想为什么?)
当然如果需要使用后缀索引的时候怎么办呢?比如现在有好多不同域的电子邮箱,我想找某一个域下的所有电子邮箱,那怎么办呢》??可以将字符串反转之后存储,然后建立前缀索引。
(3)索引合并
有那么多索引,那么会选择哪一个呢,如果在以前,那么会选择其中一个,但是mysql5之后有了索引的合并算法。可以同时使用多个索引。这是一种mysql内置的优化方法,但是并非意味一定优化,如果同时存在很多and的时候,那么,是不是改成联合索引更能提高速度呢,这个也是要考虑的地方。
(4)注意索引的顺序
在不考虑排序和分组的情况下(之后有单独对排序和分组进行分析),一般来说,对联合索引,是将选择性比较高的索引列放到前面,将选择性比较差的索引列放到后面。
你想啊,选择性比较高的列放前面,也就是说第一个索引列进行刷选的时候,留下的重复索引列数据行不多,也就是去除了大多数据,第二次索引的时候就在这不多的里面继续挑,所以呢。选择性高的索引列放前面,选择性可以自己先进行语句计算之后判断。
(5)聚簇索引
一般说的是在InnoDb下的主键聚簇(只是说一数据的存储方式啦),主键索引下聚簇了所有的数据。因此只要查询的时候,通过主键了(二级索引其实也是通过了主键),那么都可以不必回数据表查询。那么为什么要这样做呢。优点:
1)在索引中查找和在数据表中查找数据,肯定是索引比较快啊。
2)减少磁盘I/O
3)使用覆盖索引扫描的查询可以直接使用叶节点的主键值
当然,缺点也会有的:
1)如果数据都存在内存,那当然没有什么优势
2)插入的速度依赖于插入顺序,如果按照主键的顺序插入当然很合适也很快
3)当数据存储在不同的页的时候,那么,页分裂导致的存储不连续也许会导致聚簇索引的全表扫描变慢
4)因为二级索引是指向主键的,所以会有两次的b树的扫描
(6)覆盖索引
如果搜索的字段,被where里面使用到的索引包含着,或者搜索的字段是索引列而且where语句没有跟着条件,那么在使用索引刷选的时候就可以一起将要搜索的字段返回,这样就可以不用去数据表从新搜索,对于InnoDb来说,如果是二级索引可以避免重新指向主键进行二次扫描。覆盖索引可以很有效的提高查询速度。
!很容易把Extra列的using index和type列的index搞混,但是实际上,type列的index指的是这个查询对数据的访问方式,或者说是mysql对数据行的查找方式,手册称之为连接方式。而using index仅仅是说用了覆盖索引
(延迟关联解决索引不能覆盖问题)
select * from products join (select pro_id from products where actor='haha' and title like '%aa%') as b on products.pro_id=b.pro_id
延迟关联在有些情况下是效果反而更差(留坑以后填);
(7)使用索引来做排序
order by 和group by不到万不得已不要让他们使用临时表或者filesort文件排序,很费时间。最好的是可以进行索引排序(type出现index或者extra没有出现临时表和文件排序即可);
mysql可以同时使用一个索引,即满足排序,又用于查找行,因此,如果有可能,尽量让其实现这个效果。什么时候可以使用索引来排序呢:
对于联合索引,比如(a,b,c)
1 where条件的索引列和orderby索引列必须符合最左前缀的原则,比如where a=1 order by b,c,当然如果存在范围的时候,也是和最左前缀一样的原则,该失效4还是失效,比如where a=1,b>2 order by c这种情况是不能用索引排序的。(有一种特例就是where a》2 order by a,b这种情况可以使用索引排序)
2 orderby索引列要么都是升序要么都是降序,不存在顺序不同的索引列
单列索引
1orderby后面的索引列必须在where条件的索引列中,这样才能即用索引查询又用索引排序
2同样不允许存在不同的orderby顺序
(8)关于orderby和limit结合的优化
我们知道,当limit a,b的时候,如果a过分大的时候,我们会扫描很多无关的行这样大大地拖慢了速度。所以可以从下面三点优化:
1)找到a位置所在的主键的值,然后where语句定位上去
2)减小a值
3)延迟关联,即使用表内连接到limita,b下的主键上