MySQL索引

MySQL索引

一、 索引的特点

索引的优点

大大加快数据的查询速度

使用分组和排序进行数据查询时,可以显著减少查询时分组和排序的时间

创建唯一索引,能够保证数据库表中每一行数据的唯一性

在实现数据的参考完整性方面,可以加速表和表之间的连接

索引的缺点

创建索引和维护索引需要消耗时间,并且随着数据量的增加,时间也会增加

索引需要占据磁盘空间

对数据表中的数据进行增加,修改,删除时,索引也要动态的维护,降低了维护的速度

创建索引的原则

更新频繁的列不应设置索引

数据量小的表不要使用索引(毕竟总共2页的文档,还要目录吗?)

重复数据多的字段不应设为索引(比如性别,只有男和女,一般来说:重复的数据超过百分之15就不该建索引)

首先应该考虑对where 和 order by 涉及的列上建立索引

二、索引的分类

索引是存储引擎用来快速查找记录的一种数据结构,按照实现的方式类分,主要有Hash索引和B+Tree索引

Hash索引

MySQL索引_第1张图片

B+Tree索引

MySQL索引_第2张图片

按照功能划分,索引划为以下分类:

MySQL索引_第3张图片

单列索引

一个索引只包含单个列,但一个表中可以有多个单列索引;

普通索引:MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一点。

唯一索引与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式:

主键索引:每张表一般都会有自己的主键,当我们在创建表时,MySQL会自动在主键列上建立一个索引,这就是主键索引。主键是具有唯一性并且不允许为NULL,所以他是一种特殊的唯一索引。

组合索引

组合索引也叫复合索引指的是我们在建立索引的时候使用多个字段,例如同时使用身份证和手机号建立索引,同样的可以建立为普通索引或者是唯一索引。
复合索引的使用复合最左原则

全文索引

全文索引的版本、存储引擎、数据类型的支持情况:
MySQL 5.6 以前的版本,只有 MyISAM 存储引擎支持全文索引;
MySQL5.6 及以后的版本,MyISAM 和 InnoDB 存储引擎均支持全文索引;
只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引;

数据量较大时候,现将数据放入一个没有全局索引的表中,然后再用create index创建fulltext索引,要比先为一张表建立fulltext然后再将数据写入的速度快很多;(即先创表再建索引效率更高)

测试或使用全文索引时,要先看一下自己的 MySQL 版本、存储引擎和数据类型是否支持全文索引。

MySQL 中的全文索引,有两个变量,最小搜索长度和最大搜索长度,对于长度小于最小搜索长度和大于最大搜索长度的词语,都不会被索引。通俗点就是说,想对一个词语使用全文索引搜索,那么这个词语的长度必须在以上两个变量的区间内。这两个的默认值可以使用以下命令查看:

show variables like '%ft%';

MySQL索引_第4张图片

# 参数名称 默认值 最小值 最大值 作用
1 ft_min_word_len 4 1 3600 MyISAM 引擎表全文索引包含的最小词长度
2 ft_query_expansion_limit 20 0 1000 MyISAM引擎表使用 with query expansion 进行全文搜索的最大匹配数
3 innodb_ft_min_token_size 3 0 16 InnoDB 引擎表全文索引包含的最小词长度
4 innodb_ft_max_token_size 84 10 84 InnoDB 引擎表全文索引包含的最大词长度

使用方式

match (col1,col2,...)  against(expr [search_modifier])

测试

-- 创建表的时候添加全文索引
create table t_article (
     id int primary key auto_increment ,
     title varchar(255) ,
     content varchar(1000) ,
     writing_date date -- , 
     -- fulltext (content) -- 创建全文检索
);

-- 插入数据
insert into t_article values(null,"Yesterday Once More","When I was young I listen to the radio",'2021-10-01');
insert into t_article values(null,"Right Here Waiting","Oceans apart, day after day,and I slowly go insane",'2021-10-02'); 
insert into t_article values(null,"My Heart Will Go On","every night in my dreams,i see you, i feel you",'2021-10-03');
insert into t_article values(null,"Everything I Do","eLook into my eyes,You will see what you mean to me",'2021-10-04');
insert into t_article values(null,"Called To Say I Love You","say love you no new year's day, to celebrate",'2021-10-05');
insert into t_article values(null,"Nothing's Gonna Change My Love For You","if i had to live my life without you near me",'2021-10-06');
insert into t_article values(null,"Everybody","We're gonna bring the flavor show U how.",'2021-10-07');

-- 建索引
-- 修改表结构添加全文索引
alter table t_article add fulltext index_content(content);
-- 直接添加全文索引
create fulltext index index_content on t_article(content);

-- 使用
-- 没有结果 innodb默认最小索引为3 ,单词数需要大于等于3
select * from t_article where match(content) against('yo'); 
-- 有结果                                                     
select * from t_article where match(content) against('you');

MySQL索引_第5张图片

上述结果我们可以看到,查询不区分大小写

空间索引

MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型
空间索引是对空间数据类型的字段建立的索引,MYSQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING、POLYGON
MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。
创建空间索引的列,必须将其声明为NOT NULL
空间索引一般是用的比较少,了解即可。

类型 含义 说明
Geometry 空间数据 任何一种空间类型
Point 坐标值
LineString 线 有一系列点连接而成
Polygon 多边形 由多条线组成

聚集索引和非聚集索引

聚集索引:叶子节点存放完整的数据

非聚集索引:叶子节点存放数据的地址

索引相关命令

