MySQL中Cardinality值的介绍
1) 什么是Cardinality
不是所有的查询条件出现的列都需要添加索引。对于什么时候添加B+树索引。一般的经验是,在访问表中很少一部分时使用B+树索引才有意义。对于性别字段、地区字段、类型字段,他们可取值范围很小,称为低选择性。如
SELECT * FROM student WHERE sex='M'
按性别进行查询时,可取值一般只有M、F。因此SQL语句得到的结果可能是该表50%的数据(加入男女比例1:1)这时添加B+树索引是完全没有必要的。相反,如果某个字段的取值范围很广,几乎没有重复,属于高选择性。则此时使用B+树的索引是最合适的。例如对于姓名字段,基本上在一个应用中不允许重名的出现
怎样查看索引是否有高选择性?通过SHOW INDEX结果中的列Cardinality来观察。非常关键,表示所以中不重复记录的预估值,需要注意的是Cardinality是一个预估值,而不是一个准确值基本上用户也不可能得到一个准确的值,在实际应用中,Cardinality/n_row_in_table应尽可能的接近1,如果非常小,那用户需要考虑是否还有必要创建这个索引。故在访问高选择性属性的字段并从表中取出很少一部分数据时,对于字段添加B+树索引是非常有必要的。如
SELECT * FROM member WHERE usernick='David';
表member大约有500W行数据,usernick字段上有一个唯一索引。这是如果查找用户名为David的用户,将得到如下执行计划

可以看到使用了usernick这个索引。这也符合之前提到的高可选择性,即SQL语句取表中较少行的原则
2) InnoDB存储引擎的Cardinality统计
建立索引的前提是高选择性。这对数据库来说才具有实际意义,那么数据库是怎样统计Cardinality的信息呢?因为MySQL数据库中有各种不同的存储引擎,而每种存储引擎对于B+树索引的实现又各不相同。所以对Cardinality统计时放在存储引擎层进行的
在生成环境中,索引的更新操作可能非常频繁。如果每次索引在发生操作时就对其进行Cardinality统计,那么将会对数据库带来很大的负担。另外需要考虑的是,如果一张表的数据非常大,如一张表有50G的数据,那么统计一次Cardinality信息所需要的时间可能非常长。这样的环境下,是不能接受的。因此,数据库对于Cardinality信息的统计都是通过采样的方法完成
在InnoDB存储引擎中,Cardinality统计信息的更新发生在两个操作中:insert和update。InnoDB存储引擎内部对更新Cardinality信息的策略为:
表中1/16的数据已发生了改变
stat_modified_counter>2000 000 000
第一种策略为自从上次统计Cardinality信息后,表中的1/16的数据已经发生过变化,这是需要更新Cardinality信息
第二种情况考虑的是,如果对表中某一行数据频繁地进行更新操作,这时表中的数据实际并没有增加,实际发生变化的还是这一行数据,则第一种更新策略就无法适用这种情况,故在InnoDB存储引擎内部有一个计数器start_modified_counter,用来表示发生变化的次数,当start_modified_counter>2 000 000 000 时,则同样更新Cardinality信息
接着考虑InnoDB存储引擎内部是怎样进行Cardinality信息统计和更新操作呢?同样是通过采样的方法。默认的InnoDB存储引擎对8个叶子节点Leaf Page进行采用。采用过程如下
取得B+树索引中叶子节点的数量,记为A
随机取得B+树索引中的8个叶子节点,统计每个页不同记录的个数,即为P1,P2....P8
通过采样信息给出Cardinality的预估值:Cardinality=(P1+P2+...+P8)*A/8
根据上述的说明可以发现,在InnoDB存储引擎中,Cardinality值通过对8个叶子节点预估而得的。而不是一个实际精确的值。再者,每次对Cardinality值的统计,都是通过随机取8个叶子节点得到的,这同时有暗示了另外一个Cardinality现象,即每次得到的Cardinality值可能不同的,如
SHOW INDEX FROM OrderDetails
上述SQL语句会触发MySQL数据库对于Cardinality值的统计,第一次运行得到的结果如图5-20

在上述测试过程中,并没有通过INSERT、UPDATE这类的操作来改变OrderDetails中的内容,但是当第二次运行SHOW INDEX FROM OrderDetails语句是,发生了变化,如图5-21

可以看到,当第二次运行SHOW INDEX FROM OrderDetails语句时,表OrderDetails索引中的Cardinality值发生了变化,虽然表OrderDetails本身并没有发生任何变化,但是由于Cardinality是随机取8个叶子节点进行分析,所以即使表没有发生变化,用户观察到索引Cardinality值还是会发生变化,这本身不是Bug,而是随机采样而导致的结果
当然,有一种情况可以使得用户每次观察到的索引Cardinality值是一样的。那就是表足够小,表的叶子节点树小于或者等于8个。这时即使随机采样,也总是会采取倒这些页,因此每次得到的Cardinality值是相同的
在InnoDB1.2版本之前,可以通过innodb_stats_sample_pages用来设置统计Cardinality时每次采样页的数量,默认为8.同时,参数innodb_stats_method用来判断如何对待索引中出现NULL值记录。该参数默认值为nulls_equal,表示将NULL值记录为相等的记录。其有效值还nulls_unequal,nulls_ignored,分别表示将NULL值记录视为不同的记录和忽略NULL值记录。例如某夜中索引记录为NULL、NULL、1、2、2、3、3、3,在参数innodb_stats_method默认设置下,该页的Cardinality为4;若参数innodb_stats_method为nulls_unequal,则该页的Cardinality为5,若参数innodb_stats_method为nulls_ignored,则Cardinality值为3
当执行ANALYZE TABLE、SHOW TABLE STATUS、SHOW INDEX 以及访问INFORMATION_SCHEMA架构下的表TABLES和STATISTICS时会导致InnoDB存储引擎会重新计算索引Cardinality值,若表中的数据量非常大,并且表中存在多个辅助索引时,执行上述操作可能会非常慢,虽然用户可能并不希望去更新Cardinality值
InnoDB1.2版本提供了更多参数对Cardinality进行设置。如表

