索引那些事儿----基于Mysql

做~自己de王妃 提交于 2020-02-07 03:38:59



武汉加油!!!

背景

数据库是什么? 这个问题大家都知道吧, 用来存放数据的, 生活中你在银行中存的金额, 或者一个户籍所中存放的户籍以及个人信息, 在比如一个学校的学生信息等等, 这些都存放在我们的数据库里面. 对不数据库中的数据一般采用一些DML语句(insert, update, delete)来进行数据操作. 想要查看数据库里面的数据使用select语句进行数据的查询.

对于数据在数据库里面的存放, 可以简单理解为类似Excel表格, 表格里面每一行代表一条数据. 一个Sheet页来代表一类数据.
一个例子 现在我们有一张excel表格, 里面存放了一个学校的学生信息, 包含学号, 姓名, 班级,年级等等信息

  • 如果, 如果这张表里面只存放了较少的数据(几十条, 或者十几条), 那现在让你找到关于张三学生的信息, 我们便开始从上到下或者从下到上开始浏览每一行数据, 直到找到张三, 便完成了数据的查询.
  • 但是, 数据量大了, 这个excel存放了成千上万条数据, 再让你找出来张三, 你还是需要从上到下, 或者从下到上开始找张三, 这一次因为数据变多了, 导致你可能一眼找到张三, 可能要浏览一段时间才能找出来张三.

上面的例子, 便是一个数据查询经典的问题, 那么如何解决这个问题呢? 通过索引即可

另一个例子 张三买了一本书《钢铁是怎样炼成的》看完了一遍之后, 时隔半年突然想起了人最宝贵的东西是生命.生命对人来说只有一次.因此,人的一生应当这样度过:当一个人回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧.. 但是忘记了后半句, 只记得是在某一章(我记得是好像是在整书结尾来着), 然后张三通过目录找到了这一章, 很快便从这一章里面找到了这句话的后半句.

那么这个目录便可以理解为一个索引, 最主要的目的就是加快查询的速度

索引

在上面通过两个生活中的例子, 描述了索引是什么以及索引的功能, 在我们的数据库中, 道理也是一样的,
索引: 索引用于快速找出在某个列中有一特定值的行,不使用索引,MySQL必须从第一条记录开始读完整个表,直到找出相关的行,表越大,查询数据所花费的时间就越多,如果表中查询的某列有一个索引,MySQL能够快速到达一个位置去搜索数据文件,那么将会节省很大一部分时间
索引存储类型: 当把某一列作为索引的时候, 数据查询就变成了 先找索引, 再根据索引找这一条数据. 为了进一步提升所以的查询效率, 就引入了一些数据结构算法来提升效率MySQL中的索引的存储类型有两种:BTREE、HASH。 也就是用树或者Hash值来存储该字段

  • 优点:
    • 理论上任何字段类型都可以被建立索引.
    • 显著提高查询的速度
  • 缺点:
    • 索引的创建需要消耗时间, 并且索引也需要维护, 维护的也会增加工作量
  • 何时使用 :
    • 对于经常作为查询条件的字段优先建立索引
    • 数据经常变动的表避免过多建立索引
    • 数据量较小的表, 尽可能不去建立索引, 因为由于数据较少可能查询全部花费的时间比遍历索引时间更少.

存储引擎

对于Mysql首先要知道的是:索引是在存储引擎中实现的,也就是说不同的存储引擎,会使用不同的索引, 所以先来认识一下mysql几种存储引擎.

MySQL有一个被称为“Pluggable Storage Engine Architecture”(可替换存储引擎架构)的特性,也就意味着MySQL数据库提供了多种存储引擎。用户可以根据不同的需求为数据表选择不同的存储引擎,用户也可以根据自己的需要编写自己的存储引擎。

