MySQL之索引初识篇:索引机制、索引分类、索引使用与管理综述)
引言由于MySQL是作为存储层部署在业务系统的最后端所有的业务数据最终都要入库落盘但随着一个项目在线上运行的时间越来越久数据库中的数据量自然会越来越多而数据体积出现增长后当需要从表查询一些数据时效率会越发低下。在正常情况下表的查询性能和数据量是成反比的也就是数据越多查询越慢。这是什么原因导致的呢由于MySQL默认的查询方式导致的举个例子~SELECT * FROM zz_student; ---------------------------------- | student_id | name | sex | height | ---------------------------------- | 1 | 竹子 | 男 | 185cm | | 2 | 熊猫 | 女 | 170cm | | 3 | 子竹 | 男 | 182cm | | 4 | 棕熊 | 男 | 187cm | | 5 | 黑豹 | 男 | 177cm | | 6 | 脑斧 | 男 | 178cm | | 7 | 兔纸 | 女 | 165cm | ---------------------------------- SELECT * FROM zz_student WHERE name 脑斧;上面给出了一张学生表其中有七位学生信息而此时要查询姓名为「脑斧」的学生信息时MySQL底层是如何检索数据的呢会触发磁盘IO对表中的数据进行逐条读取并判断也就是说在这里想要查找到符合要求的数据至少要经过六次磁盘IO才能检索到目标暂且先不考虑局部性读取原理与随机IO。• 那假设这个表中有1000W条数据呢要查的目标数据位于表的900W行以后怎么办岂不是要触发几百万次磁盘IO才能检索到数据啊如果真的这样去干其效率大家可想而知。在这种情况下又该如何去提升数据库的查询性能呢因为查询往往都是一个业务系统中最频繁的操作一般项目的写/读请求比例都遵循三七定律也就是30%的请求会涉及到写库操作另外70%则属于查库类型的操作。在思考如何提升查询性能前咱们不妨先回想一下小时候的场景小时候由于刚接触汉字很多字都不认识所以通常每个人小时候都会拥有一本「新华字典」但一本字典那么厚我们是一页页去翻的吗并不是字典中有目录索引我们可以根据音节、偏旁等方式查找不认识的字。新华字典在「新华字典」中一页页翻找某个汉字就类似于我们前面给出的全表扫描方式效率特别特别低而通过目录索引则能够在很短的时间内找到目标汉字。既然字典中都存在目录索引页能帮助小时候的我们快速检索汉字那这个思想能否应用到数据库中来呢答案是当然可以并且MySQL也提供了索引机制索引是数据库中的核心组件之一一张表中建立了合适的索引后往往在面对海量数据查询时能够事半功倍接下来一起聊一聊MySQL的索引。索引机制会分为上、中、下三篇进行阐述大致内容如下《上篇索引初识篇》主要讲解索引的概述、分类、使用与管理等《中篇索引应用篇》主要阐述索引优劣分析、建立索引的原则、索引失效的场景、如何正确的使用索引、索引优化机制等《下篇索引原理篇》则主要讲述索引的底层实现、BTree、Hash数据结构、聚簇索引和非聚簇索引实现、索引查询原理、索引管理实现等一、MySQL索引机制概述对于MySQL索引机制的作用经过上述「新华字典」的案例后可得知索引就是用来帮助表快速检索目标数据的。此时先来简单回顾一下MySQL中索引是如何使用的呢首先需要创建索引MySQL可以通过CREATE、ALTER、DDL三种方式创建一个索引。1.1、MySQL索引的创建方式• ①使用CREATE语句创建CREATE INDEX indexName ON tableName (columnName(length) [ASC|DESC]);这种创建方式可以给一张已存在的表结构添加索引其中需要指定几个值•indexName当前创建的索引创建成功后叫啥名字。•tableName要在哪张表上创建一个索引这里指定表名。•columnName要为表中的哪个字段创建索引这里指定字段名。•length如果字段存储的值过长选用值的前多少个字符创建索引。•ASC|DESC指定索引的排序方式ASC是升序DESC是降序默认ASC。当然上述语句中的INDEX也可更改为KEY作用都是创建一个普通索引而对于其他的索引类型这点在后续的索引分类中再聊。• ②使用ALTER语句创建ALTER TABLE tableName ADD INDEX indexName(columnName(length) [ASC|DESC]);这里的参数都相同所以不再重复赘述。• ③建表时DDL语句中创建CREATE TABLE tableName( columnName1 INT(8) NOT NULL, columnName2 ...., ....., INDEX [indexName] (columnName(length)) );这种方式就比较适合在库表设计时已经确定了索引项的情况下建立。1.2、查询、删除、指定索引但不管通过哪种方式建立索引本质上创建的索引都是相同的当索引创建完成后可通过SHOW INDEX FROM tableName;这条命令查询一个表中拥有的索引如下CREATE TABLE zz_user ( user_id int(8) NOT NULL AUTO_INCREMENT, user_name varchar(255) NULL DEFAULT , user_sex varchar(255) NULL DEFAULT , user_phone varchar(255) NULL DEFAULT , PRIMARY KEY (user_id) USING BTREE ) ENGINE InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci ROW_FORMAT Compact;在上述的建表SQL中为user_id创建了一个主键索引然后来查一下当前表的索引信息索引查询简单的概述一下查询后每个字段的含义• ①Table当前索引属于那张表。• ②Non_unique目前索引是否属于唯一索引0代表是的1代表不是。• ③Key_name当前索引的名字。• ④Seq_in_index如果当前是联合索引目前字段在联合索引中排第几个。• ⑤Column_name当前索引是位于哪个字段上建立的。• ⑥Collation字段值以什么方式存储在索引中A表示有序存储NULL表无序。• ⑦Cardinality当前索引的散列程度也就是索引中存储了多少个不同的值。• ⑧Sub_part当前索引使用了字段值的多少个字符建立NULL表示全部。• ⑨Packed表示索引在存储字段值时以什么方式压缩NULL表示未压缩• ⑩Null当前作为索引字段的值中是否存在NULL值YES表示存在。• ⑪Index_type当前索引的结构BTREE, FULLTEXT, HASH, RTREE。• ⑫Comment创建索引时是否对索引有备注信息。这条命令在后续排除问题、性能调优时会有不小的作用比如可以通过分析其中的Cardinality字段值如果该值少于数据的实际行数那目前索引有可能失效对于这些后续排查篇和SQL优化篇再聊。OK~到这里了解了一下索引相关的创建、查询命令接着再看看删除、强制使用命令。在MySQL中并未提供修改索引的命令也就说当你建错了索引只能先删再重新建立一次删除索引的语句如下DROP INDEX indexName ON tableName;当然当建立了一条索引后也可以强制性的为SELECT语句指定索引如下SELECT * FROM table_name FORCE INDEX(index_name) WHERE .....;FORCE INDEX关键字可以为一条查询语句强制指定走哪个索引查询但要牢记的是如果当前的查询SQL压根不会走指定的索引字段哪这种方式是行不通的这个关键字的用法是一条查询语句在有多个索引可以检索数据时显式指定一个索引减少优化器选择索引的耗时。但要注意如果你对于你整个业务系统十分熟悉那可以这样干。但如果不熟悉的话还是交给优化器来自行选择否则会适得其反1.3、数据库索引的本质前面一直在聊创建、查看、删除、指定等一些索引的基本操作但索引本质上在数据库中是什么呢大家都知道数据库是基于磁盘工作的所有的数据都会放到磁盘上存储而索引也是数据的一种因此与表数据相同最终创建出的索引也会在磁盘生成本地文件。不过索引文件在磁盘中究竟以何种方式存储这是由索引的数据结构来决定的。同时由于索引机制最终是由存储引擎实现因此不同存储引擎下的索引文件其保存在本地的格式也并不相同。在这里有一个点需要注意建立索引的工作在表数据越少时越好如果你想要给一张百万、千万条数据级别的表新创建一个索引那创建的耗时也不短这是为什么呢因为刚刚聊过索引本质上和表是一样的都是磁盘中的文件那也就代表着创建一个索引并不像单纯的给一张表加个约束那么简单而是会基于原有的表数据重新在磁盘中创建新的本地索引文件。假设表中有一千万条数据那创建索引时就需要将索引字段上的1000W个值全部拷贝到本地索引文件中同时做好排序并与表数据产生映射关系。OK~至此就对MySQL提供的索引机制做了简单回顾下面再来说说数据库中“多样化”的索引类型。二、MySQL的索引分类在前面我为什么用多样化去形容数据库索引呢因为确实如此先列一些大家都听说过的索引称呼聚簇索引、非聚簇索引、唯一索引、主键索引、联合索引、全文索引、单列索引、多列索引、复合索引、普通索引、二级索引、辅助索引、次级索引、有序索引、BTree索引、R-Tree索引、T-Tree索引、Hash索引、空间索引、前缀索引......是不是看的眼花缭乱这些都是MySQL中索引的一些称呼一通看下来估计大家看“索引”两个字都有点不认识了^_^但实际上MySQL中真的有这么多索引类型吗其实并没有上述列出的索引称呼中有几个称呼对应的索引是同一个有一部分只是逻辑上的索引那索引究竟该如何分类呢其实从不同的层面上来说可以将索引划分为不同的类型接下来重点聊一聊。2.1、数据结构层次前面聊索引本质的时候提到过索引建立后也会在磁盘生成索引文件那每个具体的索引节点该如何在本地文件中存放呢这点是由索引的数据结构来决定的。比如索引的底层结构是数组那所有的索引节点都会以Node1→Node2→Node3→Node4....这样的形式存储在磁盘同一块物理空间中不过MySQL的索引不支持数组结构或者说数组结构不适合作为索引结构MySQL索引支持的数据结构如下•BTree类型MySQL中最常用的索引结构大部分引擎支持有序。•Hash类型大部分存储引擎都支持字段值不重复的情况下查询最快无序。•R-Tree类型MyISAM引擎支持也就是空间索引的默认结构类型。•T-Tree类型NDB-Cluster引擎支持主要用于MySQL-Cluster服务中。在上述的几种索引结构中B树和哈希索引是最常见的索引结构几乎大部分存储引擎都实现了对于后续两种索引结构在某些情况下也较为常见但除开列出的几种索引结构外MySQL索引支持的数据结构还有R、R*、QR、SS、X树等结构。但为何后续的一些索引结构大家没听说过呢这是因为索引到底支持什么数据结构这是由存储引擎决定的不同的存储引擎支持的索引结构也并不同目前较为常用的引擎就是MyISAM、InnoDB因此大家未曾听说后面列出的这些索引结构也是正常的。当然也正因为索引结构由存储引擎决定而MySQL引擎层在《MySQL架构篇》中提到过属于可拔插式引擎所以如果你有能力自己实现一个引擎那你甚至可以让引擎的索引机制支持任何数据结构。在MySQL中创建索引时其默认的数据结构就为BTree如何更换索引的数据结构呢如下CREATE INDEX indexName ON tableName (columnName(length) [ASC|DESC]) USING HASH;也就是在创建索引时通过USING关键字显示指定索引的数据结构必须要为当前引擎支持的结构。同时索引会被分为有序索引和无序索引这是指索引文件中存储索引节点时会不会按照字段值去排序。那一个索引到底是有序还是无序就是依据数据结构决定的例如BTree、R-Tree等树结构都是有序而哈希结构则是无序的。2.2、字段数量层次前面从索引的数据结构层次出发可以将索引分为不同结构的类型而从表字段的层次来看索引又可以分为单列索引和多列索引这两个称呼也比较好理解单列索引是指索引是基于一个字段建立的多列索引则是指由多个字段组合建立的索引。单列索引也会分为很多类型比如• 唯一索引指索引中的索引节点值不允许重复一般配合唯一约束使用。• 主键索引主键索引是一种特殊的唯一索引和普通唯一索引的区别在于不允许有空值。• 普通索引通过KEY、INDEX关键字创建的索引就是这个类型没啥限制单纯的可以让查询快一点。• .....还有很多很多只要是基于单个字段建立的索引都可以被称为单列索引。多列索引的概念前面解释过了不过它也有很多种叫法例如• 组合索引、联合索引、复合索引、多值索引....但不管名称咋变描述的含义都是相同的即由多个字段组合建立的索引。不过在使用多列索引时要注意当建立多列索引后一条SELECT语句只有当查询条件中了包含了多列索引的第一个字段时才能使用多列索引下面举个栗子。比如在用户表中通过id、name、age三个字段建立一个多列索引什么情况下会使用索引什么时候不会呢如下-- 无法使用多列索引的SQL语句 SELECT * FROM zz_user WHERE name 竹子 AND age 18; -- 能命中多列索引的SQL语句 SELECT * FROM zz_user WHERE name 竹子 AND id 6;OK到这里就根据字段数量的层面出发简单讲明了单列和多列索引的概念但无论是单列还是多列都可以存在一个前缀索引的概念啥叫前缀索引呢还记得创建索引时指定的length字段吗•length如果字段存储的值过长选用值的前多少个字符创建索引。使用一个字段值中的前N个字符创建出的索引就可以被称为前缀索引前缀索引能够在很大程度上节省索引文件的存储空间也能很大程度上提升索引的性能这是为什么呢后面分析索引实现原理的时候细聊。2.3、功能逻辑层次相信大家在面试时如果问到了MySQL索引机制相信一定会问如下这道面试题请回答一下你知道的MySQL索引类型。这题的答案该怎么回答呢其实主要就是指MySQL索引从逻辑上可以分为那些类型以功能逻辑划分索引类型这也是最常见的划分方式从这个维度来看主要可划分为五种• 普通索引、唯一索引、主键索引、全文索引、空间索引对于普通索引、唯一索引、主键索引都介绍过了就不再过多阐述但稍微提一嘴在主键字段上建立的索引被称为主键索引非主键字段上建立的索引一般被称为辅助索引或、二级索引或次级索引接着重点聊一下全文索引和空间索引。全文索引和空间索引都是MySQL5.7版本后开始支持的索引类型不过这两种索引都只有MyISAM引擎支持其他引擎要么我没用过要么就由于自身实现的原因不支持例如InnoDB。对于全文索引而言其实在MySQL5.6版本中就有了但当时并不支持汉字检索到了5.7.6版本的时候才内嵌ngram全文解析器才支持亚洲语种的分词同时InnoDB引擎也开始支持全文索引在5.7版本之前只有MyISAM引擎支持。全文索引全文索引类似于ES、Solr搜索中间件中的分词器或者说和之前常用的like%模糊查询很类似它只能创建在CHAR、VARCHAR、TEXT等这些文本类型字段上而且使用全文索引查询时条件字符数量必须大于3才生效。当然还是举个栗子才有感觉-------------------------------------------------------------------------- | article_id | article_name | special_column | -------------------------------------------------------------------------- | 1 | MySQL架构篇自顶向下深入剖析MySQL整体架构 | 《全解MySQL》 | | 2 | MySQL执行篇一条SQL语句从诞生至结束的历程 | 《全解MySQL》 | | 3 | MySQL设计篇数据库六范式与反范式设计准则| 《全解MySQL》 | | 4 | MySQL索引篇索引概述、分类及建立索引的原则| 《全解MySQL》 | --------------------------------------------------------------------------比如现在用户想要搜索一篇文章但是忘记文章全称了只记得「诞生至结束」这个词汇此时用户搜索这个词汇走全文索引的情况下照样能够定位到上表中的第二条记录。当然全文索引如何创建与使用待会儿后面一起列出来。空间索引空间索引这玩意儿其实用的不多至少大部分项目的业务中不会用到想要弄清楚空间索引那么首先得知道一个概念GIS空间数据GIS是什么意思呢是地理信息系统这是一门新的学科基于了计算机、信息学、地理学等多科构建的主要就是用于管理地理信息的数据结构在国土、规划、出行、配送、地图等和地理有关的项目中应用较为频繁。地理空间数据主要包含矢量数据、3D模型、影像文件、坐标数据等说简单点空间数据也就是可以将地理信息以模型的方式在地图上标注出来。在MySQL中总共支持GEOMETRY、POINT、LINESTRING、POLYGON四种空间数据类型而空间索引则是基于这些类型的字段建立的也就是可以帮助我们快捷检索空间数据。不过对于空间索引一般用的较少大家了解即可。2.4、存储方式层次上面聊完了三种不同层次的索引划分后接着从存储方式的层面再聊聊从存储方式来看MySQL的索引主要可分为两大类• 聚簇索引也被称为聚集索引、簇类索引• 非聚簇索引也叫非聚集索引、非簇类索引、二级索引、辅助索引、次级索引重点说一说这两类索引存储方式的区别在说之前先回忆一下数组和链表的区别• 数组是物理空间上的连续存储的所有元素都会按序存放在同一块内存区域中。• 链表是逻辑上的连续存储的所有元素可能不在同一块内存元素之间以指针连接。为啥要说这个呢因为聚簇索引和非聚簇索引的区别也大致是相同的• 聚簇索引逻辑上连续且物理空间上的连续。• 非聚簇索引逻辑上的连续物理空间上不连续。当然这里的连续和数组不同因为索引大部分都是使用BTree结构存储所以在磁盘中数据是以树结构存放的所以连续并不是指索引节点而是指索引数据和表数据也就是说聚簇索引中索引数据和表数据在磁盘中的位置是一起的而非聚簇索引则是分开的索引节点和表数据之间用物理地址的方式维护两者的联系。不过一张表中只能存在一个聚簇索引一般都会选用主键作为聚簇索引其他字段上建立的索引都属于非聚簇索引或者称之为辅助索引、次级索引。但也不要走进一个误区虽然MySQL默认会使用主键上建立的索引作为聚簇索引但也可以指定其他字段上的索引为聚簇索引一般聚簇索引要求索引必须是非空唯一索引才行。其实就算表中没有定义主键InnoDB中会选择一个唯一的非空索引作为聚簇索引但如果非空唯一索引也不存在InnoDB隐式定义一个主键来作为聚簇索引。当然主键或者说聚簇索引一般适合采用带有自增性的顺序值。对于聚簇、非聚簇索引的区别、两者的查找过程、隐式主键、为何主键适合自增值等这些问题在后续的《索引原理篇》中会详细讲解。2.5、索引分类小结至此对于MySQL“多样化”的索引机制一大堆索引名词就已经梳理清楚啦相信到这里为止大家也对MySQL的索引机制有了系统化的认知其实最开始给出的一大堆索引名词只是从不同角度划分出来的在上述中分别从数据结构、字段数量、功能逻辑以及存储方式多个层面进行了描述。当然要牢记的是以功能逻辑的层次来划分索引这也是最常用的方式。三、MySQL其他索引的创建使用方式前面的案例中聊到了咱们有三种方式创建索引在创建时可通过INDEX、KEY两个关键字创建但这种方式建立的索引仅是普通索引接着再来聊一聊MySQL数据库其他类型的索引该如何创建以及使用。但不管是何种类型的索引都可以通过前面聊到的三种方式创建。3.1、唯一索引的创建与使用唯一索引在创建时需要通过UNIQUE关键字创建如下-- 方式① CREATE UNIQUE INDEX indexName ON tableName (columnName(length)); -- 方式② ALTER TABLE tableName ADD UNIQUE INDEX indexName(columnName); -- 方式③ CREATE TABLE tableName( columnName1 INT(8) NOT NULL, columnName2 ...., ....., UNIQUE INDEX [indexName] (columnName(length)) );在已有的表基础上创建唯一索引时要注意如果选用的字段表中字段的值存在相同值时这时唯一索引是无法创建的比如SELECT * FROM zz_article; --------------------------------------------------------- | article_id | article_name | special_column | --------------------------------------------------------- | 1 | MySQL架构篇....... | 《全解MySQL》 | | 2 | MySQL执行篇....... | 《全解MySQL》 | | 3 | MySQL设计篇....... | 《全解MySQL》 | | 4 | MySQL索引篇....... | 《全解MySQL》 | | 5 | MySQL索引篇....... | 《全解MySQL》 | --------------------------------------------------------- CREATE UNIQUE INDEX i_article_name ON zz_article (article_name);比如上述文章表中第4、5条数据是重复的此时创建利用SQL语句创建唯一索引就会抛出1062错误码ERROR 1062 (23000): Duplicate entry MySQL索引篇....... for key i_article_name在这种情况下就只能先删除重复数据然后才能创建唯一索引成功。同时当唯一索引创建成功后它同时会对表具备唯一约束的作用当再使用INSERT语句插入相同值时会同样会抛出1062错误码INSERT INTO zz_article VALUES(6,MySQL索引篇.......,《全解MySQL》); 1062 - Duplicate entry MySQL索引篇....... for key i_article_name这里会提示你插入的哪个值已经在表中存在因此无法插入当前这条数据。3.2、主键索引的创建与使用前面聊到过主键索引其实是一种特殊的唯一索引但主键索引却并不是通过UNIQUE关键字创建的而是通过PRIMARY关键字创建-- 方式① ALTER TABLE tableName ADD PRIMARY KEY indexName(columnName); -- 方式② CREATE TABLE tableName( columnName1 INT(8) NOT NULL, columnName2 ...., ....., PRIMARY KEY [indexName] (columnName(length)) );在这里要注意• 创建主键索引时必须要将索引字段先设为主键否则会抛1068错误码。• 这里也不能使用CREATE语句创建索引否则会提示1064语法错误。• 同时创建索引时关键字要换成KEY并非INDEX否则也会提示语法错误。还是以之前的文章表为例如下-- 对非主键字段创建主键索引 ALTER TABLE zz_article ADD PRIMARY KEY i_special_column(special_column); -- 报错信息如下 1068 - Multiple primary key defined -- 使用CREATE关键字创建主键索引 CREATE PRIMARY KEY i_article_id ON zz_article (article_id); -- 报错信息如下 1064 - You have an error in your SQL syntax; check.... -- 使用INDEX关键字创建索引 ALTER TABLE zz_article ADD PRIMARY INDEX i_article_id(article_id); -- 报错信息如下 1064 - You have an error in your SQL syntax; check.... -- 创建主键索引正确的方式 ALTER TABLE zz_article ADD PRIMARY KEY i_article_id(article_id);当然一般主键索引都会在建表的DDL语句中创建不会在表已经建立后再创建。但似乎无论在讲普通索引还是唯一索引、主键索引的时候我们都没有讲如何使用这些创建好的索引查询数据其实这一点无需咱们考虑参考之前《SQL执行篇》中查询语句的执行流程在一条SELECT语句来到MySQL时会经历优化器优化的过程而优化器则会自动帮咱们选择一个最合适的索引查询数据。当然前提是查询条件中涉及到了索引字段才行。前面也说过你不想让优化器自动选择也可以手动通过FORCE INDEX关键字强制指定。3.3、全文索引的创建与使用全文索引和其他索引不同首先如果你想要创建全文索引那么MySQL版本必须要在5.7及以上同时使用时也需要手动指定一起来先看看如何创建全文索引此时需要使用FULLTEXT关键字-- 方式① ALTER TABLE tableName ADD FULLTEXT INDEX indexName(columnName); -- 方式② CREATE FULLTEXT INDEX indexName ON tableName(columnName);不过在创建全文索引时有三个注意点•5.6版本的MySQL中存储引擎必须为MyISAM才能创建。• 创建全文索引的字段其类型必须要为CHAR、VARCHAR、TEXT等文本类型。• 如果想要创建出的全文索引支持中文需要在最后指定解析器with parser ngram。此时还依旧是以文章表为例为文章名称字段创建一个全文索引命令如下ALTER TABLE zz_article ADD FULLTEXT INDEX ft_article_name(article_name) WITH PARSER NGRAM;创建好全文索引后当你想要使用全文索引时优化器这时不能自动选择因为全文索引有自己的语法但在了解如何使用之前得先清楚两个概念最小搜索长度和最大搜索长度先来看看全文索引的一些参数可通过show variables like %ft%;命令查询如下全文索引参数多余的参数就不介绍了重点讲一下其中的几个重要参数•ft_min_word_len使用MyISAM引擎的表中全文索引最小搜索长度。•ft_max_word_len使用MyISAM引擎的表中全文索引最大搜索长度。•ft_query_expansion_limitMyISAM中使用with query expansion搜索的最大匹配数。•innodb_ft_min_token_sizeInnoDB引擎的表中全文索引最小搜索长度。•innodb_ft_max_token_sizeInnoDB引擎的表中全文索引最大搜索长度。那么究竟做最小搜索长度、最大搜索长度的作用是什么呢其实这个是一个限制对于长度小于最小搜索长度和大于最大搜索长度的词语都无法触发全文索引。也就是说如果想要使用全文索引对一个词语进行搜索那这个词语的长度必须在这两个值之间。其实这两个值自己可以手动调整的最小值可以手动调整为1MyISAM引擎的最大值可以调整为3600但InnoDB引擎最大似乎就是84。OK~了解全文索引中的一些概念后接下来看看如何使用全文索引全文索引中有两个专门用于检索的关键字即MATCH(column)、AGAINST(关键字)同时这两个检索函数也支持三种搜索模式• 自然语言模式(默认搜索模式)• 布尔搜索模式• 查询拓展搜索MATCH()主要是负责指定要搜索的列这里要指定创建全文索引的字段AGAINST()则指定要搜索的关键字也就是要搜索的词语接下来简单的讲一下三种搜索模式。自然语言模式这种模式也是在使用全文索引时默认的搜索模式使用方法如下--------------------------------------------------------- | article_id | article_name | special_column | --------------------------------------------------------- | 1 | MySQL架构篇....... | 《全解MySQL》 | | 2 | MySQL执行篇....... | 《全解MySQL》 | | 3 | MySQL设计篇....... | 《全解MySQL》 | | 4 | MySQL索引篇....... | 《全解MySQL》 | --------------------------------------------------------- SELECT COUNT(article_id) AS 搜索结果数量 FROM zz_article WHERE MATCH(article_name) AGAINST(MySQL); -- 运行结果如下 -------------- | 搜索结果数量 | -------------- | 4 | --------------一眼看过去SQL就能看懂毕竟都可以排版了一下SQL不过多介绍了。唯一要注意的是如果给定的关键词长度小于默认的最小搜索长度那是无法使用全文索引的比如下述这条SQL就不会触发SELECT COUNT(article_id) AS 搜索结果数量 FROM zz_article WHERE MATCH(article_name) AGAINST(M);布尔搜索模式布尔搜索模式有些特殊因为在这种搜索模式中还需要掌握特定的搜索语法•表示必须匹配的行数据必须要包含相应关键字。•-和上面的相反表示匹配的数据不能包含相应的关键字。•提升指定关键字的相关性在查询结果中靠前显示。•降低指定关键字的相关性在查询结果中靠后显示。•~表示允许出现指定关键字但出现时相关性为负。•*表示以该关键字开头的词语如A*可以匹配A、AB、ABC....•双引号中的关键字作为整体检索时不允许再分词。•X Yn包含的多个词语之间的距离必须要在n之间单位-字节如•竹子 熊猫10表示竹子和熊猫两个词语之间的距离要在10字节内。• .......举个几个例子使用一下如下-- 查询文章名中包含 [MySQL] 但不包含 [设计] 的数据 SELECT * FROM zz_article WHERE MATCH(article_name) AGAINST(MySQL -设计 IN BOOLEAN MODE); -- 查询文章名中包含 [MySQL] 和 [篇] 的数据但两者间的距离不能超过10字节 SELECT * FROM zz_article WHERE MATCH(article_name) AGAINST(MySQL 篇10 IN BOOLEAN MODE); -- 查询文章名中包含[MySQL] 的数据 -- 但包含 [执行] 关键字的行相关性要高于包含 [索引] 关键字的行数据 SELECT * FROM zz_article WHERE MATCH(article_name) AGAINST(MySQL (执行 索引) IN BOOLEAN MODE); -- 查询文章名中包含 [MySQL] 的数据但包含 [设计] 时则将相关性降为负 SELECT * FROM zz_article WHERE MATCH(article_name) AGAINST(MySQL ~设计 IN BOOLEAN MODE); -- 查询文章名中包含 [执行] 关键字的行数据 SELECT * FROM zz_article WHERE MATCH(article_name) AGAINST(执行* IN BOOLEAN MODE); -- 查询文章名中必须要包含 [MySQL架构篇] 关键字的数据 SELECT * FROM zz_article WHERE MATCH(article_name) AGAINST(MySQL架构篇 IN BOOLEAN MODE);同样的上述的SQL语句应该都能看明白最后的IN BOOLEAN MODE表示使用布尔搜索模式除此外大家唯一疑惑的就在于相关性这个词其实这个词也不难理解就是检索数据后数据的优先级顺序当相关性越高对应数据在结果中越靠前当相关性为负则相应的数据排到最后。查询拓展搜索查询拓展搜索其实是对自然语言搜索模式的拓展比如举个例子SELECT COUNT(article_id) AS 搜索结果数量 FROM zz_article WHERE MATCH(article_name) AGAINST(MySQL WITH QUERY EXPANSION);在自然语言模式的查询语句基础上最后面多加一个WITH QUERY EXPANSION表示使用查询拓展搜索这种模式下会比自然语言模式多一次检索过程比如上述的例子中• 首先会根据指定的关键字MySQL进行一次全文检索。• 然后第二阶段还会对指定的关键进行分词然后再进行一次全文检索。之前介绍全文索引参数时也列出来了一个名为ft_query_expansion_limit的参数这个参数就是控制拓展搜索时的拓展行数的最大可以调整到1000。但由于Query Expansion的全文检索可能带来许多非相关性的查询结果因此在实际情况中要慎用实际上全文索引引入MySQL后可以用它代替之前的like%模糊查询效率会更高。3.4、空间索引的创建与使用空间索引这玩意儿实际上很多项目不会用到我用的次数也不多但如果你要用到这个索引那可以通过SPATIAL关键字创建如下ALTER TABLE tableName ADD SPATIAL KEY indexName(columnName);但在创建空间索引的时候有几个注意点需要牢记• 目前MySQL常用引擎中仅有MyISAM支持空间索引所以表引擎必须要为它。• 空间索引必须要建立在类型为GEOMETRY、POINT、LINESTRING、POLYGON的字段上。这个用的较少就不展开细聊了~3.5、联合索引的创建与使用联合索引呢实际上并不是一种逻辑索引分类它是索引的一种特殊结构前面给出的所有案例中都仅仅是在单个字段的基础上建立索引而联合索引的意思是可以使用多个字段建立索引。那该如何创建联合索引呢不需要特殊的关键字方法如下CREATE INDEX indexName ON tableName (column1(length),column2...); ALTER TABLE tableName ADD INDEX indexName(column1(length),column2...);• 你可以使用INDEX关键字让多个列组成一个普通联合索引• 也可以使用UNIQUE INDEX关键字让多个列组成一个唯一联合索引• 甚至还可以使用FULLTEXT INDEX关键字让多个列组成一个全文联合索引• .......但是前面也提过SELECT语句的查询条件中必须包含组成联合索引的第一个字段此时才会触发联合索引否则是无法使用联合索引的。四、索引初识篇总结OK~在本篇中就对MySQL的索引机制有了全面认知从索引的由来到索引概述、索引管理、索引分类、唯一/全文/联合/空间索引的创建与使用等内容进行了全面概述相信本章看下来足够让你对MySQL索引机制有一个系统化的体系那么我们下篇再见。