文章目录
- 1. 索引的使用
- 1.1 避免索引失效
- 1.1.1 全值匹配,对索引中所有列都指定具体值。
- 1.1.2 最左前缀法则
- 1.1.3 范围查询右边的列,不能使用索引。
- 1.1.4 不要在索引列上进行运算操作,索引将失效
- 1.1.5 字符串不加单引号,造成索引失效
- 1.1.6 尽量使用覆盖索引,避免select *
- 1.1.7 in走索引,not in索引失效
- 1.1.7 用or分隔开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
- 1.1.8 以%开头的Like模糊查询,索引失效。
- 1.1.9 如果MySQL评估使用索引比全表更慢,则不使用索引。
- 1.1.10 is NULL ,is NOT NULL有时索引失效
- 1.1.11 in走索引,not in索引失效
- 1.1.12 单列索引和复合索引
- 1.3查看索引使用情况
- 2.SQL优化
1. 索引的使用
索引是数据库优化最常用也是最重要的手段之一,通过索引通常可以帮助用户解决大多数的MySQL的性能优化问题。
1.1 避免索引失效
1.1.1 全值匹配,对索引中所有列都指定具体值。
该情况下,索引生效,执行效率高。
1.1.2 最左前缀法则
如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始,并且不跳过索引中的列。
匹配最左前缀法则,走索引
1.1.3 范围查询右边的列,不能使用索引。
根据前面的两个字段name,status查询是走索引的,但是最后一个条件address没有用到索引。
1.1.4 不要在索引列上进行运算操作,索引将失效
1.1.5 字符串不加单引号,造成索引失效
由于在查询时,没有对字符串加单引号,MySQL的查询优化器,会自动的进行类型转换,造成索引失效。
1.1.6 尽量使用覆盖索引,避免select *
尽量使用覆盖索引(只访问索引的查询(索引列完全包含查询列)),减少select *
如果查询列,超出索引列,也会降低性能。
using index:使用覆盖索引的时候就会出现
using where:在查找使用索引的情况下,需要回表去查询所需的数量
using index condition:查找使用了索引,但是需要回表查询数据
using index;using where :查找使用了索引,但是需要的数据都在索引中能找到,所以不需要回表查询数据
1.1.7 in走索引,not in索引失效
1.1.7 用or分隔开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
1.1.8 以%开头的Like模糊查询,索引失效。
如果仅仅是尾部模糊匹配,索引不会失效,如果是头部模糊匹配,索引失效。
解决方案:使用覆盖索引
1.1.9 如果MySQL评估使用索引比全表更慢,则不使用索引。
1.1.10 is NULL ,is NOT NULL有时索引失效
1.1.11 in走索引,not in索引失效
1.1.12 单列索引和复合索引
尽量使用复合索引,而少使用单列索引。
创建符合索引
create index idx_name_sta_address on tb_seller(name,status,address);
相当于创建了三个索引:
name
name + status
name + status + address
创建单列索引
create index idx_seller_name on tb_seller(name);
create index idx_seller_status on tb_seller(status);
create index idx_seller_address on tb_seller(address);
数据库会选择一个最优的索引(辨识度最高
)来使用,并不会使用全部索引。
1.3查看索引使用情况
查看的是当前会话的索引使用情况
show status like ‘Handler_read%’;
查看全局的索引使用情况
show global status like ‘Handler_read%’;
2.SQL优化
2.1 大批量插入数据
当使用load命令导入数据的时候,适当的设置可以提高导入的效率
对于InnoDB类型的表,有以下几种方式可以提高导入的效率:
(1)主键顺序插入
因为InnoDB类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。如果InnoDB表没有主键,那么系统会自动默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这点,来提高导入数据的效率。
(2)关闭唯一性校验
在导入数据前执行set unique_ckecks=0,关闭唯一性校验,在导入结束后执行
set unique_checks=1,恢复唯一性校验,可以提高导入的效率。
(3)手动提交事务
如果应用使用自动提交的方式,建议在导入前执行set autocommit=0,关闭自动提交,导入结束后再执行set autocommit=1,打开自动提交,也可以提高导入的效率。
2.2 优化insert语句
当进行数据的insert操作的时候,可以考虑采用以下几种优化方案。
2.2.1
如果需要同时对一张表插入很多行数据时,应该尽量使用多个值表的insert语句,这种方式将大大的缩减客户端与数据库之间的连接、关闭等消耗,使得效率比分开执行的单个insert语句快。
优化前:
insert into 表 values(1,‘Tom’);
insert into 表 values(2,‘Cat’);
insert into 表 values(3,‘Jerry’);
优化后:
insert into 表 values(1,‘Tom’),(2,‘Cat’),(3,‘Jerry’);
2.2.2 在事务中进行数据插入
注意:如果数据量比较大,建议每隔几 句就执行一次commit
start transaction;
insert into 表 values(1,‘Tom’);
insert into 表 values(2,‘Cat’);
insert into 表 values(3,‘Jerry’);
commit;
2.2.3 数据有序插入
优化前:
insert into 表 values(4,‘Tim’);
insert into 表 values(1,‘Tom’);
insert into 表 values(3,‘Jerry’);
insert into 表 values(5,‘Rose’);
insert into 表 values(2,‘Cat’);
优化后:
insert into 表 values(1,‘Tom’);
insert into 表 values(2,‘Cat’);
insert into 表 values(3,‘Jerry’);
insert into 表 values(4,‘Tim’);
insert into 表 values(5,‘Rose’);
2.3 优化order by 语句
2.3.1 两种排序方式
(1)FileSort
第一种是通过对返回数据进行排序,也就是通常说的filesort排序,所有不是通过索引直接返回排序结果的排序豆角FileSort排序
(2)Using index
第二种通过有序索引顺序扫描直接返回有序数据,这种情况即为using index,不需要额外排序,操作效率高。
多字段排序
(1)要么统一升序,要么统一降序
(2)排序顺序需要和索引顺序保持一致
优化目标:尽量减少额外的排序,通过索引直接返回有序数据。where条件和Order by使用相同的索引,并且Order By的顺序和索引顺序相同,并且Order by的字段都是升序,或者都是降序。否则肯定需要额外的操作,这样就会出现FileSort
2.3.2 FileSort的优化
通过创建合适的索引,能够减少FileSort的出现,但是在某些情况下,条件限制不能让FileSort消失,那就需要加快FileSort的排序操作。对于Filesort,MySQL有两种排序算法:
(1)两次扫描算法:MySQL4.1之前,使用该方式排序。首先根据条件取出排序字段和行指针信息,然后在排序区sort buffer中排序,如果sort buffer不够,则在临时表temporary table中存储排序结果。完成排序之后,再根据行指针回表读取记录,该操作可能会导致大量随机I/O操作。
(2)一次扫描算法:一次性取出满足条件的所有字段,然后在排序区sort buffer中排序后直接输出结果集。排序时内存开销较大,但是排序效率比两次扫描算法要高。
MySQL通过比较系统变量max_length_for_sort_data的大小和Query语句取出的字段总大小,来判定是哪种排序算法,如果max_length_for_sort_data更大,那么使用第二种优化之后的算法;否则使用第一种
可以适当提高sort_buffer_size和max_length_for_sort_data系统变量,来增大排序区的大小,提高排序的效率。
show variables like ‘max_length_for_sort_data’;
show variables like ‘sort_buffer_size’;
2.4 优化group by 语句
由于GROUP BY实际上也同样会进行排序操作,而且与ORDER BY相比,GROUP BY主要只是多了排序之后的分组操作。当然,如果在分组的时候还使用了其他的一些聚合函数,那么还需要一些聚合函数的计算。所以,在GROUP BY的实现过程中,与ORDER BY一样也可以利用到索引。
如果查询包含group by 但是用户想要避免排序结果的消耗,则可以执行order by null禁止排序
优化前
explain select age,count(*) from emp group by age;
优化后
explain select age,count(*) from emp group by age order by null;
2.5优化嵌套查询
MySQL4.1版本之后,开始支持SQL的子查询。这个技术可以使用select语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。使用子查询可以一次性的完成很多逻辑上需要很多个步骤才能完成的SQL操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子查询是可以被更高效的连接(JOIN)替代。
2.6优化OR条件
对于包含OR的查询子句,如果要利用索引,则OR之间的每个条件都必须用到索引,而且不能使用到复合索引;如果没有索引,则应该考虑增加索引。
建议使用union(求并集的操作)替换or
优化前
select * from emp where id = 1 or age = 10;
优化后
select * from emp where id = 1 union select * from emp where age = 10;
type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:
system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL
UNION语句的type值为ref,OR语句的type值为range,可以看到这是一个很明显的差距
UNION语句的ref值为const,OR语句的type值为null,const表示是常量值引用,非常快
2.7优化分页查询
一般分页查询时,通过创建覆盖索引能够比较好地提高性能。一个常见又非常头疼的问题就是limit 2000000,10 。此时需要MySQL排序前2000010记录,仅仅返回2000000 - 2000010的记录,其他记录丢弃,查询排序的代价非常大
未优化 select * from 表 limit 2000000,10;
2.7.1 优化思路一
在索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容
优化后
select * from tb_item t ,(select id from tb_item order by id limit 2000000,10) a where t.id = a.id;
2.7.2 优化思路二
该方案适用于主键自增的表,可以把limit查询转换成某个位置的查询
select * from tb_item where id> 2000000 limit 10
2.8使用SQL提示
SQL提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。
2.8.1 USE INDEX
在查询语句中表名的后面,添加use index来提供希望MySQL去参考的索引列表,就可以让MySQL不再考虑其他可用的索引。
2.8.2 IGNORE INDEX
如果用户只是单纯的想让MySQL忽略一个或者多个索引,则可以使用ignore index作为