为什么要进行SQL调优?

        首先我们要理解一下为什么需要SQL调优,其实企业要求SQL调优最关键的就是,帮公司省钱,为什么这么说呢?我们看看这个比较

  • 优化成本:硬件>系统配置>数据库表结构>SQL及索引
  • 优化效果:硬件<系统配置<数据库表结构<SQL及索引

        所以我们可以看出如果SQL调的好,对整个系统的可用性是非大的提升。

五个原则

        SQL优化我们一般进行五个原则:

                1.减少数据访问:设置合理的字段类型,启用压缩,通过索引访问等减少磁盘IO,也可以将不重要的数据放在Redis中或MongoDB中进行分库存储。

                2.返回更少的数据:只返回需要的字段或进行对数据分页处理,以此来减少磁盘IO以及网络IO

                3.减少连接次数:对DML(通俗来说就是增删改查),以及函数存储进行批量操作通俗

                4.减少服务器CPU的开销:尽量减少数据库排序操作以及全表查询,减少CPU的内存占用

                5.利用更多的资源:使用表分区,可以增加并行操作,更大限度利用CPU资源。

        在我们理解SQL优化原理的时候,首先要搞清楚SQL的执行顺序:

   

关于SQL的优化策略

1.避免不走索引的情况

下面给出导致数据库引擎放弃索引,然后进行全表扫描的情况,以及其优化策略

1.尽量避免在字段开头走模糊查询

SELECT *
FROM user
WHERE username LIKE '%白%'
--->尽量在字段后面使用模糊查询。
SELECT *
FROM user
WHERE username LIKE '白%'

2.尽量避免使用in和not in

SELECT * 
FROM user 
WHERE id IN (2,3)
--->如果是连续数值,可以用between代替
SELECT * 
FROM user 
WHERE id BETWEEN 2 AND 3

如果是子查询,可以用exists代替。

-- 不走索引
select * from A where A.id in (select id from B);
-- 走索引
select * from A where exists (select * from B where B.id = A.id);

3.尽量避免使用or

SELECT * 
FROM t 
WHERE id = 1 OR id = 3
--->可以使用union代替or
SELECT * FROM t WHERE id = 1
    UNION
SELECT * FROM t WHERE id = 3

4.尽量避免对NULL进行判断

SELECT * 
FROM t
WHERE score IS NULL
--->可以给默认字段添加默认值0,对0进行判断
SELECT *
FROM t
WHERE score = 0

5.尽量避免在where条件中等号左侧,进行表达式或函数操作

--->全表扫描
SELECT * FROM T WHERE score/10 = 9
--->走索引
SELECT * FROM T WHERE score = 10*9

6. 当数据量大时,避免使用where 1=1的条件。通常为了方便拼装查询条件,我们会默认使用该条件。

SELECT 
    username, age, sex 
FROM T 
WHERE 1=1

        优化方式:用代码拼装sql时进行判断,没 where 条件就去掉 where,有where条件就加 and。

7. 查询条件不能用 <> 或者 !=

        使用索引列作为条件进行查询时,需要避免使用<>或者!=等判断条件。如确实业务需要,使用到不等于符号,需要在重新评估索引建立,避免在此字段上建立索引,改由查询条件中其他索引字段代替。

8. where条件仅包含复合索引非前置列

        如下:复合(联合)索引包含key_part1,key_part2,key_part3三列,但SQL语句没有包含索引前置列"key_part1",按照MySQL联合索引的最左匹配原则,不会走联合索引。

select col1 from table where key_part2=1 and key_part3=2

9. 隐式类型转换造成不使用索引 

                如下SQL语句由于索引对列类型为varchar,但给定的值为数值,涉及隐式类型转换,造成不能正确走索引。

select col1 from table where col_varchar=123;

10. order by 条件要与where中条件一致,否则order by不会利用索引进行排序

---> 不走age索引
SELECT * FROM t order by age;
 
---> 走age索引
SELECT * FROM t where age > 0 order by age;

        这段SQL正确的处理顺序是:

  • 根据WHERE条件和统计信息生成执行计划,得到数据。
  • 当执行order by时,数据库会先查看第一步的执行计划,看order by的字段是否在执行计划中利用了索引。如果是,则可以利用索引顺序而直接取得已经排序好的数据。反之重新排序操作。
  • 返回排序后的结果

        只有在order by(或group by,union等)中的字段出现在where条件中时,才会利用索引,而不使用二次排序。

二.关于SELECT语句的优化

1.避免出现select*

这个大家都见怪不怪了,那么为什么要避免select*呢?这里分三个小点展开:

  • 不需要的列会增加数据传输时间以及网络开销
  • 对于没有用的大字段,如varchar,text,会增加IO操作
  • 失去MySQL优化器“覆盖索引”策略优化的可能性
  • SELECT* 杜绝了覆盖索引的一个可能性,而基于我们MySQL优化器的“覆盖索引”策略又是速度极快,效率很高,业界比较推荐。

2.避免出现不确定结果的函数

         就比如说我们在使用now()、rand()、sysdate()等不确定结果的函数很容易,导致主库与从库相应的数据不一致。

3.在多表关联查询的时候,小表在前,大表在后。

        因为在MySQL中,表关联查询是从左往右的,一张表会涉及全表扫描,所以我们一般将小表放在前面,这样扫描效率会比较高。

4.使用表的别名

        当有多个表的时候,建议把表的别名放在每个列名前。

三.对DML语句进行优化

1.大批量的插入数据

insert into T values(1,2); 
 
insert into T values(1,3); 
 
insert into T values(1,4);

--->
Insert into T values(1,2),(1,3),(1,4);

采用第二种插入的时候,只需要解析一次。而且SQL较短,也可以减少网络传输的IO

四.对查询条件优化

1.合理使用分页查询

五.建表优化

1. 在表中建立索引,优先考虑where、order by使用到的字段。

2.尽量用数字型字段,(男:1    女:0)

3.用varchar/nvarchar代替char/nchar