Appearance
ANALYZE 对查询的影响
ANALYZE 收集数据库中表内容的统计信息,然后把结果保存在系统表 pg_statistic里。 帮助查询规划器(Query Planner)做出更优的决策。
ANALYZE 的核心使命:为查询规划器提供“情报”
您可以将数据库的查询规划器想象成一位将军,他需要制定最佳的作战计划(如何执行一个SQL查询)。而 ANALYZE 命令 就像是负责收集敌方(数据表)情报的侦察兵。没有准确的情报,将军就只能盲目指挥,可能会选择一条非常低效的进攻路线。
ANALYZE 收集的“情报”就是 统计信息,它告诉规划器关于数据的一切:表的规模有多大、数据是如何分布的、哪些值的出现频率更高等等。
表的统计信息
- 总行数
- 索引的唯一性比例 (Index Uniqueness)
- 作用: 这个指标帮助规划器判断一个索引的“选择性”有多高。一个高选择性的索引(比如主键索引,唯一值很多)在查询时能迅速定位到极少数的几行,效率极高。
- 例子: 假设一个“性别”列有索引,但列中只有“男”和“女”两个值。这个索引的选择性就很低,规划器可能会判断走索引的成本(先读索引,再根据索引回表取数据)比直接全表扫描还要高,从而放弃使用该索引。性别索引很可能会指向大量不连续的数据页,(页1、页3、页5、页18…),会产生大量的随机IO,磁盘不断的寻道读取,不如直接寻道一次全表扫描更快些。
列的统计信息
- 数据列直方图
sql
-- 示例1
-- 查询规划器需要决定是先执行 vip = true 还是先执行 amound > 1000。
-- 它会参考直方图提供的估算值:
-- vip = true 可能会返回约 100 行。
-- amound > 1000 可能会返回约 10 行。
-- 为了最小化I/O操作(即读取更少的数据行),规划器会选择先执行能过滤掉更多数据的条件。
-- 它会选择先执行 amound > 1000,因为这个条件返回的结果集更小(10行 vs 100行)。
WHERE vip = true AND amound > 1000sql
示例2:
假设一个订单表 orders 有一个 status 列,
包含“待支付”、“已支付”、“已发货”、“已完成”、“已取消”等状态。
如果 90% 的订单都是“已完成”状态,那么:
- 执行 `WHERE status = '待支付'`,
规划器通过直方图得知只会返回很少的行,这非常适合走索引。
- 执行 `WHERE status = '已完成'`
规划器通过直方图得知会返回表中90%的数据。此时,它很可能会放弃索引,选择全表扫描
因为回表查询90%的数据行所带来的随机I/O成本会远远高于一次性的顺序全表扫描。- **NULL值的比例 (Null Fraction):**记录列中 NULL 值的占比。这对于 IS NULL 或 IS NOT NULL 的查询估算很重要。
- **不同值的数量 (N-Distinct):**估算一列中不重复值的数量。如果这个值接近于总行数,说明该列的选择性很高。
总结
诊断慢查询的利器: 当你遇到一个慢查询时,检查其 EXPLAIN 计划,如果发现行数估算(rows)和实际执行行数(actual rows in EXPLAIN ANALYZE)之间存在巨大差异,通常就意味着统计信息过时或不准确,此时手动对相关表执行一次 ANALYZE 往往能立竿见影地解决问题。