
现在某个表,有个 status,有两个值,0,1
按照好多文档说明,这列不应该加索引。
比如,0 是未处理的,1 是处理过的。
一般都是要查 0,来进行处理。
发现 status 加了索引之后,查找的速度飞快。
2000w 的表,SELECT COUNT(*), 从 14s 下降到 0.1s 以下( SQL_NO_CACHE )
1 yemoluo 2020-04-28 18:53:21 +08:00 加了索引,`select count(*)` 走的是索引,索引比起原表那真是小太多了 |
2 gotonull 2020-04-28 18:53:51 +08:00 status 加索引对 count 有影响?不懂,插眼。等一个大佬解释 |
3 virusdefender 2020-04-28 18:55:46 +08:00 status 加索引对 count 有影响?+1 看下 explain 的结果 |
4 yumenawei 2020-04-28 18:57:37 +08:00 这个是特例。 你随便查点需要回表的数据试试。 |
5 sadfQED2 2020-04-28 19:01:54 +08:00 via Android Count 操作不会回表,你试试 select * |
6 xuanbg 2020-04-28 19:19:14 +08:00 这种看情况,索引就是使无序的数据变得有序,相当于让乱糟糟的一群人按某种特性排起了整齐的队伍。如果你需要找的人在队伍里面占大多数,那这个队伍没多大意思。如果你要找的是队伍里面的少数人,那效率提升就是杠杠的。 |
7 xinshoushanglu 2020-04-28 19:24:50 +08:00 count 应该是在 mysql.sys 表里记录的一个量,和数据表的规模没关系。我之前一张一千多万的表,查都查不动,但是 count(1)或者 count(*) 还是秒出 |
8 encro 2020-04-28 19:32:18 +08:00 索引对于量少的数据有效。 比如你表数据绝大部分都是 status=0 的, 但是你查询是 status=1 的数据,这时候索引有效的,也是很快的, 如果你查 status=0,因为数据量超过了总数一般,那么索引无效。 |
9 glacer 2020-04-28 20:36:13 +08:00 加索引有效的原因是 0 和 1 的数据量不均等吧。如果 0 只占很小一部分,status=0 的时候当然很快 |
10 PopRain 2020-04-28 20:38:22 +08:00 @xinshoushanglu 人家是做条件 count, 不是统计全表的行数。 状态值用索引快是因为一个 Page 可以保存更多的记录,就算走索引全扫描,所需要的 I/O 比表扫描也少的多 |
11 orcusfox 2020-04-28 20:41:43 +08:00 via iPhone 区分度不大的字段加索引效果不大吧 |
12 wdlth 2020-04-28 20:45:57 +08:00 应该与其他的字段一起加联合索引,单独加不一定能用。 |
13 gongwenhua 2020-04-28 21:23:29 +08:00 截个图看看 explain ? |
14 daozhihun 2020-04-28 21:25:29 +08:00 不建议加索引,筛选的行数太少,系统很可能会忽略掉 |
15 cheng6563 2020-04-28 21:27:01 +08:00 这算是个特殊用法吧 |
16 jam1024 2020-04-28 21:50:40 +08:00 建议加组合索引,不建议加单独索引 |
17 Orenoid 2020-04-28 21:57:25 +08:00 via Android status 这种选择性很低的列,单独加索引收益很低 |
18 love 2020-04-28 21:59:51 +08:00 这个状态很少的列要看数据分布的。如果是分布很平均就不用加。 |
19 dongisking 2020-04-28 22:00:52 +08:00 不建议,建议分表 |
20 uxff 2020-04-28 22:20:29 +08:00 加索引快是因为直接读索引就能统计到条数。而不需要再读表内容,减少了 io 次数。不加索引会增加额外的 io 开销。 读完索引再读表内容一般至少多加一次 io,除非表很小(在 B+数的一簇以内)。 如果不加索引,且 status=0 的值很多,分散在不同的簇上,那就很慢,需要很多次 io 。 |
21 uxff 2020-04-28 22:23:15 +08:00 看了 mysql 的实现原理后,你就懂了,mysql innodb 索引是针对现代磁盘高度优化的。只统计或查询索引上的字段都会快很多。 |
22 littlewing 2020-04-28 23:24:18 +08:00 count(*) count(1) count(status) 确实是有用的,因为 MySQL 判断扫描 status 索引也能得到正确的 count,而 status 索引比其他索引和主键索引扫描起来快多了 但是如果想用 status 索引加快 select * from xxx where status = 1 这样的查找速度的话,就不用想了,MySQL 绝对会选择扫描主键索引,因为 cardinality 太小了,再加上回表的开销,MySQL 会认为走主键索引更快 |
23 littlewing 2020-04-28 23:25:54 +08:00 @xinshoushanglu innodb 是不能这样做的,因为有事务和隔离级别的存在,同一时间不同事务看到的 count 可以不一样,Myisam 是可以这样做的 |
24 hooopo 2020-04-29 00:34:18 +08:00 具体情况具体分析 |
25 thinkmore 2020-04-29 16:54:37 +08:00 不建议加。status 区分度太低了,基本全是扫描叶子节点。 如果你查这样的,你就能感受到了 select column_1,column_2,column_3 from table where status = 1 |
26 qyvlik 2020-04-29 23:06:10 +08:00 根据业务要求加,就是根据哪种 sql 查询多的去加索引,还要根据具体 sql 查询拼接的条件。 所谓 status 区分度低的前提是 0,1 均匀分布,说白了可能各 50%,这样加索引就没啥效果。按照你的问题描述,以及可能的常用场景,0 和 1 的分布不是均匀的,一般是 0 >> 1,就是说 status 为 0 可能就是全表记录的 一小部分(例如 1%),那么如下的查询 sql: select * from table where status = 0 就会走索引,而且索引扫描的行数也不会太多。 但是如下的 sql: select * from table where status = 1,可能会走索引,但是扫描的行数过多时会让 mysql 做出扫描全表的执行计划。 select count(*) from table,在有索引的情况,可能会走索引,具体看看执行计划。 |
27 54qyc 2023-08-25 21:39:43 +08:00 status 如果是和常量值比较,并且常量值占比比较小,则 mysql 会走索引而不会全表扫描. 这里和 count 机制没关系吧,select 任意的速度应该都会更快。OP 是这样吗? |
28 54qyc 2023-08-25 21:45:37 +08:00 @littlewing 并不是这样。与常量比较,mysql 会看 1 的占比。占比低就会走索引。而不是看基数,看基数发生在与列值比较的情况。 |