数据库的可爱之举!!- 趁大家不注意记小本本

 每日之想

这个行为也太可爱了吧!!👅👅👅👅

如果每次查询前,优化器都要真刀真枪地去把目录(Index)数一遍,再把表(Table)数一遍,那光是“数数”这个动作就已经慢死了,还查什么数据?

所以,它依靠的是一份**“作弊小抄”**,专业术语叫:数据库统计信息 (Database Statistics)。


1. 它的“作弊小抄”里记了什么?

数据库会定期(比如每天夜里,或者数据变动很大时)悄悄去抽查你的表,然后在一个小本本上记下这些信息:

  1. 行数 (Row Count): 表里大概有多少行?(比如:100万行)。

  2. 区分度 (Cardinality): 这一列大概有多少个不同的值?(比如:status 列只有 3 个值)。

  3. 分布图 (Histogram/Distribution): 数据的分布是不均匀的吗?(比如:99% 是 False,1% 是 True)。

重点来了: 当你查询时,优化器不读原表,也不读索引,它只是瞄了一眼这个小本本。

2. 它是怎么做“预计”的?(模拟计算过程)

假设你发来一条 SQL:SELECT * FROM users WHERE city = 'Beijing';

优化器开始掐指一算:

步骤 A:看小抄

  • 总行数: 1000 万。

  • city 列的统计信息: 北京的用户占比约为 5%(这是之前抽查记录下来的)。

步骤 B:算成本 (Cost Estimation)

  • 预计行数: $1000万 \times 5\% = 50万行$。

  • 方案一(走索引): * 读取 50 万个索引节点 + 回表(随机跳跃读取)50 万次。

    • 成本分: 假设是 500 分(回表很累)。

  • 方案二(全表扫描):

    • 直接从头读到尾,顺序读 1000 万行。

    • 成本分: 假设是 1000 分(虽然顺路,但路太长)。

步骤 C:做决定

  • 500 < 1000,决定走索引!


3. 既然是“预计”,那会出错吗?

会!而且经常出错。 这就是所谓的“统计信息过期”或者“统计信息不准”。

情况一:数据突然暴增

昨天表里只有 100 行数据,优化器觉得“全表扫描最快”。今天你突然导入了 1000 万行数据,但小本本还没来得及更新。优化器还以为只有 100 行,继续傻乎乎地用全表扫描,结果数据库直接卡死。

情况二:抽样误差

数据库为了维护这个“小本本”,不会每次都把全表数一遍(太慢),它通常是**“随机抽样”**(比如只看前几页)。

就像“盲人摸象”,如果它正好抽到了布尔值全是 True 的那几页,它就会以为整张表都是 True,从而做出了错误的索引判断。

4. 怎么解决“预计不准”的问题?

如果你发现明明加了索引,查询还是很慢,或者 EXPLAIN 显示它没走索引,很有可能就是“小抄”过期了。

你需要手动命令数据库:“别偷懒了,把数据重新数一遍!”

  • MySQL: ANALYZE TABLE teams;

  • PostgreSQL: ANALYZE teams;

执行完这个命令后,数据库会重新计算统计信息,优化器拿到最新的“情报”,通常就会变聪明了。



评论

此博客中的热门博文

时间