mysql 索引(InnoDB)

Posted 啄木鸟伍迪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql 索引(InnoDB)相关的知识,希望对你有一定的参考价值。

mysql 创建索引地址:https://dev.mysql.com/doc/refman/8.0/en/create-index.html

概述:

什么是索引:

在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。也就是添加一条数据,对应要创建数据对应的索引。索引消耗磁盘空间;

 

有哪些索引: 

InnoDB存储引擎索引只支持BTREE类型的索引,索引的类别有Primary Key,Unique,Key,FULLTEXT和SPATIAL。当然也有其他的分法,按照索引列的数量分为单列索引和组合索引。

  1. Primary Key(聚集索引)一般应用在主键上默认自动创建,只能有一个;InnoDB存储引擎的表会存在主键(唯一非null),如果建表的时候没有指定主键,则会使用第一非空的唯一索引作为聚集索引,否则InnoDB会自动帮你创建一个不可见的、长度为6字节的row_id用来作为聚集索引。
  2. 单列索引:单列索引即一个索引只包含单个列
  3. 组合索引:组合索引指在表的多个字段组合上创建的索引,只有在查询条件中使用了这些字段的左边字段时,索引才会被使用。使用组合索引时遵循最左前缀集合
  4. Unique(唯一索引)索引列的值必须唯一,但允许有空值。若是组合索引,则列值的组合必须唯一。主键索引是一种特殊的唯一索引,不允许有空值
  5. Key|Index(普通索引):是MySQL中的基本索引类型,允许在定义索引的列中插入重复值和空值
  6. FULLTEXT(全文索引):全文索引类型为FULLTEXT,在定义索引的列上支持值的全文查找,允许在这些索引列中插入重复值和空值。文索引可以在CHAR、VARCHAR或者TEXT类型的列上创建
  7. SPATIAL(空间索引):空间索引是对空间数据类型的字段建立的索引,MySQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING和POLYGON。MySQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类似的语法创建空间索引。创建空间索引的列必须声明为NOT NULL

mysql InnoDB 索引的介绍,如下表格:

Table 13.2 InnoDB Storage Engine Index Characteristics

Index ClassIndex TypeStores NULL VALUESPermits Multiple NULL ValuesIS NULL Scan TypeIS NOT NULL Scan Type
Primary key BTREE No No N/A N/A
Unique BTREE Yes Yes Index Index

KEY | INDEX

BTREE Yes Yes Index Index
FULLTEXT N/A Yes Yes Table Table
SPATIAL N/A No No N/A N/A

 查看索引:

SHOW INDEX FROM table_name;

 例:

show index from `user2`;

字段说明:

字段 意思
table 表名
Non_unique 如果索引不能包括重复词,则为0。如果可以,则为1
Key_name  索引名称
Seq_in_index 索引中的列序列号,从1开始。
Column_name  列名称
Collation  列以什么方式存储在索引中。在MySQL中,有值‘A’(升序)或NULL(无分类)。
Cardinality  索引中唯一值的数目的估计值,通过运行ANALYZE TABLE或myisamchk -a可以更新,基数根据被存储为整数的统计数据来计数,所以即使对于小型表,该值也没有必要是精确的,基数越大,当进行联合时,MySQL使用该索引的机会就越大.
Sub_part  如果列只是被部分地编入索引,则为被编入索引的字符的数目,如果整列被编入索引,则为NULL.
Packed  指示关键字如何被压缩,如果没有被压缩,则为NULL
Null 如果列含有NULL,则含有YES,如果没有,则该列含有NO.
Index_type  用过的索引方法(BTREE,FULLTEXT,HASH,RTREE).

 

创建:

定义语法:

CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name
    [index_type]
    ON tbl_name (key_part,...)
    [index_option]
    [algorithm_option | lock_option] ...

key_part: col_name [(length)] | (expr) [ASC | DESC]

index_option: 
    KEY_BLOCK_SIZE [=] value
  | index_type
  | WITH PARSER parser_name
  | COMMENT \'string\'
  | VISIBLE | INVISIBLE
  | ENGINE_ATTRIBUTE [=] \'string\'
  | SECONDARY_ENGINE_ATTRIBUTE [=] \'string\'


