我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何理解MySQL索引cardinalit

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何理解MySQL索引cardinalit

本篇内容主要讲解“如何理解MySQL索引cardinalit”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解MySQL索引cardinalit”吧!

查看一个表的索引:

mysql> show index from rank_item;
+-----------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name           | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| rank_item |          0 | PRIMARY            |            1 | id          | A         |     5665508 |     NULL | NULL   |      | BTREE      |         |               |
| rank_item |          1 | idx_city_category  |            1 | city        | A         |        2713 |     NULL | NULL   |      | BTREE      |         |               |
| rank_item |          1 | idx_city_category  |            2 | category    | A         |        3798 |     NULL | NULL   | YES  | BTREE      |         |               |
| rank_item |          1 | idx_artisan_id     |            1 | artisan_id  | A         |       33916 |     NULL | NULL   | YES  | BTREE      |         |               |
| rank_item |          1 | index_weight       |            1 | weight      | A         |       11680 |     NULL | NULL   | YES  | BTREE      |         |               |
| rank_item |          1 | product_id_plan_id |            1 | product_id  | A         |     1480432 |     NULL | NULL   |      | BTREE      |         |               |
| rank_item |          1 | product_id_plan_id |            2 | plan_id     | A         |     5590288 |     NULL | NULL   | YES  | BTREE      |         |               |
| rank_item |          1 | idx_cat_ci_art     |            1 | category    | A         |        3170 |     NULL | NULL   | YES  | BTREE      |         |               |
| rank_item |          1 | idx_cat_ci_art     |            2 | city        | A         |       11417 |     NULL | NULL   |      | BTREE      |         |               |
| rank_item |          1 | idx_cat_ci_art     |            3 | artisan_id  | A         |       46514 |     NULL | NULL   | YES  | BTREE      |         |               |
| rank_item |          1 | idx_ca_ci_pid_wei  |            1 | category    | A         |        3187 |     NULL | NULL   | YES  | BTREE      |         |               |
| rank_item |          1 | idx_ca_ci_pid_wei  |            2 | city        | A         |       10869 |     NULL | NULL   |      | BTREE      |         |               |
| rank_item |          1 | idx_ca_ci_pid_wei  |            3 | plan_id     | A         |       17403 |     NULL | NULL   | YES  | BTREE      |         |               |
| rank_item |          1 | idx_ca_ci_pid_wei  |            4 | weight      | A         |      659306 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

      上面有一个属性Cardinality,可以通过观察它来评估索引是否合理。它会估计索引中不重复记录,如果这个相对值很小,可能就要评估索引是否有意义。

       查看表的总行数:

mysql> select count(*) as total from rank_item;
+---------+
| total   |
+---------+
| 5581872 |
+---------+

观察以下信息:

id列:Cardinality/total=5608506/5581872=1.005

city列:Cardinality/total=2713/5581872=0.0000486

category列:Cardinality/total=3170/5581872=0.0000568

       列id由于是主键,通过cardinality估算出来的值/总数接近于1;而另外2个索引列,估算出来的值/总数都趋近于0。估算出来的值/总数=占比,我们称占比为相对值。

通过上面表格做一个大胆推测,查询id列是很快,查询另外2列是很慢;现在我们看下相应的执行计划。

mysql> explain select * from rank_item where id=2419;
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table     | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | rank_item | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from rank_item where city=4967;
+----+-------------+-----------+------------+------+-------------------+-------------------+---------+-------+--------+----------+-------+
| id | select_type | table     | partitions | type | possible_keys     | key               | key_len | ref   | rows   | filtered | Extra |
+----+-------------+-----------+------------+------+-------------------+-------------------+---------+-------+--------+----------+-------+
|  1 | SIMPLE      | rank_item | NULL       | ref  | idx_city_category | idx_city_category | 4       | const | 556680 |   100.00 | NULL  |
+----+-------------+-----------+------------+------+-------------------+-------------------+---------+-------+--------+----------+-------+
1 row in set, 1 warning (0.04 sec)

      但是发现都会走索引,而且ref都是const。难道是cardinality不准?是的,因为它是一个预估值!

cardinality是怎么预估的?

      上面提到cardinality是索引中不重复记录的预估值,那么它是怎么实现的呢?由于Mysql的B+索引在每个存储引擎中实现的都不一样,所以cardinality干脆放到存储引擎层面实现的!

对于innodb来说,达到以下2点就会重新计算cardinality

  • 如果表中1/16的数据发生变化 

  • 如果stat_modified_counter>200 000 0000

       这是为什么呢?因为真实环境中,索引的更新可能非常频繁,比如一个表中数据的插入,更新,删除等,每次都去统计cardinality会带来很大的负担;另外如果是一个大表,统计一次可能非常耗时。基于此,采用基于上面2个条件的"抽样"统计的方式。

