MySQL 索引及其分类

概述

用过 mysql 的童鞋都知道建立索引的必要性,可是不少人对建立索引的目的仅仅停留于建立索引可以让查询变快

然而,为了达到这个目的,科学合理的建立索引也是非常有必要的

索引能够轻易将查询性能提高几个数量级,而一个“最优”索引有时比一个“好的”索引性能要高两个数量级

在 MySQL 中,索引可以包含一个活多个列的值,因为 MySQL 只能高效地使用索引的最左前缀列,所以包含多个列的索引中列的顺序也十分重要

而创建一个包含两个列的索引和创建两个分别包含一列的索引是大不相同的

索引的类型

MySQL 中,索引的类型有很多类型,能够为不同场景提供更好的性能

索引是在存储引擎层实现的,不同存储引擎的索引工作方式不同,也并不是所有引擎都支持全部的索引类型,而对于同一类索引,不同引擎的底层实现也可能是不同的

B-Tree 索引

大多数 MySQL 存储引擎都支持 B-Tree 索引,也因此,B-Tree 索引是最常用的索引类型,如果未加说明,索引一般都指的是 B-Tree 索引

然而,虽然在创建表时关键字都是 B-Tree,但是各个存储引擎的底层实现可能是不同的,如 NDB 集群存储引擎内部实际上使用了 T-Tree 结构,而 innoDB 使用的 B+ Tree

磁盘 IO 与预读

由于磁盘读取靠的是机械运动,每次都要花费寻道时间、旋转延迟、传输时间三部分时间才能读取数据,总计时间是非常长的,如果针对数据库的动辄十万百万乃至千万级的数据查询,每次几毫秒的时间,结果将会是灾难性的

因此操作系统对此进行了一些优化,每次读取时并不仅仅读取需要的数据,而是把相邻数据全部读取到内存缓冲区中,这样,每次都读取一页数据(4KB 或 8KB),而针对一页上数据的读取,事实上仅进行了一次磁盘 IO 操作

B-Tree 的特性

B-Tree 的结构如下图:

由于 B 树的多分支结构特性,导致树的高度可以大幅下降,这样,如果每个节点都存储一页数据,如果需要访问第三层数据,则只需要进行三次磁盘 IO,这显然大幅的节省了时间

B+ 树与 B 树的区别在于只有叶子节点存储真实数据,其余非叶子结点仅作为指引搜索方向的数据项

这样存储引擎不再需要全表扫描,而是根据每个节点的指引可以快速找到需要的数据

同时,由于 B 树的结构特性,也导致所有的值通常都是按顺序存储的,因此在使用 ORDER BY 操作时,这个索引也可以满足对应的排序需求

多列索引的匹配规则

CREATE TABLE People (
    a    varchar(50)    not null,
    b    varchar(50)    not null,
    c    date        not null,
    d    date        not null,
    e    enum(‘m‘, ‘f‘)    not null,
    key(a, b, c, d)
);

对于上面这个表,创建了四列索引,他们遵循下列规则

  • 最左前缀匹配原则

这是一个非常重要的原则,MySQL 会一直向右匹配直到遇到范围查询(>、<、between、like)

比如查询 a="" and b="2" and c >= 3 and d = 4

在这个查询中,d 是用不到索引的,而如果建立 (a, b, d, c) 则是可以的

同时 where 语句中查询的顺序是可以任意调整的,即 a、b、c、d 的顺序可以任意调整,MySQL 总是按照索引建立的顺序进行查询

  • 最大区分度原则

尽量选择区分度高的列作为索引,或是将其放置在左端,区分度越高,即选出的结果行越少,则实际查询的次数就会越少

  • 索引列不能参与计算

对于 from_unixtime(a) = ‘2014-05-29‘ 这样的查询是不能应用索引的,而应该优化成 a = from_unixtime(‘2014-05-29‘)

比如 a+1>5 只有优化为 a > 4 才会应用索引

  • 必须以最左列开始查询

如果查询 b = 5 and c < 2014 则不会应用索引,这也正是最左前缀匹配原则

  • 不能跳过索引中的列

对于查询 a=5 and c > 2015,由于跳过了 b 列,所以 c 不会应用索引

  • 说明

上述限制存在于 MySQL 5.5 及以前的数据库版本中,未来的版本可能会取消某些限制

然而,可以看到,创建表时怎样选取索引的列,以及他们的排列顺序是非常重要的

哈希索引

简介