index_type:
    USING BTREE | HASH

algorithm_option:
    ALGORITHM [=] DEFAULT | INPLACE | COPY

lock_option:
    LOCK [=] DEFAULT | NONE | SHARED | EXCLUSIVE

 

索引的创建原则

  1. 索引并非越多越好,一个表中如果有大量的索引,不仅占用磁盘空间,而且会影响INSERT、DELETE、UPDATE等语句的性能,因为在表中的数据更改的同时,索引也会进行调整和更新
  2. 避免对经常更新的表进行过多的索引,并且索引中的列尽可能少。而对经常用于查询的字段应该创建索引,但要避免添加不必要的字段。
  3. 数据量小的表最好不要使用索引,由于数据较少,查询花费的时间可能比遍历索引的时间还要短,索引可能不会产生优化效果。
  4. 在条件表达式中经常用到的不同值较多的列上建立索引,在不同值很少的列上不要建立索引。比如在学生表的“性别”字段上只有“男”与“女”两个不同值,因此就无须建立索引。如果建立索引,不但不会提高查询效率,反而会严重降低数据更新速度。
  5. 当唯一性是某种数据本身的特征时,指定唯一索引。使用唯一索引需能确保定义的列的数据完整性,以提高查询速度。
  6. 在频繁进行排序或分组(即进行group by或order by操作)的列上建立索引,如果待排序的列有多个,可以在这些列上建立组合索引。
  7. 搜索的索引列,不一定是所要选择的列。换句话说,最适合索引的列是出现在WHERE子句中的列,或连接子句中指定的列,而不是出现在SELECT关键字后的选择列表中的列。
  8. 使用短索引。如果对字符串列进行索引,应该指定一个前缀长度,只要有可能就应该这样做。例如,有一个CHAR(200)列,如果在前10个或20个字符内,多数值是唯一的,那么就不要对整个列进行索引。对前10个或20个字符进行索引能够节省大量索引空间,也可能会使查询更快。较小的索引涉及的磁盘 IO 较少,较短的值比较起来更快。更为重要的是,对于较短的键值,索引高速缓存中的块能容纳更多的键值,因此,MySQL 也可以在内存中容纳更多的值。这样就增加了找到行而不用读取索引中较多块的可能性。
  9. 利用最左前缀。在创建一个n列的索引时,实际是创建了MySQL可利用的n个索引。多列索引可起几个索引的作用,因为可利用索引中最左边的列集来匹配行。这样的列集称为最左前缀。
  10. 对于InnoDB存储引擎的表,记录默认会按照一定的顺序保存,如果有明确定义的主键,则按照主键顺序保存。如果没有主键,但是有唯一索引,那么就是按照唯一索引的顺序保存。如果既没有主键又没有唯一索引,那么表中会自动生成一个内部列,按照这个列的顺序保存。按照主键或者内部列进行的访问是最快的,所以InnoDB表尽量自己指定主键,当表中同时有几个列都是唯一的,都可以作为主键的时候,要选择最常作为访问条件的列作为主键,提高查询的效率。另外,还需要注意,InnoDB 表的普通索引都会保存主键的键值,所以主键要尽可能选择较短的数据类型,可以有效地减少索引的磁盘占用,提高索引的缓存效果

创建表时创建索引:

 列1:普通索引

CREATE TABLE learn_index.`user2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`sex` varchar(5) DEFAULT NULL,
`address` varchar(100) DEFAULT NULL,
`birthday` datetime NOT NULL,
PRIMARY KEY (`id`),
index idx1(username)
);

 

 列2:unique index

CREATE TABLE learn_index.`user2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `sex` varchar(5) DEFAULT NULL,
  `address` varchar(100) DEFAULT NULL,
  `birthday` datetime NOT NULL,
  `score_num` int(11) NOT NULL UNIQUE,
  PRIMARY KEY (`id`),
  unique index idx1(username)
);

 

 

例3:创建组合索引:

 

(1) 何时使用组合索引,要根据where条件建索引,注意不要过多使用索引,过多使用会对更新操作效率有很大影响。

 

