【MySQL技术内幕】5.5-Cardinality值

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL DuckDB 分析主实例,集群系列 8核16GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 【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

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
5月前
|
缓存 关系型数据库 MySQL
在MySQL中处理高并发和负载峰值的关键技术与策略
采用上述策略和技术时,每个环节都要进行细致的规划和测试,确保数据库系统既能满足高并发的要求,又要保持足够的灵活性来应对各种突发的流量峰值。实施时,合理评估和测试改动对系统性能的影响,避免单一措施可能引起的连锁反应。持续的系统监控和分析将对维护系统稳定性和进行未来规划提供重要信息。
276 15
|
监控 关系型数据库 MySQL
10亿数据如何最快速插入MySQL:技术干货分享
【8月更文挑战第2天】在大数据时代,处理并快速插入数十亿条数据到MySQL数据库是许多企业面临的关键挑战。本文将深入分享一系列高效的技术策略和实战经验,帮助读者优化这一过程,确保数据能够快速、准确地进入数据库系统。
526 1
|
12月前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
509 1
|
监控 前端开发 Java
【技术开发】接口管理平台要用什么技术栈?推荐:Java+Vue3+Docker+MySQL
该文档介绍了基于Java后端和Vue3前端构建的管理系统的技术栈及功能模块,涵盖管理后台的访问、登录、首页概览、API接口管理、接口权限设置、接口监控、计费管理、账号管理、应用管理、数据库配置、站点配置及管理员个人设置等内容,并提供了访问地址及操作指南。
|
监控 关系型数据库 MySQL
MySQL自增ID耗尽应对策略:技术解决方案全解析
在数据库管理中,MySQL的自增ID(AUTO_INCREMENT)属性为表中的每一行提供了一个唯一的标识符。然而,当自增ID达到其最大值时,如何处理这一情况成为了数据库管理员和开发者必须面对的问题。本文将探讨MySQL自增ID耗尽的原因、影响以及有效的应对策略。
575 3
|
XML 关系型数据库 MySQL
MySQL 导出某些数据的技术详解
MySQL 导出某些数据的技术详解
576 3
|
存储 关系型数据库 MySQL
技术解析:MySQL中取最新一条重复数据的方法
以上提供的两种方法都可以有效地从MySQL数据库中提取每个类别最新的重复数据。选择哪种方法取决于具体的使用场景和MySQL版本。子查询加分组的方法兼容性更好,适用于所有版本的MySQL;而窗口函数方法代码更简洁,执行效率可能更高,但需要MySQL 8.0及以上版本。在实际应用中,应根据数据量大小、查询性能需求以及MySQL版本等因素综合考虑,选择最合适的实现方案。
1045 6
|
前端开发 数据挖掘 关系型数据库
基于Python的哔哩哔哩数据分析系统设计实现过程,技术使用flask、MySQL、echarts,前端使用Layui
本文介绍了一个基于Python的哔哩哔哩数据分析系统,该系统使用Flask框架、MySQL数据库、echarts数据可视化技术和Layui前端框架,旨在提取和分析哔哩哔哩用户行为数据,为平台运营和内容生产提供科学依据。
1110 9
|
SQL 存储 关系型数据库
mysql加索引真的会锁表吗?揭秘背后的技术细节与规避策略
【8月更文挑战第16天】在数据库管理中,添加索引能大幅提升查询效率。MySQL执行此操作时的锁定行为常引起关注。文章详细解析MySQL中索引添加时的锁定机制及其原理。不同存储引擎及SQL语句影响锁定策略:MyISAM需全表锁定;InnoDB提供更灵活选项,如使用`ALTER TABLE... LOCK=NONE`可在加索引时允许读写访问,尽管可能延长索引构建时间。自MySQL 5.6起,在线DDL技术可进一步减少锁定时间,通过`ALGORITHM=INPLACE`和`LOCK=NONE`实现近乎无锁的表结构变更。合理配置这些选项有助于最小化对业务的影响并保持数据库高效运行。
1437 4

推荐镜像

更多