二.索引
1.什么是索引
索引是一种特殊的数据库结构,由数据表中的一列或多列组合而成,可以用来快速查询数据表中有某一特定值的记录。通过索引,查询数据时不用读完记录的所有信息,而只是查询索引列。否则,数据库系统将读取每条记录的所有信息进行匹配。
可以把索引比作新华字典的音序表。例如,要查“库”字,如果不使用音序,就需要从字典的 400 页中逐页来找。但是,如果提取拼音出来,构成音序表,就只需要从 10 多页的音序表中直接查找。这样就可以大大节省时间。
因此,使用索引可以很大程度上提高数据库的查询速度,还有效的提高了数据库系统的性能。
2.为什么要使用索引
索引就是根据表中的一列或若干列按照一定顺序建立的列值与记录行之间的对应关系表,实质上是一张描述索引列的列值与原表中记录行之间一 一对应关系的有序表。
索引是 MySQL 中十分重要的数据库对象,是数据库性能调优技术的基础,常用于实现数据的快速检索。
在 MySQL 中,通常有以下两种方式访问数据库表的行数据:
1) 顺序访问
顺序访问是在表中实行全表扫描,从头到尾逐行遍历,直到在无序的行数据中找到符合条件的目标数据。
顺序访问实现比较简单,但是当表中有大量数据的时候,效率非常低下。例如,在几千万条数据中查找少量的数据时,使用顺序访问方式将会遍历所有的数据,花费大量的时间,显然会影响数据库的处理性能。
2) 索引访问
索引访问是通过遍历索引来直接访问表中记录行的方式。
使用这种方式的前提是对表建立一个索引,在列上创建了索引之后,查找数据时可以直接根据该列上的索引找到对应记录行的位置,从而快捷地查找到数据。索引存储了指定列数据值的指针,根据指定的排序顺序对这些指针排序。
简而言之,不使用索引,MySQL 就必须从第一条记录开始读完整个表,直到找出相关的行。表越大,查询数据所花费的时间就越多。如果表中查询的列有一个索引,MySQL 就能快速到达一个位置去搜索数据文件,而不必查看所有数据,这样将会节省很大一部分时间。
3.优缺点
索引有其明显的优势,也有其不可避免的缺点。
3.1优点
索引的优点如下:
通过创建唯一索引可以保证数据库表中每一行数据的唯一性。
可以给所有的 MySQL 列类型设置索引。
可以大大加快数据的查询速度,这是使用索引最主要的原因。
在实现数据的参考完整性方面可以加速表与表之间的连接。
在使用分组和排序子句进行数据查询时也可以显著减少查询中分组和排序的时间
3.2缺点
增加索引也有许多不利的方面,主要如下:
创建和维护索引组要耗费时间,并且随着数据量的增加所耗费的时间也会增加。
索引需要占磁盘空间,除了数据表占数据空间以外,每一个索引还要占一定的物理空间。如果有大量的索引,索引文件可能比数据文件更快达到最大文件尺寸。
当对表中的数据进行增加、删除和修改的时候,索引也要动态维护,这样就降低了数据的维护速度。
索引可以提高查询速度,但是会影响插入记录的速度。因为,向有索引的表中插入记录时,数据库系统会按照索引进行排序,这样就降低了插入记录的速度,插入大量记录时的速度影响会更加明显。这种情况下,最好的办法是先删除表中的索引,然后插入数据,插入完成后,再创建索引。
2.4.何时不使用索引
表记录太少
经常增删改的表
数据重复且分布均匀的表字段,只应该为经常查询和最经常排序的数据列建立索引(如果某个数据类包含太多的重复数据,建立索引没有太大意义)
频繁更新的字段不适合创建索引(会增加IO负担)
where条件里用不到的字段不创建索引
2.5.索引何时失效
like以通配符%开头索引失效
当全表扫描比走索引查询的快的时候,会使用全表扫描,而不走索引
字符串不加单引号索引会失效
where中索引列使用了函数(例如substring字符串截取函数)
where中索引列有运算(用了< or > 右边的索引会失效,用<= or >= 索引不会失效)
is null可以走索引,is not null无法使用索引(取决于某一列的具体情况)
复合索引没有用到左列字段(最左前缀法则,如果没用用到最左列索引,或中间跳过了某列有索引的列,索引会部分失效)
条件中有or,前面的列有索引,后面的列没有,索引会失效。想让索引生效,只能将or条件中的每个列都加上索引
2.6.索引分类
MySQL索引分为普通索引、唯一索引、主键索引、组合索引、全文索引。索引不会包含有null值的列,索引项可以为null(唯一索引、组合索引等),但是只要列中有null值就不会被包含在索引中。
2.6.1.普通索引
普通索引是最基本的索引,它没有任何限制;
创建索引语法:
create index index_name on table(column);
修改表结构方式添加索引:
ALTER TABLE table_name ADD INDEX index_name ON (column(length))
删除索引
DROP INDEX index_name ON table
2.6.2.唯一索引
唯一索引与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。
CREATE UNIQUE INDEX indexName ON table(column(length))
2.6.3.主键索引
主键索引是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。简单来说:主键索引是加速查询 + 列值唯一(不可以有null)+ 表中只有一个。
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, PRIMARY KEY(ID) );
2.6.4.组合索引
组合索引指在多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合。
ALTER TABLE `table` ADD INDEX name_city_age (name,city,age);
2.6.5.全文索引
概念
全文索引主要用来查找文本中的关键字,而不是直接与索引中的值相比较。fulltext索引跟其它索引大不相同,它更像是一个搜索引擎,而不是简单的where语句的参数匹配。
fulltext索引配合match against操作使用,而不是一般的where语句加like。它可以在create table,alter table ,create index使用,不过目前只有char、varchar,text 列上可以创建全文索引。
值得一提的是,在数据量较大时候,现将数据放入一个没有全局索引的表中,然后再用CREATE index创建fulltext索引,要比先为一张表建立fulltext然后再将数据写入的速度快很多。
版本支持
Mysql 5.6之前版本,只有MyISAM支持全文索引,5.6之后,Innodb和MyISAM均支持全文索引。另外,只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引。
案例
创建数据表t_articles
CREATE TABLE t_articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT (title,body) );
给现有的article表的title和body字段创建全文索引,索引名称为fulltext_article
ALTER TABLE t_articles ADD FULLTEXT INDEX fulltext_article (title, body);
导入测试数据
INSERT INTO t_articles VALUES (NULL,'MySQL Tutorial', 'DBMS stands for DataBase ...'), (NULL,'How To Use MySQL Efficiently', 'After you went through a ...'), (NULL,'Optimising MySQL','In this tutorial we will show ...'), (NULL,'1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), (NULL,'MySQL vs. YourSQL', 'In the following database comparison ...'), (NULL,'MySQL Security', 'When configured properly, MySQL ...'); INSERT INTO t_articles VALUES (NULL,'abc', 'zs red blue ...'), (NULL,'xyz', 'ls white'); INSERT INTO t_articles VALUES (NULL,'aaa', 'zs red blue ...'), (NULL,'bbb', 'ls white red');
示例一:自然语言模式(IN NATURAL LANGUAGE MODE,默认模式)
SELECT * FROM t_articles where MATCH (title,body) AGAINST ('database')
示例二:布尔搜索模式(IN BOOLEAN MODE)
符号 | 含义 |
+ | 必须包含此字符串 |
- | 必须不包含此字符串 |
"" | 双引号内作为整体不能拆词 |
> | 提高该词的相关性,查询的结果靠前 |
< | 降低该词的相关性,查询的结果靠后 |
* | 通配符,只能接在词后面 |
#包含red或者blue SELECT * FROM t_articles where MATCH (title,body) AGAINST ('red blue' IN BOOLEAN MODE ); #包含red,但是必须包含blue SELECT * FROM t_articles where MATCH (title,body) AGAINST ('red +blue' IN BOOLEAN MODE ); #包含red,但是一定不能包含blue SELECT * FROM t_articles where MATCH (title,body) AGAINST ('red -blue' IN BOOLEAN MODE );
注意:长度超过2的英文关键字才会生效
示例三:中文搜索
5.6之后MySQL自带ngram解析器,可以解析中日韩三国文字,如果不使用ngram解析器,则MySQL默认使用空格与符号作为分隔符(对于英文自然够用了,但对于中日韩文字就不好用了,所以才需要ngram解析器)。
查看数据库版本
select version();
查看数据库引擎
show engines;
修改MySQL全文检索最小许可字符
[mysqld] ft_min_word_len = 2
全文检索的最小许可字符(默认4,通过 SHOW VARIABLES LIKE 'ft_min_word_len' 可查看),中文通常是两个字就是一个词,所以做中文的话需要修改这个值为2最好。services.msc
注意:必须要重启Mysql服务
创建全文索引并设置ngram解析器
ALTER TABLE t_book ADD FULLTEXT INDEX fulltext_bookname_type (bookname, booktype) WITH PARSER ngram;
基于t_book表中的bookname和booktype字段创建全文索引并设置ngram解析器,让其支持中文检索。
关键词搜索:
SELECT * FROM t_book where MATCH (bookname, booktype) AGAINST ('YU')