MySQL 中 Cardinality 值的介绍

本贴最后更新于 2508 天前,其中的信息可能已经事过境迁

转自 熊出陌

  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 语句取表中较少行的原则

  1.     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

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    675 引用 • 535 回帖
  • Cardinality
    1 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 606 关注
  • 招聘

    哪里都缺人,哪里都不缺人。

    189 引用 • 1056 回帖 • 1 关注
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖 • 1 关注
  • OpenResty

    OpenResty 是一个基于 NGINX 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

    17 引用 • 41 关注
  • 域名

    域名(Domain Name),简称域名、网域,是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。

    43 引用 • 208 回帖 • 3 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 445 关注
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 618 关注
  • Sillot

    Insights(注意当前设置 master 为默认分支)

    汐洛彖夲肜矩阵(Sillot T☳Converbenk Matrix),致力于服务智慧新彖乄,具有彖乄驱动、极致优雅、开发者友好的特点。其中汐洛绞架(Sillot-Gibbet)基于自思源笔记(siyuan-note),前身是思源笔记汐洛版(更早是思源笔记汐洛分支),是智慧新录乄终端(多端融合,移动端优先)。

    主仓库地址:Hi-Windom/Sillot

    安卓端仓库:Hi-Windom/Sillot-android

    注意事项:

    1. ⚠️ 汐洛仍在早期开发阶段,尚不稳定
    2. ⚠️ 汐洛并非面向普通用户设计,使用前请了解风险
    28 引用 • 25 回帖 • 56 关注
  • 安全

    安全永远都不是一个小问题。

    191 引用 • 813 回帖
  • 国际化

    i18n(其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数)是“国际化”的简称。对程序来说,国际化是指在不修改代码的情况下,能根据不同语言及地区显示相应的界面。

    7 引用 • 26 回帖
  • 笔记

    好记性不如烂笔头。

    306 引用 • 782 回帖 • 1 关注
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖 • 10 关注
  • Ngui

    Ngui 是一个 GUI 的排版显示引擎和跨平台的 GUI 应用程序开发框架,基于
    Node.js / OpenGL。目标是在此基础上开发 GUI 应用程序可拥有开发 WEB 应用般简单与速度同时兼顾 Native 应用程序的性能与体验。

    7 引用 • 9 回帖 • 355 关注
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 455 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖
  • Openfire

    Openfire 是开源的、基于可拓展通讯和表示协议 (XMPP)、采用 Java 编程语言开发的实时协作服务器。Openfire 的效率很高,单台服务器可支持上万并发用户。

    6 引用 • 7 回帖 • 96 关注
  • Kubernetes

    Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。

    109 引用 • 54 回帖 • 1 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 44 关注
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 437 关注
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 50 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    28 引用 • 108 回帖
  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖 • 2 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    163 引用 • 473 回帖
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 1 关注
  • frp

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 TCP、UDP、 HTTP 和 HTTPS 协议。

    16 引用 • 7 回帖 • 1 关注