【MySQL技术内幕】5.5-Cardinality值

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 【MySQL技术内幕】5.5-Cardinality值

1、什么是 Cardinality

并不是在所有的查询条件中出现的列都需要添加索引。对于什么时候添加B+树索引,一般的经验是,在访问表中很少一部分时使用B+树索引才有意义。对于性别字段地区字段、类型字段,它们可取值的范围很小,称为低选择性。如:

SELECT FROM student Where sex='M';

按性别进行查询时,可取值的范围一般只有"M、F"。因此上述SQL语句得到的结果可能是该表50%的数据(假设男女比例1:1),这时添加B+树索引是完全没有必要的。相反,如果某个字段的取值范围很广,几乎没有重复,即属于高选择性,则此时使用B+树索引是最适合的。例如,对于姓名字段,基本上在一个应用中不允许重名的出现。

怎样查看索引是否是高选择性的呢?可以通过 SHOW INDEX结果中的列 Cardinality来观察。 Cardinality值非常关键,表示索引中不重复记录数量的预估值。同时需要注意的是, Cardinality是一个预估值,而不是一个准确值,基本上用户也不可能得到一个准确的值。在实际应用中, Cardinality/n_rows_in_table应尽可能地接近1。如果非常小,那么用户需要考虑是否还有必要创建这个索引。故在访问高选择性属性的字段并从表中取出很少一部分数据时,对这个字段添加B+树索引是非常有必要的。如:

SELECT FROM member WHERE usernick ='David';

表 member大约有500万行数据。 usemick字段上有一个唯一的索引。这时如果查找用户名为 David的用户,将会得到如下的执行计划:

EXPLAIN SELECT* FROM memberWHERE usernick='David'\G

image.png

可以看到使用了 usernick这个索引,这也符合之前提到的高选择性,即SQL语句选取表中较少行的原则。

2、InnoDB存储引擎的 Cardinality统计

建立索引的前提是列中的数据是高选择性的,这对数据库来说才具有实际意义。然而数据库是怎样来统计 Cardinality信息的呢?因为 MySQL数据库中有各种不同的存储引擎,而每种存储引擎对于B+树索引的实现又各不相同,所以对 Cardinality的统计是放在存储

引擎层进行的。

此外需要考虑到的是,在生产环境中,索引的更新操作可能是非常频繁的。如果每次索引在发生操作时就对其进行 Cardinality的统计,那么将会给数据库带来很大的负担。另外需要考虑的是,如果一张表的数据非常大,如一张表有50G的数据,那么统计次 Cardinality信息所需要的时间可能非常长。这在生产环境下,也是不能接受的。因此,数据库对于 Cardinality的统计都是通过采样( Sample)的方法来完成的。

在 InnoDB存储引擎中, Cardinality统计信息的更新发生在两个操作中: INSERT和 UPDATE。根据前面的叙述,不可能在每次发生 INSERT和 UPDATE时就去更新Cardinality信息,这样会增加数据库系统的负荷,同时对于大表的统计,时间上也不允许数据库这样去操作。因此, InnoDB存储引擎内部对更新 Cardinality信息的策略为:

  • 表中116的数据已发生过变化。
  • stat_modified_counter>2000000000。

第一种策略为自从上次统计 Cardinality信息后,表中1/16的数据已经发生过变化,这时需要更新 Cardinality信息。第二种情况考虑的是,如果对表中某一行数据频繁地进行更新操作,这时表中的数据实际并没有增加,实际发生变化的还是这一行数据,则第一种更新策略就无法适用这这种情况。故在 InnoDB存储引擎内部有一个计数器stat_modified_counter,用来表示发生变化的次数,当 stat_modified_counter大于2000000000时,则同样需要更新 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值的统计,第一次运行得到的结果如图所示。

image.png

在上述测试过程中,并没有通过 INSERT、 UPDATE这类操作来改变表 OrderDetails中的内容,但是当第二次再运行 SHOW INDEX FROM语句时, Cardinality值还是会发生变化,如图所示。

image.png

可以看到,第二次运行 SHOW INDEX FROM语句时,表 OrderDetails中索引的Cardinality值都发生了变化,虽然表 OrderDetails本身并没有发生任何的变化,但是,由于 Cardinality是对随机取8个叶子节点进行分析,所以即使表没有发生变化,用户观察到的索引 Cardinality值还是会发生变化,这本身并不是 InnoDB存储引擎的Bug,只是随机采样而导致的结果。

当然,有一种情况可能使得用户每次观察到的索引 Cardinali!y值都是一样的,那就是表足够小,表的叶子节点数小于或者等于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、12、2、3、3、3,在参数 innodb_stats_method的默认设置下,该页的 Cardinality为4;若参数 innodb_stats_method为 nulls_unequal,则该页的Cardinality为5;若参数 innodb_stats_method为nulls_ignored,则Cardinality为3。

当执行SQL语句 ANALYZE TABLE、 SHOW TABLE STATUS、 SHOW INDEX以及访问 INFORMATION SCHEMA架构下的表 TABLES和 STATISTICS时会导致InnoDB存储引擎去重新计算索引的 Cardinality值。若表中的数据量非常大,并且表中存在多个辅助索引时,执行上述这些操作可能会非常慢。虽然用户可能并不希望去更新Cardinality值。

InnoDB1.2版本提供了更多的参数对 Cardinality统计进行设置,这些参数如下表所示。

InnoDB1.2新增参数

参数

说明

innodb_stats_persistent

