Mysql 几种索引方式的区别及适用情况

本贴最后更新于 2423 天前,其中的信息可能已经时移世易

转自 董志峰 Do 的博客

Mysql 目前主要有以下几种索引方式:FULLTEXT,HASH,BTREE,RTREE。

那么,这几种索引有什么功能和性能上的不同呢?

FULLTEXT

即为全文索引,目前只有 MyISAM 引擎支持。其可以在 CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。值得一提的是,在数据量较大时候,现将数据放入一个没有全局索引的表中,然后再用 CREATE INDEX 创建 FULLTEXT 索引,要比先为一张表建立 FULLTEXT 然后再将数据写入的速度快很多。

全文索引并不是和 MyISAM 一起诞生的,它的出现是为了解决 WHERE name LIKE “%word%"这类针对文本的模糊查询效率较低的问题。在没有全文索引之前,这样一个查询语句是要进行遍历数据表操作的,可见,在数据量较大时是极其的耗时的,如果没有异步 IO 处理,进程将被挟持,很浪费时间,当然这里不对异步 IO 作进一步讲解,想了解的童鞋,自行谷哥。

全文索引的使用方法并不复杂:

创建 ALTER TABLE table ADD INDEX FULLINDEX USING FULLTEXT(cname1[,cname2…]);

使用 SELECT * FROM table WHERE MATCH(cname1[,cname2…]) AGAINST ('word' MODE );

其中, MODE 为搜寻方式(IN BOOLEAN MODE ,IN NATURAL LANGUAGE MODE ,IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION / WITH QUERY EXPANSION)。

关于这三种搜寻方式,在这里也不多做交代,简单地说,就是,布尔模式,允许 word 里含一些特殊字符用于标记一些具体的要求,如 + 表示一定要有,-表示一定没有,*表示通用匹配符,是不是想起了正则,类似吧;自然语言模式,就是简单的单词匹配;含表达式的自然语言模式,就是先用自然语言模式处理,对返回的结果,再进行表达式匹配。

对搜索引擎稍微有点了解的同学,肯定知道分词这个概念,FULLTEXT 索引也是按照分词原理建立索引的。西文中,大部分为字母文字,分词可以很方便的按照空格进行分割。但很明显,中文不能按照这种方式进行分词。那又怎么办呢?这个向大家介绍一个 Mysql 的中文分词插件 Mysqlcft,有了它,就可以对中文进行分词,想了解的同学请移步 Mysqlcft,当然还有其他的分词插件可以使用。

HASH

Hash 这个词,可以说,自打我们开始码的那一天起,就开始不停地见到和使用到了。其实,hash 就是一种(key=>value)形式的键值对,如数学中的函数映射,允许多个 key 对应相同的 value,但不允许一个 key 对应多个 value。正是由于这个特性,hash 很适合做索引,为某一列或几列建立 hash 索引,就会利用这一列或几列的值通过一定的算法计算出一个 hash 值,对应一行或几行数据(这里在概念上和函数映射有区别,不要混淆)。在 java 语言中,每个类都有自己的 hashcode()方法,没有显示定义的都继承自 object 类,该方法使得每一个对象都是唯一的,在进行对象间 equal 比较,和序列化传输中起到了很重要的作用。hash 的生成方法有很多种,足可以保证 hash 码的唯一性,例如在 MongoDB 中,每一个 document 都有系统为其生成的唯一的 objectID(包含时间戳,主机散列值,进程 PID,和自增 ID)也是一种 hash 的表现。额,我好像扯远了-_-!

由于 hash 索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。那为什么还需要其他的树形索引呢?

在这里就不自己总结了。引用下园子里其他大神的文章:来自 14 的路 的 MySQL 的 btree 索引和 hash 索引的区别

(1)Hash 索引仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询。
由于 Hash 索引比较的是进行 Hash 运算之后的 Hash 值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证和 Hash 运算前完全一样。
(2)Hash 索引无法被用来避免数据的排序操作。
由于 Hash 索引中存放的是经过 Hash 计算之后的 Hash 值,而且 Hash 值的大小关系并不一定和 Hash 运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算;
(3)Hash 索引不能利用部分索引键查询。
对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。
(4)Hash 索引在任何时候都不能避免表扫描。
前面已经知道,Hash 索引是将索引键通过 Hash 运算之后,将 Hash 运算结果的 Hash 值和所对应的行指针信息存放于一个 Hash 表中,由于不同索引键存在相同 Hash 值,所以即使取满足某个 Hash 键值的数据的记录条数,也无法从 Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。
(5)Hash 索引遇到大量 Hash 值相等的情况后性能并不一定就会比 B-Tree 索引高。
对于选择性比较低的索引键,如果创建 Hash 索引,那么将会存在大量记录指针信息存于同一个 Hash 值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下。

我稍作补充,讲一下 HASH 索引的过程,顺便解释下上面的第 4,5 条:

当我们为某一列或某几列建立 hash 索引时(目前就只有 MEMORY 引擎显式地支持这种索引),会在硬盘上生成类似如下的文件:

| hash 值 | 存储地址
|| 1db54bc745a1 | 77#45b5 |
| 4bca452157d4 | 76#4556,77#45cc… |