CREATE TABLE testhash (
    a varchar(50) not null,
    b varchar(50) not null,
    KEY USING HASH(a)
) ENGINE=MEMORY;

上面创建表的过程中创建了一个哈希索引

顾名思义,哈希索引的底层数据结构是用哈希表实现的,只有精确匹配索引所有列的查询才有效

索引会为每一行数据建立一个很小的哈希码,因此哈希索引占用空间小,执行效率高,但只支持等值查询,而不支持范围查询

同时,由于哈希表并不按照值的大小顺序存储,因此在 ORDER BY 操作中并不会应用该索引,也不支持仅使用索引中部分列进行查找

但是,如果是某些特定适合使用哈希索引的场合,索引所带来的性能提升将非常显著,如经典的“星型” schema,需要关联很多查找表,哈希索引就非常适合查找表的需求

哈希索引与存储引擎

哈希索引是 MEMORY 存储引擎的默认索引方式,MEMORY 引擎同时也支持 B-Tree 索引,目前,在 MySQL 中,只有 MEMORY 引擎显式支持哈希索引

InnoDB 引擎有一个特殊的功能 -- 自适应哈希索引,对于被频繁使用的索引值,InnoDB 引擎会自动在内存中创建一个哈希索引,用户只能通过配置选择是否启用这一特性,一旦启用,该过程将是完全自动,用户无法察觉的

InnoDB 创建的自适应哈希索引和真正的哈希索引并不是一回事,而是在原有的 B-Tree 索引的基础上,将检索的值变成哈希码,以降低磁盘使用

自定义哈希索引

针对不支持哈希索引的存储引擎,用户也可以采用类似 InnoDB 的思路去自定义哈希索引

典型的如将 url 变成 CRC32,可以有效节省磁盘使用,并且提高查询速度

如针对下面的查询:

SELECT id FROM url WHERE url = ‘http://www.techlog.cn/article/list/10182793‘;

这样的查询显然是很耗时的,且如果为 url 创建索引,索引也将非常庞大

优化成以下这样:

