MySQL索引

Posted ych9527

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL索引相关的知识,希望对你有一定的参考价值。

1.索引带来的价值

索引带来的价值,是提高查找的效率,如果有大量的插入、更新、删除则不建议使用索引

2.mysql与磁盘

2.1mysql与磁盘交互的基本单位

  • MySQL 作为一款应用软件,可以想象成一种特殊的文件系统。它有着更高的IO场景,所以,为了提高基本的IO效率, MySQL 进行IO的基本单位是 16KB (InnoDB 存储引擎)
  • 这个基本单位在mysql之中叫做page,即只要发生了数据的交互,哪怕只有1bit,也是需要进行16KB的数据进行交互
  • mysql在服务器启动的时候,会预先加载一大块空间自己进行内存管理,这块空间被称为Buffer Pool(mysql 5.7之中为128KB)
  • page的大小是固定的,数据量有限,不存储数据,就能够存储更多的索引信息,目录page能够管理更多的page,否则目录page管理的页数太少,整颗树的层数就越多,更深,也就意味着从根节点到叶子节点的page更多,即需要更多的IO

2.2为什么交互的基本单位为page

  • 由冯诺依曼体系可知,IO的时间远远大于CPU运算的时间,如果每次要那个数据就加载那个数据,这样IO的次数就提高了,程序所需要的时间就会提高,效率也就降低了
  • 因此,mysql提高效率的本质是减少IO
  • 根据局部性原理,我们查找的数据有很大的概率会在同一个区间之内,即同一个page之内,因此我们进行IO的时候就加载一个page到内存之中,如果下次数据在这个区间之间,就不需要进行IO,提高了程序的效率

2.3默认索引的创建

  • 由下述代码可知
    • 没有设置主键的时候,mysql会生成默认的索引(可不见的)
    • 当设置了主键,mysql会生成默认的主键索引
mysql> create table t(id int,name varchar(10));
mysql> insert into t values(3,'小红');
mysql> insert into t values(1,'小白');
mysql> insert into t values(2,'小蓝');
mysql> select *from t;
+------+--------+
| id   | name   |
+------+--------+
|    3 | 小红   |
|    1 | 小白   |
|    2 | 小蓝   |
+------+--------+

//将id设置为主键 -> 生成主键索引,并且进行排序 
mysql> create table t2(id int primary key,name varchar(10));
mysql> insert into t2 values(3,'小红');
mysql> insert into t2 values(1,'小白');
mysql> insert into t2 values(2,'小蓝');
mysql> select *from t2;
+----+--------+
| id | name   |
+----+--------+
|  1 | 小白   |
|  2 | 小蓝   |
|  3 | 小红   |
+----+--------+

2.4理解单个page

  • mysql中需要管理很多数据文件,管理一个文件,就需要描述和组织这个文件,可以将文件理解成是由一个或者多个page组成的
  • 在mysql之中,不同的page的大小是相同的,都是16KB,page中的数据构成双向链表
  • 当有主键存在时,mysql会默认按照主键进行排序存储
  • 插入数据时,排序可以优化查询的效率,页内部存放数据的模块,实质上也是一个链表的结构,链表的特点也就是增删快,查询修改慢,所以优化查询的效率是必须的
  • 正式因为有序,在查找的时候,从头到后都是有效查找,没有任何一个查找是浪费的,如果运气好,是可以提前结束查找过程的

2.5理解多个page

  • page之中采用的也是链表的形式,如果有很多条数据的话,实际上也是采用的遍历的方式搜索数据,那么应该如何提高搜索的效率呢
    • 通过给数据建立目录的方式来提高搜索的效率(不断的缩减范围,筛选)

  • MySQL 中每一页的大小只有 16KB ,单个Page大小固定,所以随着数据量不断增大, 16KB 不可能存下所有的数据,那么必定会有多个页来存储数据
  • 当对应的页多起来的时候,如果加载每个页去遍历检测的话,时间会非常慢,这时可以给每个页建立起对应的目录,这就是索引
    • 使用一个目录项来指向某一页,而这个目录项存放的就是将要指向的页中存放的最小数据的键值
    • 和页内目录不同的地方在于,这种目录管理的级别是页,而页内目录管理的级别是行
    • 其中,每个目录项的构成是:键值+指针
    • 通过索引,在查找的时候,筛选出满足条件的页加载到内存之中进行查找,这样大大的提高了效率

  • 存在一个目录页来管理页目录,目录页中的数据存放的就是指向的那一页中最小的数据。有数据,就可通过比较,找到该访问那个Page,进而通过指针,找到下一个Page
  • 其实目录页的本质也是页,普通页中存的数据是用户数据,而目录页中存的数据是普通页的地址
  • 小结
    • Page分为目录页和数据页。目录页只放各个下级Page的最小键值
    • 查找的时候,自顶向下找,只需要加载部分目录页到内存,即可完成算法的整个查找过程,大大减少了IO次数
    • 每一层IO一次,再对加载的页进行二分查找,寻找下一层的页的地址,或者对应的数据的地址