hash 值即为通过特定算法由指定列数据计算出来,磁盘地址即为所在数据行存储在硬盘上的地址(也有可能是其他存储地址,其实 MEMORY 会将 hash 表导入内存)。

这样,当我们进行 WHERE age = 18 时,会将 18 通过相同的算法计算出一个 hash 值==> 在 hash 表中找到对应的储存地址==> 根据存储地址取得数据。

所以,每次查询时都要遍历 hash 表,直到找到对应的 hash 值,如(4),数据量大了之后,hash 表也会变得庞大起来,性能下降,遍历耗时增加,如(5)。

BTREE

BTREE 索引就是一种将索引值按一定的算法,存入一个树形的数据结构中,相信学过数据结构的童鞋都对当初学习二叉树这种数据结构的经历记忆犹新,反正我当时为了软考可是被这玩意儿好好地折腾了一番,不过那次考试好像没怎么考这个。如二叉树一样,每次查询都是从树的入口 root 开始,依次遍历 node,获取 leaf。

BTREE 在 MyISAM 里的形式和 Innodb 稍有不同

在 Innodb 里,有两种形态:一是 primary key 形态,其 leaf node 里存放的是数据,而且不仅存放了索引键的数据,还存放了其他字段的数据。二是 secondary index,其 leaf node 和普通的 BTREE 差不多,只是还存放了指向主键的信息.

而在 MyISAM 里,主键和其他的并没有太大区别。不过和 Innodb 不太一样的地方是在 MyISAM 里,leaf node 里存放的不是主键的信息,而是指向数据文件里的对应数据行的信息.

RTREE

RTREE 在 mysql 很少使用,仅支持 geometry 数据类型,支持该类型的存储引擎只有 MyISAM、BDb、InnoDb、NDb、Archive 几种。

相对于 BTREE,RTREE 的优势在于范围查找.

各种索引的使用情况

(1)对于 BTREE 这种 Mysql 默认的索引方式,具有普遍的适用性

(2)由于 FULLTEXT 对中文支持不是很好,在没有插件的情况下,最好不要使用。其实,一些小的博客应用,只需要在数据采集时,为其建立关键字列表,通过关键字索引,也是一个不错的方法,至少我是经常这么做的。

(3)对于一些搜索引擎级别的应用来说,FULLTEXT 同样不是一个好的处理方法,Mysql 的全文索引建立的文件还是比较大的,而且效率不是很高,即便是使用了中文分词插件,对中文分词支持也只是一般。真要碰到这种问题,Apache 的 Lucene 或许是你的选择。

(4)正是因为 hash 表在处理较小数据量时具有无可比拟的素的优势,所以 hash 索引很适合做缓存(内存数据库)。如 mysql 数据库的内存版本 Memsql,使用量很广泛的缓存工具 Mencached,NoSql 数据库 redis 等,都使用了 hash 索引这种形式。当然,不想学习这些东西的话 Mysql 的 MEMORY 引擎也是可以满足这种需求的。

(5)至于 RTREE,至今还没有使用过,它具体怎么样,我就不知道了。有 RTREE 使用经历的同学,到时可以交流下!

  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    675 引用 • 535 回帖
  • Index
    4 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    16 引用 • 53 回帖 • 118 关注
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    4 引用 • 16 回帖 • 3 关注
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    21 引用 • 58 回帖
  • WebSocket

    WebSocket 是 HTML5 中定义的一种新协议,它实现了浏览器与服务器之间的全双工通信(full-duplex)。

    48 引用 • 206 回帖 • 398 关注
  • gRpc
    10 引用 • 8 回帖 • 52 关注
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖 • 227 关注
  • etcd

    etcd 是一个分布式、高可用的 key-value 数据存储,专门用于在分布式系统中保存关键数据。

    5 引用 • 26 回帖 • 492 关注
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    19 引用 • 31 回帖 • 3 关注
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 69 关注
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 427 关注
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    124 引用 • 580 回帖 • 1 关注
  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用 • 28 关注
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 404 关注
  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 383 回帖 • 3 关注
  • 知乎

    知乎是网络问答社区,连接各行各业的用户。用户分享着彼此的知识、经验和见解,为中文互联网源源不断地提供多种多样的信息。

    10 引用 • 66 回帖
  • 智能合约

    智能合约(Smart contract)是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于 1994 年由 Nick Szabo 首次提出。

    1 引用 • 11 回帖 • 10 关注
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖
  • 导航

    各种网址链接、内容导航。

    37 引用 • 168 回帖
  • uTools

    uTools 是一个极简、插件化、跨平台的现代桌面软件。通过自由选配丰富的插件,打造你得心应手的工具集合。

    5 引用 • 13 回帖
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    76 引用 • 421 回帖 • 1 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    106 引用 • 152 回帖 • 1 关注
  • Flutter

    Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。 Flutter 可以与现有的代码一起工作,它正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。

    39 引用 • 92 回帖 • 7 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 512 关注
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    28 引用 • 108 回帖 • 3 关注
  • 招聘

    哪里都缺人,哪里都不缺人。

    189 引用 • 1056 回帖
  • danl
    61 关注