存储引擎种类
引擎名称 解释
CSV 基于 CSV 格式文件存储数据(应用于跨平台的数据交换)
Archive 将数据压缩后进行存储,非常适合存储大量的独立的,作为历史记录的数据,但是只能进行插入查询操作
Falcon 一种新的存储引擎,支持事物处理
Memory 内存存储引擎,拥有极高的插入,更新和查询效率。但是会占用和数据量成正比的内存空间。只在内存上保存数据,意味着数据可能会丢失
MRG_MyISAM(MERGE) 将多个表联合成一个表使用,在超大规模数据存储时很有用
ISAM MyISAM的前身,MySQL5.0以后不再默认安装
MyISAM 高速引擎,拥有较高的插入,查询速度,但不支持事务
InnoDB 5.5版本后MySQL的默认数据库,支持事务和行级锁定,比MyISAM处理速度稍慢

表格中列举的是Mysql支持的几种存储引擎的, 其中后两种是生产开发中使用最多的方案, 下面我们重点介绍一下.

MyISAM引擎

这种引擎又可以细分为动态, 静态, 压缩三种:

  • 静态MyISAM:如果数据表中的各数据列的长度都是预先固定好的,服务器将自动选择这种表类型。因为 数据表中每一条记录所占用的空间都是一样的,所以这种表存取和更新的效率非常高。

  • 动态MyISAM:如果数据表中出现varcharxxxtext或xxxBLOB字段时,服务器将自动选择这种表类型。相对于静态MyISAM,这种表存储空间比较小,但由于每条记录的长度不一,所以多次修改数据后,数据表中的数据就可能离散的存储在内存中,进而导致执行效率下降。同时,内存中也可能会出现很多碎片。因此,这种类型的表要经常用optimize table 命令或优化工具来进行碎片整理

  • 压缩MyISAM:以上说到的两种类型的表都可以用myisamchk工具压缩。这种类型的表进一步减小了占用的存储,但是这种表压缩之后不能再被修改。另外,因为是压缩数据,所以这种表在读取的时候要先时行解压缩。

  • 优点: 有着较高的查询和写入速度, 独立于操作系统, 不受 win 和linux的限制

    • 适用于选择密集型的表。MyISAM存储引擎在筛选大量数据时非常迅速,插入密集型的表。MyISAM的并发插入特性允许同时选择和插入数据。
  • 缺点: 不支持事务

InnoDB引擎

InnoDB表类型可以看作是对MyISAM的更新产品,它提供了事务行级锁机制外键约束的功能, 而且还支持子等增加列AUTO_INCREMENT属性.

不过, 因为它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引, 所以InnoDB的表比MyISAM需要更多的内存和存储.

==备注, 即便在同一个数据库中, 也可以将多种存储引擎混用, 如果需要支持事务, 可以选择InnoDB, 如果该数据库需要一个用于查询的临时表,可以选择MEMORY存储引擎 ==

索引方式

在mysql中 InnoDB和MyISAM引擎默认存储索引的结构为B+Tree, 并且此处B+树索引又分为了两类

  • 聚集索引:指索引项的排序方式和表中数据记录排序方式一致的索引,每张表只能有一个聚集索引,聚集索引的叶子节点存储了整个行数据。
    一个例子: 新华字典, 大家都用过吧, 把字典看做一张具体的数据表, 那么字典的目录就是聚集索引, 并且字典中的拼音目录是根据从a到z来进行排列的, 而且字典中每个字也是按照拼音的首部a-z进行排列的, 这就是索引项的排序方式和表中数据记录排序方式一致。
    真实场景 对于InnoDB引擎表, 通常我们会设置一个主键, 并且多数时候主键是自增的, 那此刻主键便是一个聚集索引, 如果我们对一张数据表没有明确设定主键的时候, 对于InnoDB引擎表又怎么处理呢?

    • 首先, 如果一张表主键被定义了, 那么这个主键就是一个聚集索引
    • 其次, 如果主键没有被显示的定义, 那个该表的第一个唯一非空索引会作为聚集索引
    • 最后, 如果没有主键, 并且唯一索引里面里面也没有合适的, 那么innodb内部会生成一个隐藏的主键作为聚集索引,这个隐藏的主键是一个6个字节的列,该列的值会随着数据的插入自增。
  • 非聚集索引:非聚集索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引。叶子节点并不包含行记录的全部数据。叶子节点除了包含键值以外,还存储了一个指向改行数据的聚集索引建的书签。