(2) 如果表已经建立了(col1,col2),就没有必要再单独建立(col1);如果现在有(col1)索引,如果查询需要col1和col2条件,可以建立(col1,col2)复合索引,对于查询有一定提高。

 

CREATE TABLE learn_index.`user2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `sex` varchar(5) DEFAULT NULL,
  `address` varchar(100) DEFAULT NULL,
  `birthday` datetime NOT NULL,
  `score_num` int(11) NOT NULL UNIQUE,
  PRIMARY KEY (`id`),
  index idx1(id,score_num,username)
);

例4:创建全文索引:

FULLTEXT全文索引可以用于全文搜索,并且只为CHAR、VARCHAR和TEXT列创建索引。索引总是对整个列进行,不支持局部(前缀)索引

CREATE TABLE learn_index.`user2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `sex` varchar(5) DEFAULT NULL,
  `address` varchar(100) DEFAULT NULL,
  `birthday` datetime NOT NULL,
  `score_num` int(11) NOT NULL UNIQUE,
  PRIMARY KEY (`id`),
  fulltext index idx1(username)
);

例5:创建空间索引:

create table learn_index.test(
    position geometry not null,
    spatial index idx1(position)
);

例6:创建前缀索引:

CREATE TABLE learn_index.t1 (
  col1 VARCHAR(10),
  col2 VARCHAR(20),
  INDEX (col1, col2(10))
);

直接创建索引:

alert方式:

ALTER TABLE table_name ADD [UNIQUE|FULLTEXT|SPATIAL] [INDEX|KEY] [index_name] (col_name[length],...) [ASC|DESC]

create方式:

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name ON  table_name (col_name[length],...) [ASC|DESC]

 

删除索引:

AUTO_INCREMENT约束字段的唯一索引不能被删除

alter方式

ALTER TABLE table_name DROP INDEX index_name

drop方式:

DROP INDEX index_name ON table_name;

 

最左前缀匹配原则;

1、在mysql建立联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配,示例:
对列col1、列col2和列col3建一个联合索引

KEY index_col1_col2_col3 on test(col1,col2,col3);

联合索引 index_col1_col2_col3 实际建立了(col1)、(col1,col2)、(col,col2,col3)三个索引。

SELECT * FROM table WHERE col1="1" AND clo2="2" AND clo4="4"

上面这个查询语句执行时会依照最左前缀匹配原则,检索时会使用索引(col1,col2)进行数据匹配。索引的字段可以是任意顺序的。

 

关于全文索引的sql 查询:

语法:

