浅谈 SQL 优化

  • SQL 优化目标:避免全表查询,降低磁盘IO,提高查询效率。

执行顺序

在有优化 SQL 之前,我们需要先了解一下 SQL 执行过程,每个语句的执行顺序。

# 选择字段、去重
SELECT DISTINCT COLUMN, ...
# 聚合函数
    AGG_FUNC(COLUMN OR expression), ...
# 选择表
    FORM [left_table] 
# 链接
<join_type> JOIN <right_table>
# 链接条件
ON <join_condition>
# 条件过滤
WHERE <where_condition>
# 分组
GROUP BY <group_by_list>
# 分组过滤
HAVING <having_condition>
# 排序
ORDER BY <order_by_list>
# 分页
    LIMIT COUNT OFFSET COUNT;
执行顺序关键词功能
1FORM [left_table]选择表
2ON <join_condition>链接条件
3<join_type> JOIN <right_table>链接
4WHERE <where_condition>条件过滤
5GROUP BY <group_by_list>分组
6AGG_FUNC(COLUMN OR expression), ...聚合函数
7HAVING <having_condition>分组过滤
8SELECT DISTINCT COLUMN, ...选择字段、去重
9ORDER BY <order_by_list>排序
10LIMIT COUNT OFFSET COUNT分页

基础优化

  1. 尽可能指定查询字段,而不是使用 select *
  2. 避免在 where 子句中使用 or 来连接条件,推荐使用 union all 替换
  3. 使用 varchar 代替 char
  4. 尽量使用数值替代字符串类型

尽可能指定查询字段,而不是使用 select *

原因:

  1. 节省资源,减少网络开销。
  2. select * 查询时,很可能不会用到索引,造成全表查询。

避免在 where 子句中使用 or 来连接条件,推荐使用 union all 替换

原因:

  1. 使用 or 可能使索引失效,造成全表查询。

使用 varchar 代替 char

  • varchar变长字段按照数据内容实际长度存储,存储空间小,可以节省存储空间。
  • char按声明大小存储,不足补空格

尽量使用数值替代字符串类型

扩展

如何优化 SQL 慢查询?

  1. 分析语句,是否加载了不必要的字段/数据。
  2. 分析 SQL 执行计划(explain extended),思考可能的优化点,是否命中索引等。
  3. 查看 SQL 涉及的表结构和索引信息。
  4. 如果 SQL 很复杂,优化 SQL 结构。
  5. 按照可能的优化点执行表结构变更、增加索引、SQL 改写等操作。
  6. 查看优化后的执行时间和执行计划。
  7. 如果表数据量太大,考虑分表。
  8. 利用缓存,减少查询次数。

怎么创建索引

不了解什么是索引的,可以先看这篇文章【浅析数据库索引

  • 索引不宜太多,一般5个以内。

推荐创建索引情况

  • 频繁出现在where查询条件的字段
  • 多表查询中与其它表进行on关联的字段,外键关系
  • 查询中经常用来排序的字段
  • 查询中经常用来统计或者分组字段

不建议创建索引情况

  • 频繁更新的字段:每次更新都需要更新索引
  • where条件查询中用不到的字段
  • 经常增删改的表:每次更新都需要更新索引
  • 重复记录非常多的情况

单列索引/复合索引怎么选择?

高并发下倾向创建复合索引。

什么情况索引不生效?

  1. 有or必全有索引;
  2. 复合索引未用左列字段;
  3. like以%开头;
  4. 需要类型转换;
  5. where中索引列有运算;
  6. where中索引列使用了函数;
  7. 如果mysql觉得全表扫描更快时(数据少);

使用 explain 分析 SQL 执行计划

TODO: 后续举例详细说说。