MySQL中Cardinality值的介绍的更多相关文章
- MySQL 中的默认数据库介绍
MySQL 中的默认数据库介绍:https://dataedo.com/kb/databases/mysql/default-databases-schemas 默认数据库 官方文档 informat ...
- mysql中CONCAT值为空的问题解决办法
在mysql中concat函数有一个特点就是有一个值为null那么不管第二个字符有多少内容都返回为空了,这个特性让我们在实例应用中可能觉得不方便,但实现就是这样我们需要使用其它办法来解决. 天在做op ...
- mysql中id值被重置的情况
MySQL中,如果你为一张使用了innodb引擎的表指定了一auto_increment列,那么这张表会有一个auto_increment计数器,专门记录当前auto_increment的相关值,用来 ...
- mysql中查询值为NULL的记录
例如表A中的user_login_name的值为NULL,用mysql语句把这条记录查询出来,用select user_login_name from A where user_login_name ...
- MySQL中字符串函数详细介绍
MySQL字符串函数对于针对字符串位置的操作,第一个位置被标记为1. ASCII(str)返回字符串str的 最左面字符的ASCII代码值.如果str是空字符串, 返回0.如果str是NULL,返回N ...
- SQL Server、Oracle和MySQL中查出值为NULL的替换
参考文献: http://database.51cto.com/art/200803/67397.htm 正文 在SQL Server Oracle MySQL当数据库中查出某值为NULL怎么办? 1 ...
- MySQL中的sleep函数介绍
MySQL数据库中有一个不太常用但便于进行某些调试的函数:sleep(),今天我们就来介绍一下这个函数的用法. 首先,看看官网对于函数的定义: SLEEP(duration)Sleeps (pause ...
- mysql中exists的用法介绍
SELECT c.CustomerId, CompanyName 2 FROM Customers c 3 WHERE EXISTS( 4 SELECT OrderID FROM ...
- MySQL中常用转换函数介绍
Cast函数:CONVERT函数. 用法:CAST(expr AS type), CONVERT(expr,type) , CONVERT(expr USING transcoding_name). ...
随机推荐
- 《深入浅出mfc》 第1章 笔记
需要什么函数库(.lib) windows支持动态链接库,应用程序所调用 的windows api 函数是在“执行期间“才链接上的.Windows程序调用 可以分为 C Runtimes以及windo ...
- Telerik UI for ASP.NET Core概要
介绍:不介绍了,刚开始研究. 下载:CSDN或者51cto上都有最新的开发版 安装:默认的安装目录是C:\Program Files (x86)\Progress\Telerik UI for ASP ...
- 网易2016年研发project师编程题(2)
序 网易互联网的实习笔试立即就開始了,做几个练习题熟悉熟悉~嘿嘿~ 题目一: 小易的升级之路 小易常常沉迷于网络游戏.有一次,他在玩一个打怪升级的游戏,他的角色的初始能力值为 a.在接下来的一段时间内 ...
- MyBatis官方教程及源代码解析——mapper映射文件
缓存 1.官方文档 MyBatis 包括一个非常强大的查询缓存特性,它能够非常方便地配置和定制. MyBatis 3 中的缓存实现的非常多改进都已经实现了,使得它更加强大并且易于配置. 默认情况下是没 ...
- 12.extern(转)
本文转自:http://blog.csdn.net/xingjiarong/article/details/47656339 利用关键字extern,可以在一个文件中引用另一个文件中定义的变量或者函数 ...
- Unix环境高级编程(一)
Unix基础知识1.引言2.Unix体系结构3.登陆4.文件和目录5.输入和输出6.程序和进程7.出错和处理8.用户标示9.信号10.时间值11.系统调用和库函数12.小结
- 问题解决 —— Http Status 500
在完成JavaWeb项目的过程中经常会出现这种错误 500:指的是服务器内部错误 通常遇到这种情况,我会去看控制台的信息,那里肯定会有提示,空指针(值没有传过去),或者java.sql.SQLExce ...
- freemark 页面静态化
1. 页面静态化是什么? 页面静态化有非常多含义,在WEB开发中.静态网页一般理解为站点中大部分超级链接所引用的页面是单独的HTML静态页面文件(如.htm..html等页面文件,html语言本身是静 ...
- c# 扩展方法奇思妙用基础篇八:Distinct 扩展
刚看了篇文章 <Linq的Distinct太不给力了>,文中给出了一个解决办法,略显复杂. 试想如果能写成下面的样子,是不是更简单优雅 var p1 = products.Distinct ...
- Apache的下载以及安装
前言:生活,生下来,活下去 第一步:在浏览器的搜索栏输入:apache下载:显示如下,单机进入Apache的官网