# MATCH() in SELECT list...
SELECT MATCH (a) AGAINST (\'abc\') FROM t GROUP BY a WITH ROLLUP;
SELECT 1 FROM t GROUP BY a, MATCH (a) AGAINST (\'abc\') WITH ROLLUP;

# ...in HAVING clause...
SELECT 1 FROM t GROUP BY a WITH ROLLUP HAVING MATCH (a) AGAINST (\'abc\');

# ...and in ORDER BY clause
SELECT 1 FROM t GROUP BY a WITH ROLLUP ORDER BY MATCH (a) AGAINST (\'abc\');

全文索引的模式:

search_modifier:
  
       IN NATURAL LANGUAGE MODE
     | IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
     | IN BOOLEAN MODE
     | WITH QUERY EXPANSION
  

 

全文索引测试表:

 CREATE TABLE articles (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       title VARCHAR(200),
       body TEXT,
       FULLTEXT (title,body)
     ) ENGINE=InnoDB
         
         
INSERT INTO articles (title,body) VALUES
       (\'MySQL Tutorial\',\'DBMS stands for DataBase ...\'),
       (\'How To Use MySQL Well\',\'After you went through a ...\'),
       (\'Optimizing MySQL\',\'In this tutorial, we show ...\'),
       (\'1001 MySQL Tricks\',\'1. Never run mysqld as root. 2. ...\'),
       (\'MySQL vs. YourSQL\',\'In the following database comparison ...\'),
       (\'MySQL Security\',\'When configured properly, MySQL ...\');

 

 自然语言搜索:自然语言搜索中,innodb >3个字符串才可以被搜索到;

文档地址:https://dev.mysql.com/doc/refman/8.0/en/fulltext-natural-language.html

SELECT * FROM articles
     WHERE MATCH (title,body)
     AGAINST (\'database\' IN NATURAL LANGUAGE MODE);

对于自然语言全文搜索,MATCH()函数中命名的列必须与表中某个FULLTEXT索引中包含的列相同。对于前面的查询,请注意MATCH()函数中命名的列(titile ,body)与articles表的FULLTEXT索引定义中命名的那些列相同。要分别搜索title或body,需要为每列创建单独的FULLTEXT索引。

带查询扩展的全文搜索

例1

    SELECT * FROM articles
    WHERE MATCH (title,body)
    AGAINST (\'database\' IN NATURAL LANGUAGE MODE)

列2

 

SELECT * FROM articles
    WHERE MATCH (title,body)
    AGAINST (\'database\' WITH QUERY EXPANSION);

 

全文搜索支持查询扩展(尤其是其变体“盲查询扩展”)。当搜索短语太短时,这通常很有用,这通常意味着用户依赖于全文搜索引擎所缺乏的隐含知识。例如,用户搜索“database”可能意味着“MySQL”、“Oracle”、“DB2”和“RDBMS”都是应该与“数据库”匹配的短语,也应该返回。这是隐含的知识。

例2可能是搜索Georges Simenon关于Maigret的书,当用户不确定如何拼写“Maigret”时。在搜索“Maigrete and the reluctant witnesses”时,只找到了“Maigret and the Reluctant Witnesses”,没有扩展查询范围。带有查询扩展的搜索可以在第二遍中找到所有带有单词“Maigret”的书籍。

Boolean全文搜索:

SELECT * FROM articles WHERE MATCH (title,body)
    AGAINST (\'+MySQL -YourSQL\' IN BOOLEAN MODE)

MySQL可以使用IN boolean MODE修饰符执行布尔全文搜索。使用此修饰符,某些字符在搜索字符串中单词的开头或结尾具有特殊含义。,+和-运算符分别指示一个单词必须存在或不存在,才能发生匹配。因此,查询检索所有包含单词“MySQL”但不包含单词“YourSQL”的行; 只能写+Mysql  不能写 ++Mysql 且 ”+“ 和”-“只能写在查询的字段前面,不能是Mysql+;也不支持使用带通配符的前导加号(“+*”)、加号和减号组合(“+-”)或前导加号和减码组合(“+/-apple”)。这些无效查询返回语法错误。

 

InnoDB全文搜索不支持在布尔全文搜索中使用@符号。@符号是为@distance proximity搜索运算符保留的。

  • +代表AND
  • -代表NOT
  • [无运算符]表示OR

表达式说明

表达式 意义
\'apple banana\' 至少其中之一
\'+apple +banana\' 两个都要包含
\'+apple banana\' 必须包含apple,可以包含banana
\'+apple -banana\' 必须包含apple,不可以包含banana
\'+apple ~banana\' ?查找包含单词“apple”的行,但如果该行也包含单词“macintosh”,则将其评分低于不包含单词的行
\'+apple +(>turnover <strudel)\' 查找包含单词“apple”和“turnover ”,或“apple”和“strudel”(按任何顺序)的行,但将“apple turnover ”列为高于“apple strudel”的行
\'apple\' 查找包含“apple”、“apples”、“applesauce”或“applet”等单词的行
\'"some words"\' 查找包含确切短语“some words”的行(例如,包含“一些智慧单词”但不包含“一些噪音单词”的列)。请注意,包含短语的“字符”是分隔短语的运算符字符。它们不是包含搜索字符串本身的引号。

 

参考地址:https://www.cnblogs.com/shine-xn/p/16658497.html

参考博客:https://www.cnblogs.com/zhangyi555/p/15596768.html

参考博客:https://www.cnblogs.com/UniqueColor/p/7305783.html

以上是关于mysql 索引(InnoDB)的主要内容,如果未能解决你的问题,请参考以下文章

搞懂Mysql InnoDB B+树索引

剖析Mysql的InnoDB索引

Mysql Innodb 索引原理

MySql的InnoDB存储引擎--索引

MySQL的InnoDB索引原理详解

mysql InnoDB 索引小记