统计信息是数据库管理系统用来描述表和索引中数据分布特征的内部数据,查询优化器依赖它来估算查询成本并选择执行计划。如果统计信息不准确,优化器就可能生成低效的计划,例如该走索引却做了全表扫描。

什么是统计信息
在关系型数据库中,统计信息通常包含表的总行数、每个列的不同值数量、空值数量、数据直方图以及索引的层级和叶块数等。以 MySQL 的 InnoDB 为例,优化器通过这些信息估算某个过滤条件会返回多少行记录。
常见统计信息内容
- 表行数估算
- 列的基数,即不同值个数
- 数据直方图,描述值分布倾斜情况
- 索引深度与聚簇因子
优化器如何使用统计信息
当一条 SQL 被执行时,优化器会解析 WHERE 条件,并利用统计信息计算每种候选计划的代价。比如对于条件 status = 'active',若统计信息显示该值占比仅 1%,优化器更倾向于使用 status 上的索引;若占比 90%,则全表扫描反而更便宜。
简单示例
以下伪代码展示了优化器选择路径的基本逻辑:
-- 假设 orders 表有索引 idx_status -- 优化器读取统计信息 SELECT table_rows, (SELECT cardinality FROM index_stats WHERE index_name = 'idx_status') AS idx_card FROM table_stats WHERE table_name = 'orders'; -- 若估算命中行数 < 表行数 * 5% 则选索引 -- 否则选全表扫描
统计信息不准带来的问题
当表经历大量插入、删除或更新后,若未重新收集统计信息,优化器看到的仍是旧数据。这时它可能低估或高估返回行数,导致错误选择嵌套循环或哈希连接。例如在 Oracle 中,可以用如下语句手动收集:
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => 'SCOTT',
tabname => 'EMP',
cascade => TRUE
);
END;
/
如何查看执行计划与统计关系
我们可以通过 EXPLAIN 命令观察优化器的判断。如果 rows 列预估值和真实值差距很大,通常说明统计信息需要更新。下面以 MySQL 为例:
EXPLAIN SELECT * FROM orders WHERE status = 'active' AND create_time > '2023-01-01';
| 字段 | 含义 |
|---|---|
| type | 访问类型,如 ref 或 ALL |
| rows | 优化器估算的扫描行数 |
| key | 实际选用的索引 |
小结
统计信息是影响执行计划的根本因素之一。保持统计信息及时、准确,才能让查询优化器做出合理选择。后续文章会进一步讨论不同数据库下统计信息的收集策略与参数调优。