SQL索引在数据库优化中占有一个很是大的比例, 一个好的索引的设计,可让你的效率提升几十甚至几百倍,在这里将带你一步步揭开他的神秘面纱。mysql
1.1 什么是索引?web
SQL索引有两种,汇集索引和非汇集索引,索引主要目的是提升了SQL Server系统的性能,加快数据的查询速度与减小系统的响应时间 sql
下面举两个简单的例子:数据库
图书馆的例子:一个图书馆那么多书,怎么管理呢?创建一个字母开头的目录,例如:a开头的书,在第一排,b开头的在第二排,这样在找什么书就好说了,这个就是一个汇集索引,但是不少人借书找某某做者的,不知道书名怎么办?图书管理员在写一个目录,某某做者的书分别在第几排,第几排,这就是一个非汇集索引api
字典的例子:字典前面的目录,能够按照拼音和部首去查询,咱们想查询一个字,只须要根据拼音或者部首去查询,就能够快速的定位到这个汉字了,这个就是索引的好处,拼音查询法就是汇集索引,部首查询就是一个非汇集索引.性能优化
看了上面的例子,下面的一句话你们就很容易理解了:网络
1.2 索引的存储机制app
首先,无索引的表,查询时,是按照顺序存续的方法扫描每一个记录来查找符合条件的记录,这样效率十分低下,举个例子,若是咱们将字典的汉字随即打乱,没有前面的按照拼音或者部首查询,那么咱们想找一个字,按照顺序的方式去一页页的找,这样效率有多底,你们能够想象。数据库设计
汇集索引和非汇集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致,其实理解起来很是简单,仍是举字典的例子:若是按照拼音查询,那么都是从a-z的,是具备连续性的,a后面就是b,b后面就是c, 汇集索引就是这样的,他是和表的物理排列顺序是同样的,例若有id为汇集索引,那么1后面确定是2,2后面确定是3,因此说这样的搜索顺序的就是汇集索引。ide
非汇集索引就和按照部首查询是同样是,可能按照偏房查询的时候,根据偏旁‘弓’字旁,索引出两个汉字,张和弘,可是这两个其实一个在100页,一个在1000页,(这里只是举个例子),他们的索引顺序和数据库表的排列顺序是不同的,这个样的就是非汇集索引。
原理明白了,那他们是怎么存储的呢?在这里简单的说一下,汇集索引就是在数据库被开辟一个物理空间存放他的排列的值,例如1-100,因此当插入数据时,他会从新排列整个整个物理空间,而非汇集索引其实能够看做是一个含有汇集索引的表,他只仅包含原表中非汇集索引的列和指向实际物理表的指针。他只记录一个指针,其实就有点和堆栈差很少的感受了
1.3 什么状况下设置索引
1) 定义主键的数据列必定要创建索引。
2) 定义有外键的数据列必定要创建索引。
3) 对于常常查询的数据列最好创建索引。
4) 对于须要在指定范围内的快速或频繁查询的数据列;
5) 常常用在WHERE子句中的数据列。
6) 常常出如今关键字order by、group by、distinct后面的字段,创建索引。若是创建的是复合索引,索引的字段顺序要和这些关键字后面的字段顺序一致,不然索引不会被使用。
7) 对于那些查询中不多涉及的列,重复值比较多的列不要创建索引。
8) 对于定义为text、image和bit的数据类型的列不要创建索引。
9) 对于常常存取的列避免创建索引
9) 限制表上的索引数目。对一个存在大量更新操做的表,所建索引的数目通常不要超过3个,最多不要超过5个。索引虽然说提升了访问速度,但太多索引会影响数据的更新操做。
10) 对复合索引,按照字段在查询条件中出现的频度创建索引。在复合索引中,记录首先按照第一个字段排序。对于在第一个字段上取值相同的记录,系统再按照第二个字段的取值排序,以此类推。所以只有复合索引的第一个字段出如今查询条件中,该索引才可能被使用,所以将应用频度高的字段,放置在复合索引的前面,会使系统最大可能地使用此索引,发挥索引的做用。
上面都在说使用索引的好处,但过多的使用索引将会形成滥用。所以索引也会有它的缺点:
使用索引时,有如下一些技巧和注意事项:
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。因此咱们在数据库设计时不要让字段的默认值为NULL。
对串列进行索引,若是可能应该指定一个前缀长度。例如,若是有一个CHAR(255)的列,若是在前10个或20个字符内,多数值是唯一的,那么就不要对整个列进行索引。短索引不只能够提升查询速度并且能够节省磁盘空间和I/O操做。
MySQL查询只使用一个索引,所以若是where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。所以数据库默认排序能够符合要求的状况下不要使用排序操做;尽可能不要包含多个列的排序,若是须要最好给这些列建立复合索引。
通常状况下不鼓励使用like操做,若是非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引,而like “aaa%”可使用索引。
将在每一个行上进行运算,这将致使索引失效而进行全表扫描,所以咱们能够改为
1.4 如何建立索引
1.41 建立索引的语法:
1.42 删除索引语法:
1.43 显示索引信息:
使用系统存储过程:sp_helpindex 查看指定表的索引信息。
执行代码以下:
1.44查询索引(都可)
1.44组合索引
不少时候,咱们在mysql中建立了索引,可是某些查询仍是很慢,根本就没有使用到索引!通常来讲,多是某些字段没有建立索引,或者是组合索引中字段的顺序与查询语句中字段的顺序不符。
看下面的例子:
假设有一张订单表(orders),包含order_id和product_id二个字段。
一共有31条数据。符合下面语句的数据有5条。执行下面的sql语句:
这条语句要mysql去根据order_id进行搜索,而后返回匹配记录中的product_id。因此组合索引应该按照如下的顺序建立:
为何要建立组合索引呢?这么简单的状况直接建立一个order_id的索引不就好了吗?果只有一个order_id索引,没什么问题,会用到这个索引,而后mysql要去磁盘上的表里面取到product_id。若是有组合索引的话,mysql能够彻底从索引中取到product_id,速度天然会快。再多说几句组合索引的最左优先原则:
组合索引的第一个字段必须出如今查询组句中,这个索引才会被用到。果有一个组合索引(col_a,col_b,col_c),下面的状况都会用到这个索引:
经过实例理解单列索引、多列索引以及最左前缀原则。实例:如今咱们想查出知足如下条件的用户id:
由于咱们不想扫描整表,故考虑用索引。
1.单列索引:
将lname列建索引,这样就把范围限制在lname='Liu'的结果集1上,以后扫描结果集1,产生知足fname='Zhiqun'的结果集2,再扫描结果集2,找到 age=26的结果集3,即最终结果。
由 于创建了lname列的索引,与执行表的彻底扫描相比,效率提升了不少,但咱们要求扫描的记录数量仍旧远远超过了实际所需 要的。虽然咱们能够删除lname列上的索引,再建立fname或者age 列的索引,可是,不论在哪一个列上建立索引搜索效率仍旧类似。
2.多列索引:
为了提升搜索效率,咱们须要考虑运用多列索引,因为索引文件以B-Tree格式保存,因此咱们不用扫描任何记录,便可获得最终结果。
注:在mysql中执行查询时,只能使用一个索引,若是咱们在lname,fname,age上分别建索引,执行查询时,只能使用一个索引,mysql会选择一个最严格(得到结果集记录数最少)的索引。
3.最左前缀:顾名思义,就是最左优先,上例中咱们建立了lname_fname_age多列索引,至关于建立了(lname)单列索引,(lname,fname)组合索引以及(lname,fname,age)组合索引。
注:在建立多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。
创建索引的时机
到这里咱们已经学会了创建索引,那么咱们须要在什么状况下创建索引呢?通常来讲,在WHERE和JOIN中出现的列须要创建索引,但也不彻底如此,由于MySQL只对<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE才会使用索引。例如:
此时就须要对city和age创建索引,因为mytable表的userame也出如今了JOIN子句中,也有对它创建索引的必要。
刚才提到只有某些时候的LIKE才需创建索引。由于在以通配符%和_开头做查询时,MySQL不会使用索引。例以下句会使用索引:
下句就不会使用:
所以,在使用LIKE时应注意以上的区别。
1.5 索引实战(摘抄)
人们在使用SQL时每每会陷入一个误区,即太关注于所得的结果是否正确,而忽略了不一样的实现方法之间可能存在的性能差别,
这种性能差别在大型的或是复杂的数据库环境中(如联机事务处理OLTP或决策支持系统DSS)中表现得尤其明显。
笔者在工做实践中发现,不良的SQL每每来自于不恰当的索引设计、不充份的链接条件和不可优化的where子句。
在对它们进行适当的优化后,其运行速度有了明显地提升!
下面我将从这三个方面分别进行总结:
为了更直观地说明问题,全部实例中的SQL运行时间均通过测试,不超过1秒的均表示为(< 1秒)。
1、不合理的索引设计----
例:表record有620000行,试看在不一样的索引下,下面几个 SQL的运行状况:
---- 1.在date上建有一非个群集索引
---- 2.在date上的一个群集索引
---- 3.在place,date,amount上的组合索引
---- 4.在date,place,amount上的组合索引
---- 5.总结:----
缺省状况下创建的索引是非群集索引,但有时它并非最佳的;合理的索引设计要创建在对各类查询的分析和预测上。
通常来讲:
①.有大量重复值、且常常有范围查询(between, >,< ,>=,< =)和order by、group by发生的列,可考虑创建群集索引;
②.常常同时存取多列,且每列都含有重复值可考虑创建组合索引;
③.组合索引要尽可能使关键查询造成索引覆盖,其前导列必定是使用最频繁的列。
2、不充份的链接条件:
例:表card有7896行,在card_no上有一个非汇集索引,表account有191122行,在account_no上有一个非汇集索引,试看在不一样的表链接条件下,两个SQL的执行状况:
---- 分析:----
可见,只有充份的链接条件,真正的最佳方案才会被执行。
总结:
1.多表操做在被实际执行前,查询优化器会根据链接条件,列出几组可能的链接方案并从中找出系统开销最小的最佳方案。链接条件要充份考虑带有索引的表、行数多的表;内外表的选择可由公式:外层表中的匹配行数*内层表中每一次查找的次数肯定,乘积最小为最佳方案。
2.查看执行方案的方法-- 用set showplanon,打开showplan选项,就能够看到链接顺序、使用何种索引的信息;想看更详细的信息,需用sa角色执行dbcc(3604,310,302)。
3、不可优化的where子句
1.例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却很是慢:
你会发现SQL明显快起来!
2.例:表stuff有200000行,id_no上有非群集索引,请看下面这个SQL:
---- 总结:----
可见,所谓优化即where子句利用了索引,不可优化即发生了表扫描或额外开销。
1.任何对列的操做都将致使表扫描,它包括数据库函数、计算表达式等等,查询时要尽量将操做移至等号右边。
2.in、or子句常会使用工做表,使索引失效;若是不产生大量重复值,能够考虑把子句拆开;拆开的子句中应该包含索引。
3.要善于使用存储过程,它使SQL变得更加灵活和高效。
从以上这些例子能够看出,SQL优化的实质就是在结果正确的前提下,用优化器能够识别的语句,充份利用索引,减小表扫描的I/O次数,尽可能避免表搜索的发生。其实SQL的性能优化是一个复杂的过程,上述这些只是在应用层次的一种体现,深刻研究还会涉及数据库层的资源配置、网络层的流量控制以及操做系统层的整体设计。