3.innoDB在建立索引结构来管理数据的时候,除了B+树,可以使用其他结构吗?

  • 链表
    • 链表是线性结构的,查找的时候需要线性遍历
  • 二叉搜索树?
    • 在某些场景下,二叉搜索树会退化成链表
  • AVL &&红黑树
    • 和B+树相比,B+树的层数更低,每层进行一次IO,树越矮,IO的次数越少,AVL和红黑树相对来说,比B+树更改
  • Hash
    • 官方的索引实现方式中, MySQL 是支持HASH的,不过 InnoDB 和 MyISAM 并不支持.Hash跟进其算法特征,决定了虽然有时候也很快(O(1)),不过,在面对范围查找就明显不行
  • B树
    • B树节点,既有数据,又有Page指针,而B+,只有叶子节点有数据,其他目录页,只有键值和Page指针
      • B+树节点不存储data,这样一个节点就可以存储更多的key。可以使得树更矮,所以IO操作次数更少
    • B+叶子节点,全部相连,而B没有
      • 叶子节点相连,更便于进行范围查找

4.InnoDB 和 MyISAM索引的区别

4.1聚簇索引 VS 非聚簇索引

  • MyISAM 最大的特点是,将索引Page和数据Page分离,也就是叶子节点没有数据,只有对应数据的地址这种用户数据与索引数据分离的索引方案,叫做非聚簇索引
  • InnoDB 的数据和索引是放在一起的,这种用户数据与索引数据在一起索引方案,叫做聚簇索引
//存储引擎使用MyISAM 
create table t3 (id int,name varchar(10))engine=myisam;

//查看索引和数据结构
root@VM-0-6-centos etc]# cd /var/lib/mysql
[root@VM-0-6-centos mysql]# cd base2
[root@VM-0-6-centos base2]# ls

//innoDB和 MyISAM引擎的索引区别

 MyISAM  -> t3.MYD(表中数据) t3.frm(表结构数据)  t3.MYI(索引)
 innoDB -> t2.ibd(索引和用户数据)   t2.frm(表结构数据) 

4.2辅助索引

  • MySQL 除了默认会建立主键索引外,我们用户也有可能建立按照其他列信息建立的索引,一般这种索引可以叫做辅助(普通)索引
  • 对于 MyISAM ,建立辅助(普通)索引和主键索引没有差别,无非就是主键不能重复,而非主键可重复
  • InnoDB 的非主键索引中叶子节点并没有数据,而只有对应记录的key值
    • 所以通过辅助(普通)索引,找到目标记录,需要两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。这种过程,就叫做回表查询
    • 不给辅助索引的叶子节点附上数据,有利于空间的节省
  • 小结
    • MyISAM相对于innoDB 删除和修改的效率会低一点,MyISAM删除和修改除了对数据进行更新外,还需要对内容进行更新。innoDB可以直接在B+树中进行修改,因为叶子节点中存储的是数据
    • MyISAM查找的效率高一些,innoDB有可能需要进行回表查询,所以有可能会慢一点

5.索引操作

5.1创建索引

  • 主键索引(指定主键,mysql自定创建)
    • 一个表中,最多有一个主键索引
    • 主键索引的效率高(主键不可重复)
    • 创建主键索引的列,它的值不能为null,且不能重复
    • 主键索引的列基本上是int
  • 唯一建索引(添加唯一建,mysql自动创建)
    • 一个表中,可以有多个唯一索引
    • 查询效率高
    • 如果在某一列建立唯一索引,必须保证这列不能有重复数据
    • 如果一个唯一索引上指定not null,等价于主键索引(主键和唯一建的区别,主键不可以为空,唯一建可以为空)
  • 创建普通索引
    • 创建方法
      • 在表的最后定义、指定某列为索引
      • 创建完成表后指定某列为普通索引
      • 直接创建一个索引
    • 特点
      • 一个表中可以有多个普通索引,普通索引在实际开发中用的比较多
      • 如果某列需要创建索引,但是该列有重复的值,那么我们就应该使用普通索引
mysql> create table t6(id int ,name char(10),grade int,index(id));在表的最后定义、指定某列为索引
mysql> alter table t6 add index(name);	  创建完成表后指定某列为普通索引
mysql> create index idx_name on t6(grade); 直接创建一个索引
  • 全文索引的创建
    • 当对文章字段或有大量文字的字段进行检索时,会使用到全文索引。MySQL提供全文索引机制,但是有要求,要求表的存储引擎必须是MyISAM,而且默认的全文索引支持英文,不支持中文。如果对中文进行全文检索,可以使用sphinx的中文(coreseek)。innoDB不支持,主要使用在查询多,修改、插入少的时候
    • 只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引
    • fulltext(关键字,关键字…) -> 创建全文索引
//不能使用id作为全文索引,因为id为int类型
mysql> create table t1(id int primary key auto_increment,name char(10),body text,fulltext(name,body))engine=myisam;

//插入数据
mysql> select *from t1;
+----+------+-------------------+
| id | name | body              |
+----+------+-------------------+
|  1 | jim  | how are you       |
|  2 | tom  | im fine           |
|  3 | bob  | today is good day |
+----+------+-------------------+

  • explain查看是否使用全文索引
    • explain 预执行指令,查看结果
