优化目标
1. 减少 IO 次数
IO 永远是数据库最容易瓶颈的地方 , 这是数据可的职责所决定的 , 大部分数据库操作中超过 90% 的时间都是 IO 操作所占用的 , 减少 IO 次数 是 SQL 优化中需要第一优先考虑 , 当然, 也是收益最明显的优化手段 .
2. 降低 CPU 计算
除了 IO 瓶颈之外 , SQL 优化中需要考虑的就是 CPU 运算量的优化了 。 order by , group by ,distinct … 都是消耗 CPU 的大户(这些操作基本都是 CPU 处理内存中的数据比较运算) 。 当我们的 IO 优化做到一定阶段之后 , 降低 CPU 计算也就成为了我们 SQL 优化的重要目标 .
优化方法
改变 SQL 执行计划
明确了优化目标之后 , 我们需要确定打到我们目标的方法 . 对于 SQL 语句来说 , 达到上述 2 个目标的方法其实只有一个 , 那就是改变 SQL 的执行计划 , 让他尽量 “少走弯路” , 尽量通过各种 “捷径” 来找到我们的需要的数据 , 以达到 “减少 IO 次数” 和 “降低CPU计算” 的目标 .
常见误区
-
count(1)
和count(primary_key)
优于count(*)
很多人为了统计记录条数 , 就使用 count(1) 和 count(primary_key) 而不是 count() , 他们认为这样性能更好 , 其实这是一个误区 , 对于有些场景 , 这样做可能性能会更差 , 应为数据库对 count() 计数操作做了一些特别的优化 . -
count( column )
和count(*)
是一样的
这个误区甚至在很多的资深工程师或者是DBA中都普遍存在 , 很多人都会认为这是理所当热的 , 实际上 , count( column ) 和 count(*) 是一个完全不一样的操作 , 所代表的意义也完全不一样 .
count( column ) 是表示结果集中有多少个 column 字段不为空的记录 .
count( * ) 表示整个结果集中有多少条记录 . -
select a,b from ...
比select a,b,c from ...
可以让数据库访问更少的数据量 .
这个误区主要存在于大量的开发人员中 , 主要原因就是对数据库的存储原理不是太了解 .
实际上 , 大多数关系型数据库都是按照行 (row) 的方式存储 , 而数据库存取操作都是以一个固定大小的 IO 单元(被称作 block 或者 page ) 为单位 , 一般为 4KB , 8KB … 大多数的时候 , 每个 IO 单元中存储了多行 , 每行都是存储了该行的所有字段 ( lob 等特殊类型字段除外) .
所以我们是取一个字段还是多个字段 , 实际上数据库在表中需要访问的数据量其实是一样的 .
当然 , 也有例外的情况 , 那就是我们的这个查询在索引中就可以完成 , 也就是说当制度去 a,b 两个字段的时候 , 不需要会标 , 而 c 这个字段不在使用的索引中 , 需要回表取得其数据 . 在这样的情况下 , 二者的 IO 量会有较大的差异 . -
order by
一定需要排序操作
我们知道索引数据实际上是有序的 , 如果我们需要的数据和某个索引的顺序一致 , 而且我们的查询有通过这个索引来执行 , 那么数据库一般会省略排序操作 , 而直接将数据返回 , 因为数据库知道诗句已经满足我们的排序需求了 .
实际上 , 利用索引来优化有序需求的 SQL ,是一个非常重要的手段 .
延伸阅读 : MySQL ORDER BY 的实现分析 , MySQL 中 GROUP BY 基本实现原理以及 MySQL DISTINCT 的基本实现原理 . - 执行计划中有 filesort 就会进行磁盘文件排序
有这个误区其实不能改我们 , 而是因为 MySQL 开发者在用词方面的问题 . filesort 是我们在使用 explain 命令查看一条 SQL 的执行计划的时候可能会看到在 “Extra” 一列显示的信息 .
实际上 , 只要一条 SQL 语句需要进行排序操作 , 都会显示 “Using filesort” , 这并不表示就会有文件排序操作 .