13-6_mysql索引_1_Mysql_Learning_Notes_20180719_13-6

mysql索引_1_Mysql_Learning_Notes

一种在有序数组中查找某一特定元素的搜索算法;
二分查找法的优势是比较少次数,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难,所以二分查找方法适用于不常常变更而查找频繁的有序列表.node

  • innodb 要求汇集索引列都要求是有序自增列.innnodb 是事务型的存储引擎,其中的行老是会被删除并提交,count(*) 相对要慢一些.mysql

    二叉树,binary tree

  • 二叉树的每一个节点至多只有二棵子树(不存在大于2的节点),二叉树的子树有左右有序之分,次序不能颠倒.左子树必定小于根,右子树必定大于根.根节点是子节点的中间节点.算法

4
  1               10

平衡树,平衡二叉树,Self balancing binary search tree

  • 改进的二叉查找树.通常的二叉查找树的查询复杂度是跟目标节点到树根的距离(深度)有关,所以当前节点的深度广泛较大时,查询的均摊复杂度会上升.为了更高效的查询就有了平衡树.
  • 平衡二叉树的特色:
    • 它是一棵空树或其左右两个子树的高度差的绝对值不超过1(好比左边高度是6,右的高度只能是5或7),且左右两个子树也是平衡二叉树.
    • 不平衡的树会经过自旋变成平衡树.
    • 平衡树和二叉查找树最大的区别是:前者是平衡的,后者不必定.
    • 数据库里使用平衡二叉树,若是有插入值很大可能会致使其自旋?.
      Alt textsql

      B树,balanced tree(平衡多叉树)

  • 又称B-树\B_树
  • B树,一个节点能够拥有多于2个的子节点的多叉查找树
  • 适合大量数据的读写操做,广泛运用在数据库和文件系统.
  • 一棵m阶(好比m=4阶)的B树知足如下条件.
    • 树中每一个节点至多有m个(4个)子节点
    • 除根节点和叶子节点外,其它每一个节点至少有m/2个(2个)子节点.
    • 若根节点不是叶子节点,则至少有2个子节点.
    • 全部叶子节点都出如今同一层,叶子节点不包含任何键值信息.
    • 有k个子节点的非叶子节点刚好包含有k-1个键值(索引节点)数据库

      记录中应该用'节点'仍是'结节',baidu了一下,有师兄解释:一个节点是两线相交,中间的点,另外一个结点是最后的点。二叉树好像特别一点,是结点,叶子结点和非叶子节点(但不肯定正确性,我就全部都用节点了)数组

      B+树,与B树不一样点在:

  • 有n棵子树对的节点(node)中含有n-1个关键字(key),每一个关键字不保存数据,只用来索引,全部数据都保存在叶子节点.
  • 全部的叶子节点中包含了所有关键字的信息,及指向含这些关键字记录的指针,且叶子节点自己依关键字的大小自小而大顺序连接.
  • 全部的非叶子节点能够当作是索引的部分,节点中仅含其子树(根节点)中的最大(或最小)关键字.
  • 在MySQL中,为了方便,直接写成BTREEbash

    B+树高度相关性

    高度
    1
    2
    3
    4
  • 以三层B+树为列,最查询3次,平均不到3次就能够查询到结果.查询效率高,XFS文件系统也是使用的B+树,因此优于以前的esx4
  • 怎么看innodb的B+TREE层数?,下面以sysbench_testdata.sbtest2为例查看索引层数:
    • 查看相关系统
      ``sql root@localhost [sysbench_testdata]>show create table sbtest2; | sbtest2 | CREATE TABLEsbtest2(idint(11) NOT NULL AUTO_INCREMENT,kint(11) NOT NULL DEFAULT '0',cchar(120) NOT NULL DEFAULT '',padchar(60) NOT NULL DEFAULT '', PRIMARY KEY (id), KEYk_2(k`)
      ) ENGINE=InnoDB AUTO_INCREMENT=67840915 DEFAULT CHARSET=utf8 |
      1 row in set (0.00 sec)

root@localhost [sysbench_testdata]>select count(id) from sbtest2;
+-----------+
| count(id) |
+-----------+
| 67840914 |
+-----------+
1 row in set (56.87 sec)数据结构

```性能

  • 查看information_schema中相关表信息,注意索引的PAGE_NO和:index_id
root@localhost [sysbench_testdata]>SELECT b.name, a.name, index_id, type, a.space, a.PAGE_NO FROM information_schema.INNODB_SYS_INDEXES a, information_schema.INNODB_SYS_TABLES b WHERE a.table_id = b.table_id AND a.space <> 0 and b.name='sysbench_testdata/sbtest2';
+---------------------------+---------+----------+------+-------+---------+
| name                      | name    | index_id | type | space | PAGE_NO |
+---------------------------+---------+----------+------+-------+---------+
| sysbench_testdata/sbtest2 | PRIMARY |       51 |    3 |    33 |       3 |
| sysbench_testdata/sbtest2 | k_2     |       58 |    0 |    33 |      38 |
+---------------------------+---------+----------+------+-------+---------+
2 rows in set (0.00 sec)

root@localhost [sysbench_testdata]>show global variables like 'innodb_page_size';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+
1 row in set (0.00 sec)
  • 到表的文件系统目录中:cd /data/57mysql/mysql3508/data/sysbench_testdata
#hexdump -s 49216 -n 10 ./sbtest2.ibd
000c040 0300 0000 0000 0000 3300               
000c04a

#hexdump -s 622656 -n 10 ./sbtest2.ibd
0098040 0200 0000 0000 0000 3a00               
009804a
  • 注:hexdump中49216和622656是怎么算出来的?这个数分别对应sbtest2表的两个索引,公式是 page_no * innodb_page_size + 64。PRIMARY:316384+64=49216 k_2:3816384+64=622656 ,同时能够观察hexdump结果中的3300和3a00,此数十六进制为33和3a,转换成十进制为:51和58,分别和information_schema中的index_id对应上了.
  • 能够发现 主键索引(PRIMARY)的PAGE_LEVEL 为 0300,表示这棵二级索引树的高度为 4,k_2索引的PAGE_LEVEL 为 0200,表示这棵二级索引树的高度为 3.

哈希索引,Hash Index

  • 创建在哈希表的基础上,它只对使用了索引中的每一个值的精确查找有用.
  • 对于每一行,存储引擎计算出了被索引的哈希码(Hash Code),它是一个较小的值,而且有可能和其余行的哈希码不一样(对象相等则hashCode必定相等;hashCode相等对象未必相等)
  • 把哈希码保存在索引中,而且保存了一个指向哈希表中的每一行的指针
  • 也叫散列索引.
  • 问题:若是不一样对像产生了相同的hashCode(哈希冲突),如在索引表里没法作到一一对应到记录行?
  • 哈希索引优点:合适大量的等值查询,此种状况效率高于B+TREE
  • HASH Index 缺点:
    • 不支持模糊查询和范围查询
    • 不支持排序
    • 不支持联合索引中的最左匹配规则
    • 只能显式应用于HEAP/MEMORY/NDB表
  • 注意:Innodb内部的自适应哈希索引和此处说的不是一回事.自适应哈希索引是没办法被引用和修改的,innodb自适应哈希索引只能用启用或禁用,没办法指定某一个表使用哈希索引.

什么是索引

至关于书目,用于快速检索mysql索引

  • 优势
    • 提升数据检索效率
    • 提升表间的join效率
    • 利用惟一性索引,保证数据的惟一性.
    • 提交排序和分组效率.
  • 缺点
    • 消耗更多物理存储空间
    • 数据变动时,索引也须要更新,下降更新效率.(更新索引时会致使cpu在sys增高),在5.7以上,能够经过查询获得索引的利用率.

      MySQL 5.7之后怎么查看索引使用状况?
  1. 经过show status like '%Handler_read%'方法查看:总体的
root@localhost [sysbench_testdata]>show status like '%Handler_read%';
+-----------------------+---------+
| Variable_name         | Value   |
+-----------------------+---------+
| Handler_read_first    | 7       |
| Handler_read_key      | 29      |
| Handler_read_last     | 0       |
| Handler_read_next     | 8446377 |
| Handler_read_prev     | 0       |
| Handler_read_rnd      | 20      |
| Handler_read_rnd_next | 8344612 |
+-----------------------+---------+
7 rows in set (0.00 sec)
  • Handler_read_key这个值表明了一个行将索引值读的次数,很低的值代表增长索引获得的性能改善不高,由于索引并不常用。

  • Handler_read_rnd_next 的值高则查询低效,而且应该创建索引补救。这个值是指在数据文件中读下一行的请求数。若是正进行大量的表扫描,Handler_read_rnd_next的值较高,则一般说明表索引不正确或查询没有利用索引

2.查看具体某一个sql的索引使用状况 :

root@localhost [sysbench_testdata]>explain select k from sbtest2 where k=432 limit 2;
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref   | rows   | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
|  1 | SIMPLE      | sbtest2 | NULL       | ref  | k_2           | k_2  | 4       | const | 110944 |   100.00 | Using index |
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

字段说明:
Type:告诉咱们对表所使用的访问方式,主要包含以下集中类型;
◇ all:全表扫描
◇ const:读常量,且最多只会有一条记录匹配,因为是常量,因此实际上只须要读一次;
◇ eq_ref:最多只会有一条匹配结果,通常是经过主键或者惟一键索引来访问;
◇ fulltext:
◇ index:全索引扫描;
◇ index_merge:查询中同时使用两个(或更多)索引,而后对索引结果进行merge 以后再读取表数据;
◇ index_subquery:子查询中的返回结果字段组合是一个索引(或索引组合),但不是一个主键或者惟一索引;
◇ rang:索引范围扫描;
◇ ref:Join 语句中被驱动表索引引用查询;
◇ ref_or_null:与ref 的惟一区别就是在使用索引引用查询以外再增长一个空值的查询;
◇ system:系统表,表中只有一行数据;
◇ unique_subquery:子查询中的返回结果字段组合是主键或者惟一约束;

possible_keys:可能能够利用的索引的名字。这里的索引名字是建立索引时指定的索引昵称;若是索引没有昵称,则默认显示的是索引中第一个列的名字(在本例中,它是“firstname”)。默认索引名字的含义每每不是很明显。  

key:它显示了MySQL实际使用的索引的名字。若是它为空(或NULL),则MySQL不使用索引。  

key_len:索引中被使用部分的长度,以字节计

ref:列出是经过常量(const),仍是某个表的某个字段(若是是join)来过滤(经过key)
的;

rows:MySQL所认为的它在找到正确的结果以前必须扫描的记录数。显然,这里最理想的数字就是1。

  1. 经过performance_schema能够查询到.查看sbtest2表索引状况的查询语句:
root@localhost [sysbench_testdata]>select object_type,object_schema,object_name,index_name,count_star,count_read,COUNT_FETCH from performance_schema.table_io_waits_summary_by_index_usage where object_name='sbtest2';
  • 具体查看过程:
root@localhost [sysbench_testdata]>select object_type,object_schema,object_name,index_name,count_star,count_read,COUNT_FETCH from performance_schema.table_io_waits_summary_by_index_usage where object_name='sbtest2';
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    1697669
Current database: sysbench_testdata

+-------------+-------------------+-------------+------------+------------+------------+-------------+
| object_type | object_schema     | object_name | index_name | count_star | count_read | COUNT_FETCH |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
| TABLE       | sysbench_testdata | sbtest2     | PRIMARY    |          0 |          0 |           0 |
| TABLE       | sysbench_testdata | sbtest2     | k_2        |   76287298 |   76287298 |    76287298 |
| TABLE       | sysbench_testdata | sbtest2     | NULL       |    8344631 |    8344631 |     8344631 |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
3 rows in set (0.00 sec)

root@localhost [sysbench_testdata]>select k from sbtest2 where k=432 limit 2;                                                                                                       
+-----+
| k   |
+-----+
| 432 |
| 432 |
+-----+
2 rows in set (0.00 sec)

root@localhost [sysbench_testdata]>select object_type,object_schema,object_name,index_name,count_star,count_read,COUNT_FETCH from performance_schema.table_io_waits_summary_by_index_usage where object_name='sbtest2';
+-------------+-------------------+-------------+------------+------------+------------+-------------+
| object_type | object_schema     | object_name | index_name | count_star | count_read | COUNT_FETCH |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
| TABLE       | sysbench_testdata | sbtest2     | PRIMARY    |          0 |          0 |           0 |
| TABLE       | sysbench_testdata | sbtest2     | k_2        |   76287300 |   76287300 |    76287300 |
| TABLE       | sysbench_testdata | sbtest2     | NULL       |    8344631 |    8344631 |     8344631 |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
3 rows in set (0.01 sec)

root@localhost [sysbench_testdata]>select k from sbtest2 where id=432 limit 2;                                                                                                               
+-------+
| k     |
+-------+
| 49866 |
+-------+
1 row in set (0.00 sec)

root@localhost [sysbench_testdata]>select object_type,object_schema,object_name,index_name,count_star,count_read,COUNT_FETCH from performance_schema.table_io_waits_summary_by_index_usage where object_name='sbtest2';
+-------------+-------------------+-------------+------------+------------+------------+-------------+
| object_type | object_schema     | object_name | index_name | count_star | count_read | COUNT_FETCH |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
| TABLE       | sysbench_testdata | sbtest2     | PRIMARY    |          1 |          1 |           1 |
| TABLE       | sysbench_testdata | sbtest2     | k_2        |   76287300 |   76287300 |    76287300 |
| TABLE       | sysbench_testdata | sbtest2     | NULL       |    8344631 |    8344631 |     8344631 |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
3 rows in set (0.00 sec)

root@localhost [sysbench_testdata]>

索引使用建议

  • 哪一种状况下应该建立索引
    • 常常检索的列
    • 常常用于表链接的列
    • 常常排序或分组的列
  • 不建议使用索引的状况
    • 基数很低的列
    • 更新频繁但检索不频繁的列
    • BLOB/TEXT等长内容列
    • 不多用于检索的列

汇集索引,clustered index

  • 汇集索引是一种索引,该索引中键值的逻辑顺序决定了表数据行的物理顺序(注:在汇集索引下,数据在物理上按顺序排在数据页上,重复值也排在一块儿,于是在那些包含范围检查(between、<、<=、>、>=)或使用group by或orderby的查询时,一旦找到具备范围中第一个键值的行,具备后续索引值的行保证物理上毗连在一块儿而没必要进一步搜索,避免了大范围扫描,能够大大提升查询速度)
  • 每张表只能建一个汇集索引,除了TokuDB引擎
  • InnoDB中,汇集索引即表,表即汇集索引(注:mysql一个表只支持一个汇集索引。在innodb里面汇集索引就是整个表,表就是汇集索引,由于innodb的汇集索引后面是整行数据,若是主键由多列组成,btree优先按第一列顺序存储,在汇集索引btree里面每一个叶子节点最终存储每行数据,这就是为何在innodb里面没有任何条件count (*),它会优先选择普通索引来完成扫描,而不是采用主键索引,由于若是扫汇集索引,扫描的数据量更大,产生的IO更大,若是扫描普通辅助索引,那么它的数据结构一般来说比主键索引小。)
  • MyISAM 没有汇集索引的概念.
  • InnoDB表中主键必定是汇集索引,但汇集索引不必定是主键.
  • 在汇集索引中不要包含常常修改的列,由于码值修改后,数据行必须移动到新的位置。同时新增数据过于离散随机也不合适.
  • INT/BIGINT(单调顺序列)可优先作为汇集索引
  • mysql 汇集索引的选择顺序:若是有主键则选择主键,没有主键则选择第一个not nullable的惟一索引,没有知足要求的惟一键,最后会使用rowid.,但这个rowid为实例级全局id,因此若是汇集索引若是选择rowid,可能会致使性能下降

    主键索引(PRIMARY KEY)

  • 主键由表中的一个或多个字段组成,它的值用于惟一的标识表中的某一条记录;
  • 在表引用中,主键在一个表中引用来自另外一个表中的特定记录(外键foreign key应用);
  • 保证数据的完整性
  • 加快数据的操做速度;
  • 主键值不能重复,也不能包含null.
  • 主键选择建议:
    • 对业务透明,无心义,免受业务变化影响.
    • 不多修改和删除
    • 最好是自增的
    • 不要具备动态属性(如随机值)
  • MySQL 5.6.9及之后无论索引定义时,有无显示包含主键,实际都会存储主键值,如:c1为主键,索引z,为c2,c3联合索引,但z会存储c1的值,这一特性加:索引扩展(Index Extensions).
    -查询中是基于主键好,仍是惟一索引好?

    惟一索引(UNIQUE KEY)

  • 不容许具备索引值相同的行,从而禁止重复的索引或键值;
  • 严格意义上讲,应该叫惟一约束;
  • 在惟一约束上和主键同样(以MyISAM引擎为表明)
  • 惟一索引容许有空值(null)
  • 一个表只能有一个主键,但能够有多个惟一索引;
  • 惟一索引约束可临时禁用,但主键不行;

    联合索引(Combined Indexes,Multiple-Column Indexes)

  • 多列组成,因此也叫多列索引
  • 字段从左到右排序,如c1,c2,c3的联合索引,首先进行c1排序,c1字段值相同的按c2排序,若是前两列都相同才会按c3排序.
    |c1|c2|c3|
    |-|
    |1|2|2|
    |2|3|2|
    |2|4|2|
    |3|2|0|
    |3|2|2|
  • 适合where条件中的多列组合
  • 有时候,还能够用于避免回表(覆盖索引,须要的数据都在索引覆盖的字段范围内,不须要再去表中取数据,若是使用的覆盖索引,执行计划中的Extra列会显示关键字:using index)
  • MySQL还不支持多列不一样排序规则(8.0起支持)
  • 建议:1.where条件中,常常同时出现的列放在联合索引中;2把选择性(过滤性/基数)大的列放在联合索引的最左边(常常出现的列放在最左边).

    覆盖索引(covering indexes)

  • 经过索引数据结构,便可直接返回数据,不须要回表;
  • 执行计划中的Extra列会显示关键字:using index.

相关文章
相关标签/搜索