对SQL语句进行性能分析
对SQL语句进行性能分析的目的是对性能较差的语句进行优化。
第一,SQL执行频率。我们需要弄清楚哪类语句性能较差、执行频次更高。主要优化的是查询select语句,如果表主要执行的语句是插入语句,实际上是没有必要对索引进行优化的。MySQL的客户端可以通过show [session|global] status命令查看当前数据库中不同增删改查语句的执行频次。
第二,慢查询日志。通过查询不同类型语句的执行频次,不能知道哪些select语句需要进行优化。慢查询日志记录了索引执行时间超过指定时间的索引SQL语句。MySQL的慢查询日志默认不开启,需要手动在配置文件中进行配置和设置参数。
第三,查看profile详情。慢查询日志无法记录一些其他需要优化的语句,可以使用show profiles命令,查看SQL语句的耗时情况。首先,我们需要查看have_profiling参数查看是否支持该功能,然后需要手工配置来开启该功能。show profiles命令可以显示各条语句的执行时间开销,找到其中需要优化的语句之后,可以使用show profile命令查看指定query_id的语句各个阶段的时间延迟(如优化、执行等阶段)。
第四,explain查看执行计划。在select语句前面加上explain关键字可以获取DBMS如何执行语句的各种信息,包括表如何连接、连接的顺序、使用的索引等等信息。
explain语句的输出包含多个字段,有不同的含义。:
-
id。表示查询中执行的子句或操作表的顺序,顺序为,值越大越先执行,相等时从上往下执行。
-
select_type。只是说明查询类型,常见的取值有SIMPLE(不使用连接或子查询的简单查询)、PRIMARY(主查询,外层查询)、SUBQUERY(子查询)等等。
-
type。表示连接类型,会反映性能优劣,由好到差依次为NULL、system、const、eq_ref、ref、range、index、all,显然我们应该尽量向前优化。NULL通常是语句不访问任何表,system是访问系统表,const是使用主键或唯一索引访问,ref是使用非唯一性的索引访问,index表示使用了索引但是仍遍历整个索引,all则表示全表扫描。
-
possible_key。可能使用的索引,可能有一个或多个。
-
key。实际执行使用的索引,如果没有使用任何索引,则为NULL。
-
key_len。使用的索引的字节数。
-
rows。MySQL认为需要执行查询的行数,并不总是准确的。
-
filtered。返回查询结果的行数占总共读取行数的百分比,显然是越大越好。
-
extra。额外的信息。
索引的使用
最左前缀原则
最左前缀原则是使用多列索引(联合索引)时需要遵循的一个原则,指的是查询从索引的最左列开始,且不跳过索引中的任何一列,如果跳过了某一列,索引将部分失效,也就是后面的字段上的索引会失效。
除此之外还有一个关于范围查询的原则:在联合索引中,如果出现范围查询(>号或<号),范围查询右侧的列索引会失效。要想规避这种情况,可以使用大于等于或小于等于符号,前提是需求允许的情况下。
索引何时失效
什么是索引失效?是指DBMS无法有效地利用已有的索引来加速查询的情况。索引失效时,查询操作的性能通常会下降。
-
不要在索引列上进行(函数)运算操作,否则索引会失效。
-
字符串类型的字段没加引号,索引会失效。(因为类型问题)
-
字符串模糊查询时,如果进行头部模糊匹配,索引会失效,但是如果只进行尾部模糊匹配,索引不会失效。
-
使用or连接的查询条件,只有两侧的字段都有索引时,索引才会生效。
-
如果DBMS评估使用索引比全表扫描还要慢,则不会使用索引。
使用SQL提示索引的使用
使用SQL提示是优化的一个重要手段,通过在SQL语句中人为加入提示来优化操作。使用SQL提示来优化索引的使用,有三种操作:提示使用某个索引;忽略某个索引;强制使用某个索引。
覆盖索引与回表查询
覆盖索引指的是,查询使用了索引,并且查询结果中需要返回的字段,在该索引中已经能够全部找到。因此,我们应该尽量使用覆盖索引。
如果没有使用覆盖索引,则查询在使用了索引之后,仍然需要回表查询数据,性能会降低。
上图中,第一个查询语句可以直接通过聚集索引得到结果,第二个查询语句需要使用name字段上的二级索引得到结果,第三个语句由于需要查询的字段中存在一个不再索引中,因此需要进行回表查询。
前缀索引
当字段类型为字符串(比如varchar、text等)时,有时需要索引很长的字符串,这会导致索引变得很大,查询时,会浪费大量磁盘IO,影响效率。要解决这个问题,可以只将字符串的一部分前缀建立索引,可以大大节约索引空间,从而提高索引效率。
建立前缀索引时,需要指定前缀长度。最好的前缀长度可以根据索引的选择性来决定,选择性是指不重复的索引值数目和表的记录总数比值,索引选择性数值越高(唯一索引的选择性为1,性能最好)则查询效率越高。
单列索引与联合索引
在业务场景中,如果存在多个查询条件,建议建立联合索引,而非单列索引。
索引的设计原则
-
针对于数据量较大, 且查询比较频繁的表建立索引。
-
针对于常作为查询条件 (where)、排序(order by)、分组(group by)操作的字段建立索引。
-
尽量选择区分度高的列作为索引, 尽量建立唯-索引,区分度越高,使用索引的效率越高。
-
如果是字符串类型的字段, 字段的长度较长,可以针对于字段的特点,建立前缀索引。
-
尽量使用联合索引, 减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
-
要控制索引的数量, 索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
-
如果索引列不能存储NULL值, 应该在创建表时使用NOT NULL约東它。当优化器知道每列是香包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。