小编导读:一、索引的利弊
二、索引使用原则
三、索引分析利器explain
四、引起索引失效的一些因素
在性能测试中遇到性能瓶颈最多的地方就是数据库这块,而数据库的问题大部分都是由于索引使用不当引起的,根据以往遇到的索引问题做个简单的总结:
一、索引的利弊
索引的好处:
索引能够极大地提高数据检索的效率,让Query 执行得更快,也能够改善排序分组操作的性能,在进行排序分组操作中利用好索引,将会极大地降低CPU资源的消耗。
索引的弊端:
1、更新数据库时会更新索引,这样,最明显的资源消耗就是增加了更新所带来的IO量和调整索引所致的计算量;
2、索引也会占用一定的存储空间,有些时候索引所占的空间有可能超过数据所占的空间。
二、索引使用原则
1、索引可以改善查询,但会减慢更新,索引不是越多越好,最好不超过字段数的20%(在数据增、删、改比较频繁的表中,索引数量不应超过5个)这一点已经在上面介绍过,这里就不做太多介绍。
2、离散程度越小,不适合加索引,例如:不要给性别建索引status这样字段建索引;
3、在数据量较少且访问频率不高的情况下,如只有一百行记录以下的表不需要建立索引。因为在数据量少的情况下,使用全表扫描效果比走索引更好,这就好比一本只有5页的书,如果我们想找其中一个章节,我们一般不会通过目录去寻找,而是直接去找了。
4、唯一索引:在建立索引的字段所有数值都具有唯一性特点的情况下,建立唯一索引(unique index)代替普通索引,唯一索引(unique index)查询效率比普通索引查询效率更高,可以大幅提升查询速度。
5、避免建立两个或以上功能相同索引。例如已经建立字段A、B两个字段的索引,应该避免再建立字段A的单独索引。两个索引之间,对相同的查询都会起到相同的作用。建立两个功能相同的索引,反而会容易引起数据库产生错误的查询计划,降低查询效率。
6、选择正确的组合索引字段顺序,最常用的查询字段和选择性、区分度较高的字段,应该作为索引的前导字段使用。假设存在组合索引it1(c1,c2),查询语句select * from t1 where c1=1 and c2=2能够使用该索引。查询语句select *from t1 where c1=1也能够使用该索引。但是,查询语句select * from t1 where c2=2不能够使用该索引,因为没有组合索引的引导列,即,要想使用c2列进行查找,必需出现c1等于某值,所以在在添加联合索引的时候尽量将常用的字段放到最前面。
7、合适的字段数,组合索引的字段数不适宜较多,较多的组合索引字段数会降低索引查询效率,组合索引字段数应不多于3个,除业务特点需要建立多字段的组合主键例外。
三、索引分析利器explain
在做性能测试的过程中经常遇到一些数据库的问题,通常使用慢查询日志可以找到执行效果比较差的sql,但是仅仅找到这些sql是不行的,我们需要协助开发人员分析问题所在,这就经常要用到explain。
explain显示了mysql如何使用索引来处理select语句以及连接表。可以帮助选择更好的索引和写出更优化的查询语句。
使用方法,在select语句前加上explain就可以了:
explain列的解释:
1、id:SELECT识别符。这是SELECT的查询序列号,若没有子查询和联合查询,id则都是1,并且Mysql会按照id从大到小的顺序执行query,在id相同的情况下,则从上到下执行。
2、table:显示这一行的数据是关于哪张表的。
3、type:这是重要的列,显示连接使用了何种类型。
1>system:表只有一行:system表。这是const连接类型的特殊情况
2>const:表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const表很快,因为它们只读取一次!(索引可以是主键或惟一索引)。
3>eq_ref:在连接中,MYSQL在查询时,从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或惟一键的全部时使用
4>ref:这个连接类型只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少(越少越好)。
5>range:这个连接类型使用索引返回一个范围中的行,比如使用>或
6>index:这个连接类型对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据)
7>ALL:这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免。
Explain的type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:
system > const > eq_ref > ref > range > index > ALL
4、possible_keys:显示可能应用这张表中的那个索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句。
5、key:实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USEINDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引。
6、key_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好。
7、ref:显示索引的哪一列被使用了,如果可能的话,是一个常数。
8、rows:MYSQL认为必须检查的用来返回请求数据的行数。
9、Extra:关于MYSQL如何解析查询的额外信息。
extra列返回值描述如下:Distinct:一旦MYSQL找到了与行相联合匹配的行,就不再搜索了
Not exists:MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了。
Range checked for each Record(index map:#):没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一。
Using filesort:看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行。
Using index: 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候
Using temporary:看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上。
Using where:使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题不同连接类型的解释;
四、引起索引失效的一些因素
1、like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%”不会使用索引而like “aaa%”可以使用索引。
例如:
2、在索引列上使用函数,或者对索引列进行运算,运算包括(,-,*,/,!等)会导致索引失效。
例如:
3、查询的数量是表的大部分,应该是30%以上。
例如:
4、字符型字段为数字时在where条件里不添加引号。
例如:
被测试数据库的表结构如下:
这是添加了引号的sql语句的执行计划:
这是没有添加引号的sql语句的执行计划: