如何做到SQL性能优化?

                        关注贝西奇谈不迷路!

在这里插入图片描述

1.前言

一个优秀开发的必备技能:性能优化,包括:JVM调优、缓存、Sql性能优化等。本文主要讲基于Mysql的索引优化。
首先我们需要了解执行一条查询SQL时Mysql的处理过程:

在这里插入图片描述

其次我们需要知道,我们写的SQL在Mysql的执行顺序是怎么样的?sql的执行顺序对sql的性能优化很有帮助,很重要。在建立复合索引的时候需要考虑到这点。

在这里插入图片描述

2.介绍

在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是随着互联网大数据的兴起,随着数据库中数据的增加,系统的响应速度就成为目前系统需要解决的最主要的问题之一。
系统优化中一个很重要的方面就是SQL语句的优化。对于海量数据,劣质SQL语句和优质SQL语句之间的速度差别可以达到上百倍,可见对于一个系统不是简单地能实现其功能就可,而是要写出高质量的SQL语句,提高系统的可用性。
3.常见优化规则

3.1数据类型

数据类型的选择原则:更简单或者占用空间更小。

如果长度能够满足,整型尽量使用tinyint、smallint、medium_int而非int。
如果字符串长度确定,采用char类型。
如果varchar能够满足,不采用text类型。
精度要求较高的使用decimal类型,也可以使用BIGINT,比如精确两位小数就乘以100后保存。
尽量采用timestamp而非datetime。

在这里插入图片描述

相比datetime,timestamp占用更少的空间,以UTC的格式储存自动转换时区。

3.2避免空值

MySQL中字段为NULL时依然占用空间,会使索引、索引统计更加复杂。从NULL值更新到非NULL无法做到原地更新,容易发生索引分裂影响性能。尽可能将NULL值用有意义的值代替,也能避免SQL语句里面包含is not null的判断。微信搜索web_resource 关注获取更多推送。微信搜索web_resource 关注获取更多推送。

3.3text类型优化

由于text字段储存大量数据,表容量会很早涨上去,影响其他字段的查询性能。建议抽取出来放在子表里,用业务主键关联。

3.4表连接数

连接的表越多,性能越差
可能的话,将连接拆分成若干个过程逐一执行
优先执行可显著减少数据量的连接,既降低了复杂度,也能够容易按照预期执行
如果不可避免多表连接,很可能是设计缺陷
外链接效果差,因为必须对左右表进行表扫描
尽量使用inner join查询
4.SQL语句优化

4.1 NULL列
Null列使用索引没有意义,任何包含null值的列都不会被包含在索引中。因此where语句中的is null或is not null的语句优化器是不允许使用索引的。
4.2 concat或||
concat或||是mysql和oracle的字符串连接操作,如果对列进行该函数操作,那么也开会忽略索引的使用。比较下面的查询语句:

-- 忽律索引
select ... from .. where first_name || '' || last_name = 'bill gates' ;
-- 使用索引
select ... from .. where first_name = 'bill' and last_name = 'bill gates' ;

4.3 like
通配符出现在首位,无法使用索引,反之可以。

-- 无法使用索引
select .. from .. where name like '%t%' ;
-- 可以使用索引
select .. from .. where name like 't%' ;

4.4 order by
order by子句中不要使用非索引列或嵌套表达式,这样都会导致性能降低。
4.5 Not运算
not运算无法使用索引,可以改成其他能够使用索引的操作。如下:

-- 索引无效
select .. from .. where sal != 3000 ;
-- 索引生效
select .. from .. where sal < 3000  or sal > 3000;

4.6 where与having
select … from … on … where … group by … having … order by … limit …,以上是sql语句的语法结构,其中on、where和having是有过滤行为的,过滤行为越能提前完成就越可以减少传递给下一个阶段的数据量,因此如果在having中的过滤行为能够在where中完成,则应该优先考虑where来实现。
4.7 exists替代in
not in是最低效的,因为要对子查询的表进行全表扫描。可以考虑使用外链接或not exists。如下:

-- 正确
SELECT  *
FROM EMP 
WHERE  
	EMPNO > 0 
	AND  EXISTS (SELECTX' FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB')

-- 错误
SELECT  * 
FROM  EMP 
WHERE  EMPNO > 0  AND  DEPTNO IN(SELECT DEPTNO  FROM  DEPT  WHERE  LOC =MELB')

4.8 is null & is not null
如果列可空,避免使用索引。对于多个列使用的索引,起码保证至少有个列不为空。对于多列索引,只有访问了第一个列才会启用索引,如果访问后面的列则使用的是全表扫描。

-- 低效: (索引失效) 
SELECT .. FROM  DEPARTMENT  WHERE  DEPT_CODE IS NOT NULL; 
-- 高效: (索引有效) 
SELECT .. FROM  DEPARTMENT  WHERE  DEPT_CODE >=0;

5.索引优化

5.1索引分类

普通索引:最基本的索引。
组合索引:多个字段上建立的索引,能够加速复合查询条件的检索。
唯一索引:与普通索引类似,但索引列的值必须唯一,允许有空值。
组合唯一索引:列值的组合必须唯一。
主键索引:特殊的唯一索引,用于唯一标识数据表中的某一条记录,不允许有空值,一般用primary key约束。
全文索引:用于海量文本的查询,MySQL5.6之后的InnoDB和MyISAM均支持全文索引。由于查询精度以及扩展性不佳,更多的企业选择Elasticsearch。
5.2索引优化

分页查询很重要,如果查询数据量超过30%,MYSQL不会使用索引。
单表索引数不超过5个、单个索引字段数不超过5个。
字符串可使用前缀索引,前缀长度控制在5-8个字符。
字段唯一性太低,增加索引没有意义,如:是否删除、性别。
合理使用覆盖索引,如下所示:

select login_name, nick_name from member where login_name = ?
login_name, nick_name两个字段建立组合索引,比login_name简单索引要更快。
如有文章对你有帮助,
在看”和 转发是对我最大的支持!

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝西奇谈

你的鼓励将是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值