在这里我们引入了一个词, 唯一索引有人可能会看不懂, 这个下面即将说到的索引类型的中的一种, 相信看完后续篇幅应该就明白了.

索引类型

为了提高查询的效率, 我们才使用了索引, 但是索引为了应对不同的场景又分为如下几种

  • 单列索引
    • 普通索引
    • 唯一索引
    • 主键索引
  • 组合索引
  • 全文索引
  • 空间索引
单列索引之普通索引

首先要明白的是, 单列索引是指, 一个索引只包含一个列, 但是一个表中可以建立多个单列索引
下面在来看普通索引, 顾名思义, 就是把在某一张数据表中的某一列作为索引, 是Mysql中最基本的索引类型, 没有什么限制并且允许在定义索引的列中插入重复值和空值

创建方式

  • 直接创建索引
CREATE INDEX index_name ON table(column(length));
  • 修改表结构方式创建索引
ALTER TABLE table_name ADD INDEX index_name ON (column(length));
  • 创建表的时候创建索引
CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `column1` char(255) CHARACTER NOT NULL ,
    `column2` text CHARACTER NULL ,
    PRIMARY KEY (`id`),
    INDEX index_name (column1(length))
)
单列索引之唯一索引

普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一, 也就是类似A+B, B+C, C+D这种, 一个数据表中不能出现两个A+B。

创建方式

  • 直接创建索引
CREATE UNIQUE INDEX indexName ON table(column(length));
  • 修改表结构方式创建索引
ALTER TABLE table_name ADD UNIQUE indexName ON (column(length));
  • 创建表的时候创建索引
CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `column1` char(255) CHARACTER NOT NULL ,
    `column2` text CHARACTER NULL ,
    PRIMARY KEY (`id`),
    UNIQUE indexName (column1(length))
)
单列索引之主键索引

可以看做是唯一索引的变种,一个表只能有一个主键不允许有空值。一般是在建表的时候同时创建主键索引

创建方式

  • 直接创建索引
CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `column1` char(255) CHARACTER NOT NULL ,
    `column2` text CHARACTER NULL ,
    PRIMARY KEY (`id`)
)
组合索引

指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合

解说说明最左前缀集合
一个例子 一张表中, 我们把 name, age, address创建索引, 那么索引中就按照name/age/address的顺序放置,
我们在使用的时候可以使用(name, age, address), 或者(name, age)又或者(name, address) 可以看到name就被看做我们的最左前缀.

如果查询的时候使用(age, address), 或者(age, name)这样的顺序是不会根据索引进行查询数据的.也就是称作一种无效查询.

创建方式

ALTER TABLE `table` ADD INDEX name_age_address ((name, age, address); 
全文索引

主要用来查找文本中的关键字,而不是直接与索引中的值相比较, 用在一堆文字中,通过其中的某个关键字等,就能找到该字段所属的记录行, 例如武汉加油, 通过武汉, , 等等关键字可以搜到对应的整条数据.
这种索引方式在很多非关系型的数据库中都有体现, 例如ES, 或者MongoDB

特别注意在mysql中全文索引只有在MyISAM引擎才可以使用, 并且只有char、varchar,text 列上可以创建全文索引

空间索引

空间索引是对空间数据类型的字段建立的索引,MySQL中的空间数据类型有四种,GEOMETRY、POINT、LINESTRING、POLYGON
mysql5.7及以后版本支持, 创建时候使用SPATIAL关键字, 并且涉及的列不能为空.

这种索引, 笔者在目前的生产开发中, 没有遇到过, 避免说的不完整误导大家, 如果有需要的同学可以去参考下面一些文档
空间索引和 ST_Geometry
MySQL5.7版本空间数据参考文档
MySQL支持的空间数据格式
ST_Within

总结

  • 为什么使用索引?
    • 加快查询效率
  • 索引的类别有?
    • 单列索引
      • 普通索引
      • 唯一索引
      • 主键索引
    • 组合索引
    • 全文索引
    • 空间索引

说到了索引, 就不得不提起视图, 那视图又是怎么回事, 移步《视图那些事儿----基于Mysql》

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!