mysql> select *from t1 where name like '%j%';
+----+------+-------------+
| id | name | body        |
+----+------+-------------+
|  1 | jim  | how are you |
+----+------+-------------+
1 row in set (0.01 sec)

mysql> explain select *from t1 where name like '%j%'\\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL  -> 没有使用索引
      key_len: NULL
          ref: NULL
         rows: 3
  • 如何使用全文索引
    • 关键字 match(全文索引) against(匹配内容)
mysql> select *from t1 where match(name,body) against('today');
+----+------+-------------------+
| id | name | body              |
+----+------+-------------------+
|  3 | bob  | today is good day |
+----+------+-------------------+

mysql> explain select *from t1 where match(name,body) against('today')\\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
   partitions: NULL
         type: fulltext
possible_keys: name
          key: name -> 使用了全文索引
      key_len: 0
          ref: const
         rows: 1

  • 全文索引注意点
    • 需要注意索引有最小长度和最大长度,小于或者大于规定长度都不会进行索引

参考文章

5.2查询索引

  • 第一种方法: show keys from 表名

  • 第二种方法: show index from 表名

  • 第三种方法:desc 表名

mysql> show keys from t4\\G;
*************************** 1. row ***************************(第一个主键)
Table: t4             <- 表名
Non_unique: 0         <- 如果索引不能包括重复值则为0,如果可以则为1。也就是平时所说的唯一索引
Key_name: PRIMARY     <- 索引的名字
Seq_in_index: 1		  <- 索引中的列序列号,从1开始
Column_name: id		  <- 索引是那个(索引的列名)
Collation: A		  <- 列以什么方式存储在索引中,大概意思就是字符序
Cardinality: 0     	  <- 基数的意思,表示索引中唯一值的数目的估计值
Sub_part: NULL        <-前置索引的意思,如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL
Packed: NULL		  <-指示关键字如何被压缩。如果没有被压缩,则为NULL
Null: 			      <-如果列含有NULL,则含有YES
Index_type: BTREE     <- 以二叉树的形式构建索引
Comment: 
Index_comment:          <- 注释的意思


mysql> desc t6;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(11)  | YES  | MUL | NULL    |       | (key MUL)表示索引
| name  | char(10) | YES  | MUL | NULL    |       |
| grade | int(11)  | YES  | MUL | NULL    |       |
+-------+----------+------+-----+---------+-------+

参考文章

5.3删除索引

  • 第一种方法:删除主键索引:alter table 表名 drop primary key(本质就是删除主键)
  • 第二种方法:其他索引的删除:alter table 表名 drop index 索引名,索引名就是show keys from 表名中的key_name字段
  • 第三种方法:drop index 索引名 on 表名
mysql> alter table t6 drop index id; //删除索引
mysql> desc t6;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(11)  | YES  |     | NULL    |       |
| name  | char(10) | YES  | MUL | NULL    |       |
| grade | int(11)  | YES  | MUL | NULL    |       |
+-------+----------+------+-----+---------+-------+

mysql> drop index name on t6;
mysql> drop index idx_name on t6;
mysql> desc t6;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(11)  | YES  |     | NULL    |       |
| name  | char(10) | YES  |     | NULL    |       |
| grade | int(11)  | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+

5.4索引创建的原则

  • 查询比较频繁的字段应该创建索引
  • 唯一性太差的字段,不适合单独创建索引(插入新的数据,如果重复会需要进行索引更新)
  • 更新非常频繁的字段不适合作为索引
  • 不会再where子句中出现的字段不该创建索引

5.5其它索引了解

  • 复合索引
  • 索引最左匹配原则
  • 索引覆盖

6.总结-什么是索引

  • 数据都是存储在磁盘上的,当使用mysql的时候,会将mysql加载到内存之中
  • mysql会申请大块内存自己进行调配,这块内存叫做buffer pool,mysql5.7中,这个大小为128KB
  • mysql与硬盘交互的大小为16KB,称之为页
  • 如果每次对数据进行查找或者修改都将所有的页加载至内存之中,那么当数据量很大次,就会需要IO很多次,这样程序的效率也会直线降低
  • 索引的价值就在于,将对应的页加载至buff pool中,对这个页进行二分查找,找到范围内的关键字,然后寻找下一个页或者提取数据。这样就可以有选择性的读取某些页,这就是索引
  • 通常索引用的数据结构是B+树,这样,每一层只需要进行一次IO数据都在叶子节点之中,因此树的高度约低,进行的IO次数越少,程序的效率越高

以上是关于MySQL索引的主要内容,如果未能解决你的问题,请参考以下文章

javascript UV Index Monitor App订阅PubNub并显示UV索引值。博文的代码片段。在这里查看项目:https:// githu

c_cpp UV Index Indicator订阅PubNub并使用颜色显示UV索引值。博文的代码片段。在这里查看项目:https:/

部分代码片段

linux中怎么查看mysql数据库版本

活动结果片段索引超出范围:0x20001

从mysql的片段中加载ListView