-- 创建方式
-- 1. create
create [unique][fulltext][spatial] index 索引名 on 表名(列名)
-- 2. alter
alter table 表名 add [unique][fulltext][spatial] index [索引名] (列名)
-- 3.创建表的时候直接指定
create  table tablename(
    name varchar(20),
    geom_point geometry not null comment '经纬度',
    spatial key geom_index(geom_point), -- 空间索引
    [unique][fulltext][spatial] index index_name(name) -- 给name列创建索引
);


-- 删除索引
drop index 索引名 on 表名 
-- 或 
alter table 表名 drop index 索引名

-- 查看表中所有索引 
show index from table_name;

三、索引的原理

1. 概述

一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上
这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度
换句话说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数

MySQL索引_第6张图片

2. 相关算法

2.1 hash算法

MySQL索引_第7张图片

优点:通过字段的值计算的hash值,定位数据非常快

缺点:不能进行范围查找,因为散列表中的值是无序的,无法进行大小的比较。

2.2 二叉树

MySQL索引_第8张图片

特性:分为左子树、右子树和根节点,左子树比根节点值要小,右子树比根节点值要大

缺点:有可能产生不平衡 类似于链表的结构 。

2.3 平衡二叉树

MySQL索引_第9张图片

特点:

  • 它的左子树和右子树都是平衡二叉树
  • 左子树比中间小,右子树比中间值
  • 左子树和右子树的深度之差的绝对值不超过1

缺点:

  • 插入操作需要旋转
  • 支持范围查询,但回旋查询效率较低,比如要查找大于8的,会回旋到父节点7、10。
  • 如果存放几百条数据的情况下,树高度越高,查询效率会越慢

2.4 BTREE树

目前大部分数据库系统及文件系统都采用B-Tree或其变种B+Tree作为索引结构,Btree结构可以有效的解决之前的相关算法遇到的问题。

MySQL索引_第10张图片
B-Tree的数据存储于每个节点;B+TREE真实的数据存在于叶子节点非叶子节点不存储真实的数据,只存储指引搜索方向的数据项

树构建过程

大家可以用如下工具自己构建,可能会了解的更清晰

数据结构可视化(Data Structure Visualizations)

2.4.1 B-TREE(假设每个节点存2个数据)

先存放1,2,每个节点存两个数据,刚好可以存在一个节点

在这里插入图片描述

再存放3,3应该放在2后面,此时该节点存放3个数据应该进行分裂,最中间的提上去,左右两边分裂为子节点

MySQL索引_第11张图片

剩下的添加以此类推,重复上述流程,

  1. 按大小顺序确认存放在哪个节点,左节点小于根节点,右节点大于根节点,同节点按从小到大顺序依次排序。
  2. 如果该节点数据量未达标,直接放入该节点;否则,进行分裂,中间数据移到父节点那,若父节点数据也满了则继续分裂。
2.4.2 B+TREE(假设每个节点存2个数据)

于B-TREE类似

在这里插入图片描述

B+Tree和B-Tree不同点在于,分裂过后,叶子节点仍会保留被分裂出去的数据,同时叶子节点由双向链表存储。

MySQL索引_第12张图片

不同存储引擎使用B+TREE的区别

MyISAM引擎使用B+Tree作为索引结构,索引文件和数据文件是分离的(非聚集),叶节点的data域存放的是数据记录的地址

MySQL索引_第13张图片

InnoDB的主键索引(聚集索引)叶节点的data域存放的是数据,相比MyISAM效率要高一些,但是比较占硬盘内存大小。非主键索引存储的是主键值

MySQL索引_第14张图片

因此下面的问题就有了答案

为什么InnoDB表必须有主键,并且推荐使用整形的自增主键

InnoDB表的设计为必须有一个主键索引,其索引树的叶子节点存储数据,而其他索引(非主键索引)的数据项存储的是主键值,所以必须要维护一个主键索引才能查询到数据。因此,如果表中没有建立主键索引,数据库会帮你从第一列开始查询哪一列的数据没有重复则把他维护成主键索引,如果没有符合要求的则会帮你新建一列隐藏列维护为主键索引。所以主键索引为必须的,自己建总比数据库帮你建效率高。

推荐使用整形的自增主键:因为查找索引的过程中存在许多比较操作,使用整形比较效率总比使用字符串等的,同时整形就算是bigint也就8个字节,而其他数据类型所占字节数多,更加节省空间。而自增由于叶子节点为双向链表顺序排列,非自增的数据需要插入到中间容易造成数据分裂,而自增直接插入到链表最后

为什么非主键索引结构叶子节点存储的是主键值(一致性和节省存储空间

2.4.3 计算BTREE能存储的数据

InnoDB每个节点的数据为16K

show GLOBAL STATUS like '%Innodb_page_size%'

MySQL索引_第15张图片

以3层为假设,查看能够存储多少数据

主键一般为bigint = 8B,指针 = 6B,

第一层一个节点 = 16KB / (8 + 6)B = 1170 个索引

2层每个节点同第一层可以存储1170个索引,1170 *1170 = 1,368,900个索引

3层每个节点布置存储索引,还存储数据,假设大小为1KB, 1368900 * (16KB / 1KB) = 21,902,400 个索引(约2千万数据)

所以即使是千万级别的数据,使用B+TREE也只需要查询3次

四、再谈联合索引

MySQL索引_第16张图片

索引文件的存储是按name,age,position的顺序进行排列的,因此索引必须符合最左匹配原则,若没有使用左边的索引,直接使用右边的索引,索引会失效,比如select * from table where age = 30 and position = 1;,从上面的图我们可以看到,就算找到第一个age=30的节点,但存储age=30节点数据并不连续,后面仍然有age=30的存在,所以无法通过索引判断,必须进行全表扫描。

你可能感兴趣的:(笔记,mysql,mysql,数据库,database)