索引选择性

索引选择性是索引基数(cardinality)与表中数据行数(n_row_in_table)的比值,即

索引选择性=索引基数/数据行

其中cardinality是索引中不重复记录的预估值。

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

SELECT * FROM student WHERE sex='M'

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

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

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,也会更新统计值。

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

  1. 获取B+树叶子节点的数据,记为A
  2. 随机获得B+树索引中8个叶子节点。统计每个页不同记录的个数,分别记为P1,P2...P8
  3. 计算cardinality = (P1+P2+...P8)A/8从而得出索引中不同记录的数量。

从上面可以发现,有2个问题

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

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

手动更新统计值

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

analyze table tb_name;

show table status;

show index from tb_name

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

总结

  1. cardinality代表的是此列中存储的唯一值的个数,如果此列为primary key 则值为记录的行数,如果是复合索引就是唯一组合的个数。
  2. cardinality只是个估计值,并不准确。
  3. cardinality将会作为mysql优化器对语句执行计划进行判定时依据。如果唯一性太小,那么优化器会认为,这个索引对语句没有太大帮助,而不使用索引。
  4. cardinality值越大,就意味着,使用索引能排除越多的数据,执行也更为高效。
  5. cardinality不会自动更新,需要通过analyze table来进行更新。
  6. cardinality的大小影响join时是否选用这个index的判断。
  7. 初建index时,MyISAM的表cardinality的值为null,InnoDB的表cardinality的值大概为行数。
  8. MyISAM与InnoDB对于cardinality的计算方式不同

索引选择性与cardinality的更多相关文章

  1. 0804关于mysql 索引自动优化机制: 索引选择性(Cardinality:索引基数)

    转自http://blog.csdn.net/zheng0518/article/details/50561761 1.两个同样结构的语句一个没有用到索引的问题: 查1到20号的就不用索引,查1到5号 ...

  2. MySQL前缀索引和索引选择性

    有时候需要索引很长的字符列,这会让索引变得大且慢.通常可以索引开始的部分字符,这样可以大大节约索引空间,从而提高索引效率.但这样也会降低索引的选择性.索引的选择性是指不重复的索引值(也称为基数,car ...

  3. mysql索引之四:复合索引之最左前缀原理,索引选择性,索引优化策略之前缀索引

    高效使用索引的首要条件是知道什么样的查询会使用到索引,这个问题和B+Tree中的“最左前缀原理”有关,下面通过例子说明最左前缀原理. 一.最左前缀索引 这里先说一下联合索引的概念.MySQL中的索引可 ...

  4. MySQL索引之前缀索引和索引选择性

    有时需要索引很长的字符列,它会使索引变大而且变慢.一个策略就是模拟哈希索引.但是有时这也不够好,那? 通常可以索引开始的几个字符,而不是全部值,以节约空间并得到好的性能.这使索引需要的空间变小,但是也 ...

  5. [慢查优化]建索引时注意字段选择性 & 范围查询注意组合索引的字段顺序

    文章转自:http://www.cnblogs.com/zhengyun_ustc/p/slowquery2.html 写在前面的话: 之前曾说过"不要求每个人一定理解 联表查询(join/ ...

  6. 【转】mysql的cardinality异常,导致索引不可用

    转自:http://ourmysql.com/archives/1343 前段时间,一大早上,就收到报警,警告php-fpm进程的数量超过阈值.最终发现是一条sql没用到索引,导致执行数据库查询慢了, ...

  7. 0103MySQL中的B-tree索引 USINGWHERE和USING INDEX同时出现

    转自博客http://www.amogoo.com/article/4 前提1,为了与时俱进,文中数据库环境为MySQL5.6版本2,为了通用,更为了避免造数据的痛苦,文中所涉及表.数据,均来自于My ...

  8. MYSQL索引结构原理、性能分析与优化

    [转]MYSQL索引结构原理.性能分析与优化 第一部分:基础知识 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里, 不用一页一页 ...

  9. 【转】MySQL索引背后的数据结构及算法原理

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

随机推荐

  1. window下的开发环境:常用软件

    window下的开发环境:常用软件 Visio 2010  - 产品设计 xmind        -产品设计 Axure       -产品设计 Edraw max 7.3(破解版)  -产品设计 ...

  2. FindBugs——帮助查找隐藏的bug

    FindBugs 1.什么是FindBugs FindBugs 是一个静态分析工具,它检查类或者 JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题.有了静态分析工具,就可以在不实际运行程序 ...

  3. 使用uiautomatorviewer获取元素

    1.进入以下目录,Androidsdk-tools,双击uiautomatorviewer.bat,然后弹出UI Automator Viewer窗口,按截图操作, 获取当前页面,然后点击相应的元素, ...

  4. 给定1-a的随机数生成器,产生1-b的随机数生成器

    转自http://www.code123.cc/959.html 先给出一个例子,后面会有扩展 题目 给你一个能生成1到5随机数的函数,用它写一个函数生成1到7的随机数. (即:使用函数rand5() ...

  5. Vim step by step

    @1: VIM中非常迷人的功能: D------->从当前位置开始删除,直到当前行结束 cw------->修改游标所在的单词,修改范围从游标位置到单词结尾. 一个替换一个用r,一个替换多 ...

  6. SQL Server 数据分页查询

    最近学习了一下SQL的分页查询,总结了以下几种方法. 首先建立了一个表,随意插入的一些测试数据,表结构和数据如下图: 现在假设我们要做的是每页5条数据,而现在我们要取第三页的数据.(数据太少,就每页5 ...

  7. PL/SQL编程-块编程

    (1). 简单分类                           |————过程(存储过程)                           |                        ...

  8. XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem A. Arithmetic Derivative

    题目:Problem A. Arithmetic DerivativeInput file: standard inputOutput file: standard inputTime limit: ...

  9. HYSBZ - 2818 Gcd (莫比乌斯反演)

    莫比乌斯反演的入门题,设 \(F(x): gcd(i,j)\%x=0\) 的对数,\(f(x): gcd(i,j)=x\)的对数. 易知\[F(p) = \lfloor \frac{n}{p} \rf ...

  10. Java线程的几个概念

    线程的生命周期: 新建状态:用new语句创建的线程对象处于新建状态,此时它和其它的java对象一样,仅仅在堆中被分配了内存 就绪状态:当一个线程创建了以后,其他的线程调用了它的start()方法,该线 ...