MySQL Cardinality值
(2016-10-30 20:08:44)分类: MySQL |
什么是Cardinality值?
并不是在所有的查询条件中出现的列都需要添加索引。对于什么时候添加B+树索引,一般的经验是,在访问表中很少一部分数据时使用B+树索引才有意义。例如,对于性别字段、地区字段、类型字段、状态字段,它们的可取值范围很小,成为低选择性的列。如:
select * from student where sex=’F’
按照性别查找时,可取值的范围一般是“M”和“F”。因此上述sql语句得到的结果可能是该表的50%数据,这个时候添加B+索引没有必要。但如果某个字段的取值范围很广,几乎没有重复,我们称之为高选择性,添加B+树索引很合适。
怎么查看已有的索引有高选择性呢?可以通过show index 结果中的列Cardinality来观察。Cardinality值非常关键,它表示索引中不重复记录数量的预估值。它是一个预估值,而不是一个准确的值,基本上我们不可能得到一个准确的值。
Cardinality表示索引的选择性。建立索引的前提是列中的数据是高选择性的。MySQL如何来统计Cardinality信息呢?MySQL数据库中有各种不同的存储引擎,而每种存储引擎对于B+树的实现方式各不相同,所以对于Cardinality的统计是放在存储引擎层进行的。
我们需要知道,在生产环境中,索引的更新操作可能是非常频繁的。如果每次索引在发生更新操作时,就对其进行Cardinality值的统计,那么将会给数据库带来很大的负担。如果一张表的数据非常大,假设有上百G,那么统计一次Cardinality信息所需要的时间可能非常长。在生产环境中,也是不能接受的。因此,数据库对于Cardinality的统计是通过采样(Sample)的方法来完成的。
那么什么时候会更新Cardinality值呢?以及这个值是如何得到的?
更新Cardinality发生在insert和update两个操作中。但是不是每次表中的索引发生insert和update的时候就去更新Cardinality信息。InnoDB存储引擎内部对更新Cardinality信息的策略为:
1) 、表中1/16的数据已发生过变化
2) 、stat_modified_counter>2 000 000 000
第一种策略为自从上一次统计过Cardinality信息之后,表中1/16的数据已经发生过变化,此时就要触发更新Cardinality信息了。
第二种策略考虑到一种情况,如果对表中某一行或者多行的数据频繁地进行更新操作,但是表中的记录数没有增加,发生变化的数据还是这一行或者多行。那么很显然,第一种更新策略无法适用这种情况。这个计数器stat_modified_counter大于2 000 000 000时,同样需要更新Cardinality的信息。
InnoDB存储引擎同样是通过采样的方法,统计Cardinality的值。采样方法为:
1) 、取得B+树索引中叶子节点的数量,计为A;
2) 、随机取得B+树索引中的8个叶子节点,统计每个叶子节点不同记录的个数,计为P1,P2,P3,P4,P5,...,P8。
3) 、Cardinality的预估值则为:(P1+P2+P3+...+P8)*A/8
由此我们可以知道,InnoDB存储引擎中,Cardinality值就是通过对8个叶子节点预估而得到的,不是一个实际精确的值。并且每次Cardinality得到的值可能又不一样,因为每次采样的8个叶子节点都不一定相同。
不过有一种情况可能使得用户每次观察到的索引Cardinality值都是一样的,那就是当表足够小,索引的叶子节点小于或者等于8个,那么无论如何采样,也总是会采取到同样的叶子节点。
注:show index from table_name可以查看Cardinality的值