sql优化 - 图1
优化顺序:硬件>系统配置>数据库表结构>SQL 及索引。
前3点的优化就不多说了,当数据量超过250万的时候,我们一定要考虑分表分库,这里就不多说了,我们重点看一下sql优化,如果sql没有空间去优化,那就争取征服产品去优化业务;
sql优化注意以下三点:

  • 最大化利用索引。
  • 尽可能避免全表扫描。
  • 减少无效数据的查询。

sql细节

1.假设我们有三张表t_user用户表,t_user_guide用户导购表,t_order订单表,sql语句如下

  1. SELECT
  2. o.fid
  3. FROM
  4. t_user u
  5. LEFT JOIN t_order o ON o.fuser_account_id = u.fuser_id
  6. LEFT JOIN t_user_guide g ON g.fuser_id = u.fuser_id
  7. WHERE
  8. g.fguide_id = 29

疑点:t_user和t_order关联之后的结果再和t_user_guide关联查询吗?还是三张表同时关联之后,再通过where条件过滤?
有一篇播客图,会告诉我们结果。
微信图片_20210517162006.png
以上的sql也可以这样进行优化,sao操作来了

  1. SELECT
  2. *
  3. FROM
  4. t_user u
  5. LEFT JOIN t_order o ON o.fuser_account_id = u.fuser_id
  6. LEFT JOIN t_user_guide g ON g.fuser_id = u.fuser_id
  7. AND o.forder_status = 4
  8. AND o.del_flag = 0
  9. WHERE
  10. g.fguide_id = 29

关联查询的时候,会产生临时表,我们可以给临时表加条件,这个操作将会在某些复杂的业务场景遇到。
2.一个标准:
执行DML语句,update和delete操作的时候,需要再sql语句的后面添加limit关键字,防止批量更新,需要对生产环境保持敬畏。

  1. -- 影响行数1
  2. UPDATE t_user SET fnick_name = '小学生' WHERE fuser_id = 9348 LIMIT 1;

3.注意:
查询一个对象是否存在,我们通过count函数可以查询是否存在,也可以使用limit 1来查询是否存在,
count是全表扫描,limit 1是遇到有1条,停止扫描。


sql优化开始

避免不走索引的场景
①尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描
优化:遵循左匹配原则
②尽量避免使用 in 和 not in,会导致引擎走全表扫描
优化方式:如果是连续数值,可以用 between 代替。
如果是子查询,可以用 exists 代替。
③尽量避免使用 or,会导致数据库引擎放弃索引进行全表扫描
优化方式:可以用 union 代替 or。
④尽量避免进行 null 值的判断,会导致数据库引擎放弃索引进行全表扫描
优化方式:可以给字段添加默认值 0,对 0 值进行判断。
⑤尽量避免在 where 条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描

  1. -- 全表扫描
  2. SELECT * FROM T WHERE score/10 = 9
  3. -- 走索引
  4. SELECT * FROM T WHERE score = 10*9

⑥当数据量大时,避免使用 where 1=1 的条件
优化方式:用代码拼装 SQL 时进行判断,没 where 条件就去掉 where,有 where 条件就加 and。
⑦查询条件不能用 <> 或者 !=
使用索引列作为条件进行查询时,需要避免使用<>或者!=等判断条件。
如确实业务需要,使用到不等于符号,需要在重新评估索引建立,避免在此字段上建立索引,改由查询条件中其他索引字段代替。
⑧where 条件仅包含复合索引非前置列
如下:复合(联合)索引包含 key_part1,key_part2,key_part3 三列,但 SQL 语句没有包含索引前置列”key_part1”,按照 MySQL 联合索引的最左匹配原则,不会走联合索引。

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

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

  1. select col1 from table where col_varchar=123;

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

  1. -- 不走age索引
  2. SELECT * FROM t order by age;
  3. -- age索引
  4. SELECT * FROM t where age > 0 order by age;

select语句的执行顺序

  1. FROM
  2. <表名> # 选取表,将多个表数据通过笛卡尔积变成一个表。
  3. ON
  4. <筛选条件> # 对笛卡尔积的虚表进行筛选
  5. JOIN <join, left join, right join...>
  6. <join表> # 指定join,用于添加数据到on之后的虚表中,例如left join会将左表的剩余数据添加到虚表中
  7. WHERE
  8. <where条件> # 对上述虚表进行筛选
  9. GROUP BY
  10. <分组条件> # 分组
  11. <SUM()等聚合函数> # 用于having子句进行判断,在书写上这类聚合函数是写在having判断里面的
  12. HAVING
  13. <分组筛选> # 对分组后的结果进行聚合筛选
  14. SELECT
  15. <返回数据列表> # 返回的单列必须在group by子句中,聚合函数除外
  16. DISTINCT
  17. # 数据除重
  18. ORDER BY
  19. <排序条件> # 排序
  20. LIMIT
  21. <行数限制>