数据库的可爱之举!!- 趁大家不注意记小本本
每日之想
如果每次查询前,优化器都要真刀真枪地去把目录(Index)数一遍,再把表(Table)数一遍,那光是“数数”这个动作就已经慢死了,还查什么数据?
所以,它依靠的是一份**“作弊小抄”**,专业术语叫:数据库统计信息 (Database Statistics)。
1. 它的“作弊小抄”里记了什么?
数据库会定期(比如每天夜里,或者数据变动很大时)悄悄去抽查你的表,然后在一个小本本上记下这些信息:
行数 (Row Count): 表里大概有多少行?(比如:100万行)。
区分度 (Cardinality): 这一列大概有多少个不同的值?(比如:
status列只有 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;
执行完这个命令后,数据库会重新计算统计信息,优化器拿到最新的“情报”,通常就会变聪明了。
评论
发表评论