那上面2种有什么区别呢?

       如果表中1/16数据发生变化则会更新;第2种情况比较特别,如果某一千数据频繁更新,但是数据并没有增加,则第一种无法适用,所以设置stat_modified_counter为发生变化的次数;如果次数达到200 000 0000,也会更新统计值。

那具体是如何采样统计的呢?

  • 获取B+树叶子节点的数据,记为A

  • 随机获得B+树索引中8个叶子节点。统计每个页不同记录的个数,分别记为P1,P2...P8

  • 计算cardinality = (P1+P2+...P8)A/8

从而得出索引中不同记录的数量。从上面可以发现,有2个问题

1、由于是随机采样的方式,所以会出现,连续2次统计,数量都不同。只有在表数据非常少,叶子节点不多于8个时,每次采样都是取到相同的页,统计值才会相同。
2、由于统计值是基于上面2个条件去更新的,可能出现系统运行了一段时间之后,数据发生了很大变化,统计值偏差比较大了,那么索引的效率会下降。

那对于问题2,该怎么处理呢?

手动更新统计值

       如果系统运行一段时间之后,我们可以通过执行下面的sql,重新计算cardinality值。

analyze table tablename;

不过,如果表很大,重新统计可能会非常耗时间,建议对于核心表,在非高峰时段操作

选择性

       现在又回到前面的例子,我们通过观察执行计划发现,不论cardinality大小,相对值大小,发现还是会走索引,那为什么要说对于相对值非常小的不建议建索引呢?这就涉及到一个选择性的问题

       比如有一个用户表,有一列性别sex,现在要查询所以性别为male的用户(假定只有男人-male,女人-female,没有其它不明性别),可能的sql:

select * from user where sex = 'M';

          对于这个sql,虽然sex上有索引,但是执行的时候,读取的数据可能会超过一半,甚至在极端情况下(比如程序员的网站),大部分数据都需要读取,所以还是会走全表扫描,这种数据称为低选择性。反之,如果是高选择性的,建议建索引 ,比如user表中用户,一般来说很少重复;

到此,相信大家对“如何理解MySQL索引cardinalit”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何理解MySQL索引cardinalit

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何理解MySQL的索引技术?

如何理解MySQL的索引技术?在数据库中,索引是一种提高查询效率的重要技术。MySQL作为一种流行的关系型数据库管理系统,其索引技术的运用能够显著提升查询性能。本文将从索引的定义、类型、创建和优化几个方面来解析MySQL的索引技术。首先,索
2023-10-22

深入理解MySQL索引

前言当提到MySQL数据库的时候,我们的脑海里会想起几个关键字:索引、事务、数据库锁等等,索引是MySQL的灵魂,是平时进行查询时的利器,也是面试中的重中之重。可能你了解索引的底层是b+树,会加快查询,也会在表中建立索引,但这是远远不够的,这里列举几个索引常见
深入理解MySQL索引
2017-02-27

MySQL索引原理详解

目录索引是什么索引数据结构树形索引树的动画为什么不是简单的二叉树?为什么不是红黑树?为什么最终选择B+树 而不是B树水平方向可以存放更多的索引key数据量估算叶子节点包含所有的索引字段叶子节点直接包含双向指针,范围查找效率高Hash 索引更
2022-08-19

mysql索引失效如何解决

当MySQL索引失效时,可以尝试以下方法来解决:1. 重新分析表:使用ANALYZE TABLE语句来重新分析表的统计信息,使MySQL重新计算索引的选择性和基数。2. 优化查询语句:检查查询语句的语法、表连接顺序、WHERE条件和排序等方
mysql索引失效如何解决
2024-02-29

mysql如何加索引

如何为 mysql 表格添加索引MySQL 索引是一种数据结构,它可以提高查询性能。它通过对数据列进行排序和分组,从而减少了数据库在执行查询时需要扫描的行数。添加索引的步骤:确定要索引的列:选择经常用于查询的列,尤其是那些用于过滤或排序
mysql如何加索引
2024-06-12

理解MySQL——索引与优化

写在前面:索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点。考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储100条记录。如果没有索引,查询将对整个表进行扫描,最坏的情况下,如果所有
2022-05-13

MySQL索引如何创建和使用索引

创建MySQL索引可以通过以下两种方式:使用CREATE INDEX语句创建索引:CREATE INDEX index_name ON table_name (column_name);例如,要在名为students的表上创建一个名为stu
MySQL索引如何创建和使用索引
2024-03-06

MySQL索引原理

定义索引(Index)是帮助MySQL高效获取数据的数据结构。那么什么数据结构可以用来高效的获取数据呢?查看索引mysql> show index from user;+-------+------------+------------------+-----
MySQL索引原理
2020-02-14

mysql索引如何创建

mysql索引创建指南:确定要索引的列:常被搜索或排序的列。选择索引类型:b-tree索引(范围查询)、哈希索引(等值查询)、全文索引(文本搜索)、空间索引(地理空间搜索)。命名索引:指定有意义的名称。创建索引:使用create index
mysql索引如何创建
2024-08-01

编程热搜

目录