SELECT id FROM url WHERE crc32_url = CRC32(‘http://www.techlog.cn/article/list/10182793‘);

这样,我们为 crc32_url 字段创建索引,索引的大小、查询效率都会有显著的提升

但是,这样又需要维护一个新的字段 crc32_url,通过创建触发器,可以自动的添加该字段:

CREATE TABLE pseudohash (
    id    int unsigned NOT NULL auto_increment,
    url    varchar(255) NOT NULL,
    url_crc    int unsigned NOT NULL DEFAULT 0,
    PRIMARY KEY(id)
    KEY(url_crc);
);

DELIMITER //

CREATE TRIGGER pseudohash_crc_ins BEFORE INSERT ON pseudohash FOR EACH ROW BEGIN
SET NEW.url_crc = crc32(NEW.url);
END;
//

CREATE TRIGGER pseudohash_crc_upd BEFORE UPDATE ON pseudohash FOR EACH ROW BEGIN
SET NEW.url_crc = crc32(NEW.url);
END;
//

DELIMITER ;

这样,每当添加或修改 url 字段,触发器会自动更新 url_crc 字段

由于可能存在的哈希冲突,所以直接查询可能会出现多条记录,可以优化为:

SELECT id FROM url WHERE crc32_url = CRC32(‘http://www.techlog.cn/article/list/10182793‘) and url = ‘http://www.techlog.cn/article/list/10182793‘;

空间数据索引(R-Tree)

MyISAM 表支持空间索引,可以用作地理数据存储

与 B-Tree 索引不同,空间数据索引无需前缀查询,他会从所有维度索引数据,可以任意组合查询

但是必须使用 MySQL 的 GIS 相关函数,如 MBRCONTAINS() 来维护数据,然而 MySQL 对 GIS 支持并不完善,所以大部分人不会使用这个特性

PostgreSQL 的 PostGIS 对 GIS 支持很好

全文索引

全文索引查找的是文本中的关键词,而不是比较索引中的值,类似于搜索引擎

使用 MATCH AGAINST 操作进行索引,目前不支持中文

其他索引

还有很多第三方存储引擎使用其他不同类型的数据结构来存储索引,他们各自有不同的适用场景和优势

时间: 2024-10-11 07:07:28

MySQL 索引及其分类的相关文章

mysql 索引分类以及用途分析

MySQL索引分为普通索引.唯一性索引.全文索引.单列索引.多列索引等等.这里将为大家介绍着几种索引各自的用途. 一. MySQL: 索引以B树格式保存 Memory存储引擎可以选择Hash或BTree索引,Hash索引只能用于=或<=>的等式比较. 1.普通索引:create index on Tablename(列的列表) alter table TableName add index (列的列表) create table TableName([...], index [IndexNam

mysql 索引分类

在数据库表中,对字段建立索引可以大大提高查询速度.通过善用这些索引,可以令 MySQL的查询和运行更加高效.索引是快速搜索的关键.MySQL索引的建立对于MySQL的高效运行是很重要的.下面介绍几种常见的MySQL索引类型. 1.普通型索引 这是最基本的索引类型,而且它没有唯一性之类的限制.普通索引可以通过以下几种方式创建: (1)创建索引,例如CREATE INDEX 索引的名字 ON tablename (列名1,列名2,...); (2)修改表,例如ALTER TABLE tablenam

MySQL 索引分类和每个作用

对一些大型的网站,索引的作用很明显,MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 1.普通索引 这是最基本的索引,它没有任何限制 增加索引 CREATE INDEX indexName ON student(username(100)); 修改索引 ALTER table tableName ADD INDEX student(username(100)) 删除索引 DROP INDEX [indexName] ON student; 2,唯一索

MySql 索引使用

田老师,乐学医考的试题统计, 做题记录有50w条,统计要20多分钟 经过优化sql和建立索引,响应只需0.1秒 SHOW INDEX FROM `exam_question_record`; ALTER TABLE `exam_question_record` ADD INDEX index_qid_status (`qst_id`,`status`) 查看索引  SHOW INDEX FROM `exam_question_record`; 1.添加PRIMARY KEY(主键索引) mysq

Mysql索引基础

Mysql索引基础 基本概念: 索引是一种特殊的数据库结构,可以用来快速查询数据库表中的特定记录.索引是提高数据库性能的重要方式.索引创建在表上,是对数据库表中一列或多列的值进行排序的一种结构.可以提高查询速度.MySQL中,所有的数据类型都可以被索引. 索引的优点: 增加查询速度 利用索引的唯一性来控制记录的唯一性 降低查询中分组和排序的时间 可以加速表与表之间的连接 索引的缺点: 存储索引占用磁盘空间 执行数据修改操作(INSERT.UPDATE.DELETE)产生索引维护 每次修改表结构都

Mysql 索引优化

索引的存储分类MyISAM 存储引擎的表数据和索引是自动分开存储的,各自是独一的一个文件Innodb 存储引擎的表数据和索引是存储在同一个表空间里面,但可以由多个文件构成.Mysql 目前不支持函数索引,但是能对列的前面某一部分进行索引例如 name 字段,可以只取 name 的前 4 个字符进行索引,可降低索引文件大小.Mysql> create index ind_company_name on company(name(4));说明:ind_company_name 索引名,company

sql学习笔记(15)-----------MySQL 索引与优化总结

索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点. 考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储100条记录.如果没有索引,查询将对整个表进行扫描,最坏的情况下,如果所有数据页都不在内存,需要读取10^4个页面,如果这10^4个页面在磁盘上随机分布,需要进行10^4次I/O,假设磁盘每次I/O时间为10ms(忽略数据传输时间),则总共需要100s(但实际上要好很多很多).如果对之建立B-Tree索引,则只需要进行log100(10^6

MySQL索引篇

innodb索引概念 总结记录下innodb的索引概念,以备查看 innodb索引分类: 聚簇索引(clustered index) 1)  有主键时,根据主键创建聚簇索引 2)  没有主键时,会用一个唯一且不为空的索引列做为主键,成为此表的聚簇索引 3) 如果以上两个都不满足那innodb自己创建一个虚拟的聚集索引 辅助索引(secondary index) 非聚簇索引都是辅助索引,像复合索引.前缀索引.唯一索引 myisam索引:因为myisam的索引和数据是分开存储存储的,myisam通过

八、MySQL索引

索引用于快速找到某个列中有一特定值的行.不使用索引,MySQL必须从第1条记录开始读完整个表,直到找到相关的行.表越大,查询所花费的时间越多.如果表中查询的列有一个索引,MySQL能快速到达某个位置去搜索数据文件,而不必查看所有数据. 8.1.索引简介 索引的含义与特点 索引是一个单独的.存储在磁盘上的数据库结构,它们包含着对数据表里所有记录的引用指针.使用索引用于快速找到某个或多个列中有一特定值的行,所有MySQL列类型都可以被索引,对相关列使用索引是提高查询操作速度的最佳途径. 索引实在存储