是否将命令 ANALYZE TABLE计算得到的 Cardinality值存放到磁盘上。若是,则这样做的好处是可以减少重新计算每个索引的 Cardinality值,例如当 MySQL数据库重启时。此外,用户也可以通过命令 CREATE TABLE和 ALTER TABLE的选项 STATS PERSISTENT来对每张表进行控制。默认值:OFF

innodb_stats_on_metadata

当通过命令 SHOW TABLE STATUS、 SHOW INDEX及访问INFORMATION SCHEMA架构下的表 TABLES和 STATISTICS时,是否需要重新计算索引的 Cardinality值。默认值:OFF

innodb stats_persistent_ sample_ pages

若参数 innodb_stats_persistent设置为ON,该参数表示 ANALYZETABLE更新 Cardinality t值时每次采样页的数量。默认值:20

innodb_stats_transient_sample_pages

该参数用来取代之前版本的参数 innodb_stats_sample_pages,表示每次采样页的数量。默认值为:8

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
监控 关系型数据库 MySQL
10亿数据如何最快速插入MySQL:技术干货分享
【8月更文挑战第2天】在大数据时代,处理并快速插入数十亿条数据到MySQL数据库是许多企业面临的关键挑战。本文将深入分享一系列高效的技术策略和实战经验,帮助读者优化这一过程,确保数据能够快速、准确地进入数据库系统。
186 1
|
5天前
|
监控 关系型数据库 MySQL
MySQL自增ID耗尽应对策略:技术解决方案全解析
在数据库管理中,MySQL的自增ID(AUTO_INCREMENT)属性为表中的每一行提供了一个唯一的标识符。然而,当自增ID达到其最大值时,如何处理这一情况成为了数据库管理员和开发者必须面对的问题。本文将探讨MySQL自增ID耗尽的原因、影响以及有效的应对策略。
18 3
|
1月前
|
XML 关系型数据库 MySQL
MySQL 导出某些数据的技术详解
MySQL 导出某些数据的技术详解
122 2
|
2月前
|
存储 关系型数据库 MySQL
技术解析:MySQL中取最新一条重复数据的方法
以上提供的两种方法都可以有效地从MySQL数据库中提取每个类别最新的重复数据。选择哪种方法取决于具体的使用场景和MySQL版本。子查询加分组的方法兼容性更好,适用于所有版本的MySQL;而窗口函数方法代码更简洁,执行效率可能更高,但需要MySQL 8.0及以上版本。在实际应用中,应根据数据量大小、查询性能需求以及MySQL版本等因素综合考虑,选择最合适的实现方案。
355 6
|
1月前
|
关系型数据库 MySQL 数据库
MySQL技术深度解析:每次最大插入条数探秘
MySQL技术深度解析:每次最大插入条数探秘
47 0
|
1月前
|
关系型数据库 MySQL 数据库管理
MySQL技术指南:如何更改数据字段的前几位数字
MySQL技术指南:如何更改数据字段的前几位数字
53 0
|
1月前
|
消息中间件 监控 关系型数据库
MySQL数据实时同步到Elasticsearch:技术深度解析与实践分享
在当今的数据驱动时代,实时数据同步成为许多应用系统的核心需求之一。MySQL作为关系型数据库的代表,以其强大的事务处理能力和数据完整性保障,广泛应用于各种业务场景中。然而,随着数据量的增长和查询复杂度的提升,单一依赖MySQL进行高效的数据检索和分析变得日益困难。这时,Elasticsearch(简称ES)以其卓越的搜索性能、灵活的数据模式以及强大的可扩展性,成为处理复杂查询需求的理想选择。本文将深入探讨MySQL数据实时同步到Elasticsearch的技术实现与最佳实践。
79 0
|
2月前
|
SQL 关系型数据库 MySQL
MySQL技术安装配置、数据库与表的设计、数据操作解析
MySQL,作为最流行的关系型数据库管理系统之一,在WEB应用领域中占据着举足轻重的地位。本文将从MySQL的基本概念、安装配置、数据库与表的设计、数据操作解析,并通过具体的代码示例展示如何在实际项目中应用MySQL。
87 0
|
3月前
|
SQL 存储 关系型数据库
mysql加索引真的会锁表吗?揭秘背后的技术细节与规避策略
【8月更文挑战第16天】在数据库管理中,添加索引能大幅提升查询效率。MySQL执行此操作时的锁定行为常引起关注。文章详细解析MySQL中索引添加时的锁定机制及其原理。不同存储引擎及SQL语句影响锁定策略:MyISAM需全表锁定;InnoDB提供更灵活选项,如使用`ALTER TABLE... LOCK=NONE`可在加索引时允许读写访问,尽管可能延长索引构建时间。自MySQL 5.6起,在线DDL技术可进一步减少锁定时间,通过`ALGORITHM=INPLACE`和`LOCK=NONE`实现近乎无锁的表结构变更。合理配置这些选项有助于最小化对业务的影响并保持数据库高效运行。
399 4
|
3月前
|
前端开发 数据挖掘 关系型数据库
基于Python的哔哩哔哩数据分析系统设计实现过程,技术使用flask、MySQL、echarts,前端使用Layui
本文介绍了一个基于Python的哔哩哔哩数据分析系统,该系统使用Flask框架、MySQL数据库、echarts数据可视化技术和Layui前端框架,旨在提取和分析哔哩哔哩用户行为数据,为平台运营和内容生产提供科学依据。
222 9