索引可以提高查询速度,会影响where查询,以及order by排序。
查看表的索引:
SHOW INDEX FROM tablename;
示例:
mysql> show index from user;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| user | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
1 row in set (0.20 sec)
mysql>
MySQL索引类型如下:
-
从应用层次划分:普通索引、唯一索引、主键索引、复合索引
-
从索引键值类型划分:主键索引、辅助索引(二级索引)
-
从数据存储和索引键值逻辑关系划分:聚簇索引、非聚簇索引
1.1 普通索引
基于普通字段建立的索引,没有任何限制。
普通索引的创建方法如下:
CREATE INDEX <索引名> ON tablename (字段名);
示例:
mysql> create index idx_user_name on user (name);
Query OK, 0 rows affected (2.23 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql>
ALTER TABLE tablename ADD INDEX [索引名] (字段名);
CREATE TABLE tablename ([...],INDEX [索引名](字段名);
1.2 唯一索引
与普通索引类似,不同之处在于:唯一索引的字段值必须唯一,允许有空值。在创建或者修改表时,添加唯一约束,就会自动创建对应的唯一索引。
唯一索引的创建方法如下:
CREATE UNIQUE INDEX <索引名> ON tablename (字段名);
ALTER TABLE tablename ADD UNIQUE INDEX [索引名] (字段名);
CREATE TABLE tablename ([...],UNIQUE [索引名](字段名);
1.3 主键索引
主键索引是一种特殊的唯一索引,不允许有空值,在创建表的时候加上主键约束即可,每个表只能有一个主键(可以是单个字段,也可以是联合主键)
创建主键索引的方法如下:
CREATE TABLE tablename ([...],PRIMARY KEY(字段名);
ALTER TABLE tablename ADD PRIMARY KEY [索引名] (字段名);
1.4 复合索引
单一索引是指索引列为1列的情况。用户可以在多列上创建索引,这种索引就叫做复合索引。相比多个单一索引,复合索引需要的开销更小。
索引同时有两个概念,窄索引和宽索引,窄索引是指索引列为1-2列的索引,宽索引是指索引列大于2列的索引。索引设计的一个重要原则是能使用窄索引不用宽索引,因为窄索引往往比宽索引更有效。
复合索引创建方法如下:
CREATE INDEX <索引名> ON tablename (字段名1,字段名2);
ALTER TABLE tablename ADD INDEX [索引名] (字段名1,字段名2);
CREATE TABLE tablename ([...],INDEX [索引名](字段名1,字段名2);
复合索引使用的注意事项:
-
使用复合索引要根据where条件建立索引,注意不要过多使用索引,过多使用索引会对更新效率有很大影响
-
如果表已经建立了索引(col1,col2)就没有必要单独建(col1)
-
如果表已经建立了索引(col1),如果查询需要col1、col2当条件,可以建立符合索引(col1,col2),对于查询效率有一定的提高。
1.5 全文索引
查询操作在数据量比较少时,可以使用like模糊查询,但是对于大量的文本数据检索,效率很低。如果使用全文索引,查询速度会比like高很多。(MySQL5.6前的版本只有MyISAM存储引擎支持全文索引,从MySQL5.6开始,以后的版本,MyISAM和InnoDB存储引擎均支持)
全文索引的创建方式如下:
CREATE FULLTEXT INDEX <索引名> ON tablename (字段名);
ALTER TABLE tablename ADD FULLTEXT [索引名] (字段名);
CREATE TABLE tablename ([...],FULLTEXT KEY [索引名](字段名);
全文索引和常用的like模糊查询不同,全文索引有自己的语法格式,使用match和against关键字。例如:
select * from user where match(name) against('aaa');
全文索引使用注意事项:
-
全文索引必须建立在字符串或者文本字段上
-
全文索引字段必须在最小值和最大值之间才有效。InnoDB默认为3-84,MyISAM默认为4-84,最大值只能通过修改配置文件,然后重启MySQL服务生效。
-
全文索引会进行切词处理。按照syntax字符进行切割,例如b+aaa会切割成b和aaa
-
全文索引匹配查询默认使用等值查询,例如aaa会匹配aaa,不会匹配aaab、aaac。如果想要匹配,可以在布尔模式下搜索aaa*
select * from user where match(name) against('aaa*' in boolean mode);
全文索引使用示例:
-- 1、建一张表user
mysql> CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
`sex` int NOT NULL COMMENT '性别0 女 1 男',
`age` int NOT NULL COMMENT '年龄',
`info` json DEFAULT NULL COMMENT '信息',
PRIMARY KEY (`id`),
FULLTEXT KEY `idx_user_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ;
-- 2、在name上建立全文索引
mysql> create fulltext index idx_user_name on user (name);
-- 3、查看索引
mysql> show index from user;
+-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| user | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | YES | NULL |
| user | 1 | idx_user_name | 1 | name | NULL | 4 | NULL | NULL | | FULLTEXT | | | YES | NULL |
+-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.10 sec)
-- 4、插入一些测试数据
mysql> select * from user;
+----+------+-----+-----+------+
| id | name | sex | age | info |
+----+------+-----+-----+------+
| 1 | a | 0 | 14 | NULL |
| 2 | aaa | 0 | 14 | NULL |
| 3 | aa | 0 | 14 | NULL |
| 4 | aaab | 0 | 14 | NULL |
| 5 | aaac | 0 | 14 | NULL |
+----+------+-----+-----+------+
5 rows in set (0.00 sec)
-- 5、测试like查询 以a开头的有5条数据
mysql> select count(1) from user where name like 'a%';
+----------+
| count(1) |
+----------+
| 5 |
+----------+
1 row in set (0.11 sec)
-- 6、测试match
-- 由于全文索引默认为全词匹配,由于InnoDB存储引擎的全文索引的最大值和最小值是3-84,所以匹配a的结果是0.匹配aaa的结果是1
mysql> select count(1) from user where match(name) against('a');
+----------+
| count(1) |
+----------+
| 0 |
+----------+
1 row in set (0.10 sec)
mysql> select count(1) from user where match(name) against('aaa');
+----------+
| count(1) |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)
-- 采用boolean模式匹配,因为最小长度是3,所以a和aa不会被匹配到,a*和aaa*的匹配结果均为3条数据
mysql> select count(1) from user where match(name) against('a*' in boolean mode);
+----------+
| count(1) |
+----------+
| 3 |
+----------+
1 row in set (0.00 sec)
mysql> select count(1) from user where match(name) against('aaa*' in boolean mode);
+----------+
| count(1) |
+----------+
| 3 |
+----------+
1 row in set (0.00 sec)
-- 7、测试分词
-- 插入一条数据。name为abc+def
-- 测试发现查询匹配abc* def* *def都能匹配到这条数据
mysql> insert into user (name,sex,age) values ('abc+def',0,14);
Query OK, 1 row affected (0.20 sec)
mysql> select * from user where match(name) against('abc*' in boolean mode);
+----+---------+-----+-----+------+
| id | name | sex | age | info |
+----+---------+-----+-----+------+
| 6 | abc+def | 0 | 14 | NULL |
+----+---------+-----+-----+------+
1 row in set (0.00 sec)
mysql> select * from user where match(name) against('def*' in boolean mode);
+----+---------+-----+-----+------+
| id | name | sex | age | info |
+----+---------+-----+-----+------+
| 6 | abc+def | 0 | 14 | NULL |
+----+---------+-----+-----+------+
1 row in set (0.00 sec)
mysql> select * from user where match(name) against('*def' in boolean mode);
+----+---------+-----+-----+------+
| id | name | sex | age | info |
+----+---------+-----+-----+------+
| 6 | abc+def | 0 | 14 | NULL |
+----+---------+-----+-----+------+
1 row in set (0.00 sec)
mysql> select * from user where name like 'a';
+----+------+-----+-----+------+
| id | name | sex | age | info |
+----+------+-----+-----+------+
| 1 | a | 0 | 14 | NULL |
+----+------+-----+-----+------+
1 row in set (0.00 sec)
mysql> select * from user where name like 'abc%';
+----+---------+-----+-----+------+
| id | name | sex | age | info |
+----+---------+-----+-----+------+
| 6 | abc+def | 0 | 14 | NULL |
+----+---------+-----+-----+------+
1 row in set (0.00 sec)
mysql> select * from user where name like 'def%';
Empty set (0.00 sec)
mysql> select * from user where name like '%def';
+----+---------+-----+-----+------+
| id | name | sex | age | info |
+----+---------+-----+-----+------+
| 6 | abc+def | 0 | 14 | NULL |
+----+---------+-----+-----+------+
1 row in set (0.00 sec)
mysql>