(六)MySQL索引
一、索引介绍
1.索引的介绍
索引是对数据库表中一列或者多列的值进行排序的一种结构,使用索引可提高数据库中特定数据的查询速度。
索引是一个单独的、存储在磁盘上的数据库结构,它们包含着对数据表里所有记录的引用指针。
使用索引用于快速找出在某个或多个列中有一特定值得行,所有MySQL列类型都可以被索引,对相关列使用索引是提高查询操作速度的最佳途径。
索引是在存储引擎中实现的,因此,每种存储引擎的索引都不一定完全相同,并且每种存储引擎也不一定支持索引类型。根据存储引擎定义每个表的最大索引数和最大索引长度。所有存储引擎支持每个表至少16个索引,总索引长度至少为256字节。
MyISAM ,InnoDB支持btree索引 Memory 支持 btree和hash索引。
2.索引的优势
- 加快查询速度
- 创建唯一索引来保证数据表中数据的唯一性
- 实现数据的完整性,加速表和表之间的连接
- 减少分组和排序的时间
3.索引的劣势
增加索引也有许多不利,主要表现在如下几个方面:
- 创建索引和维护索引要耗费时间,并且随着数据量的增加所耗费的时间也会增加。
- 索引需要占磁盘空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果有大量的索引,索引文件可能比数据文件更快达到最大文件尺寸。
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态地维护,这样就降低了数据的维护速度。
4.索引的分类
(1)唯一索引和普通索引
普通索引是MySQL中的基本索引类型,允许在定义索引的列中插入重复值和空值。
唯一索引,索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。
主键索引是一种特殊的唯一索引,不允许有空值。
(2)单列索引和组合索引
单列索引即一个索引只包含单个列,一个表可以有多个单列索引。
组合索引指在表的多个字段组合上创建的索引。只有在查询条件中使用了这些字段的左边字段时,索引才会被使用。使用组合索引时遵循最左前缀集合。
(3)全文索引 fulltext
全文索引类型为FULLTEXT,在定义索引的列上支持值得全文查找,允许在这些索引列中插入重复值和空值。全文索引可以在CHAR、VARCHAR或者TEXT类型的列上创建。MySQL中只有MyISAM存储引擎支持全文索引。
(4)空间索引
空间索引是对空间数据类型的字段建立的索引,MySQL中的空间数据类型有4中,分别是:geometry、point、linstring和polygon 。
MySQL使用SPATIAL关键字进行扩展,使得能够用于创建空间索引的列,必须将其声明为NOT NULL,空间索引只能在存储引擎为MyISAM的表中创建。
5.创建索引的规则
(1)创建索引并非是越多越好,一个表中如果有大量的索引,不仅占用磁盘空间,而且会影响insert、delete、update等语句的性能。因为当表中的数据更改时,索引也会进行调整和更新。
(2)数据量小得表最好不要创建索引,由于数据较少,查询花费的时间可能比遍历索引的时间还要长。
(3)避免对经常更新的数据创建索引。而对经常用于查询的字段应该创建索引。
(4)在条件表达式中经常用到的不同值较多的列创建索引
(5)当唯一性是某种数据本身的特征时,我们创建唯一性索引
(6)在频繁进行排序或分组的列上建立索引,如果排序的列有多个,可以创建组合索引
二、创建表的同时创建索引
Create index 创建索引 alter table 添加索引 Create table 表名[字段名 数据类型] [unique唯一索引|fulltext全文索引|spatial空间索引] [index|key] [索引名] (col_name [length]) [asc |desc]
语法帮助:
mysql> help index
Many help items for your request exist.
To make a more specific request, please type 'help <item>',
where <item> is one of the following
topics:
ALTER TABLE
CACHE INDEX
CREATE INDEX
CREATE TABLE
DROP INDEX
JOIN
LOAD INDEX
SHOW
SHOW INDEX
SPATIAL INDEXES
mysql> help create index
Name: 'CREATE INDEX'
Description:
Syntax:
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)] [ASC | DESC]
index_option: {
KEY_BLOCK_SIZE [=] value
| index_type
| WITH PARSER parser_name
| COMMENT 'string'
}
index_type:
USING {BTREE | HASH}
algorithm_option:
ALGORITHM [=] {DEFAULT | INPLACE | COPY}
lock_option:
LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}
Normally, you create all indexes on a table at the time the table
itself is created with CREATE TABLE. See [HELP CREATE TABLE]. This
guideline is especially important for InnoDB tables, where the primary
key determines the physical layout of rows in the data file. CREATE
INDEX enables you to add indexes to existing tables.
CREATE INDEX is mapped to an ALTER TABLE statement to create indexes.
See [HELP ALTER TABLE]. CREATE INDEX cannot be used to create a PRIMARY
KEY; use ALTER TABLE instead. For more information about indexes, see
https://dev.mysql.com/doc/refman/5.7/en/mysql-indexes.html.
URL: https://dev.mysql.com/doc/refman/5.7/en/create-index.html
mysql>
1.普通索引 index
创建普通索引:普通索引是最基础的索引类型,没有唯一性的限制。作用是只加快对数据的访问速度。
mysql> create table book(
-> bookid int not null,
-> bookname varchar(255) not null,
-> authors varchar(255) not null,
-> info varchar(255) null,
-> comment varchar(255) null,
-> year_publication year not null,
-> index(year_publication));
Query OK, 0 rows affected (0.56 sec)
mysql> desc book;
+------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+-------+
| bookid | int(11) | NO | | NULL | |
| bookname | varchar(255) | NO | | NULL | |
| authors | varchar(255) | NO | | NULL | |
| info | varchar(255) | YES | | NULL | |
| comment | varchar(255) | YES | | NULL | |
| year_publication | year(4) | NO | MUL | NULL | |
+------------------+--------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
mysql>
查看创建的索引
mysql> show create table book\G
*************************** 1. row ***************************
Table: book
Create Table: CREATE TABLE `book` (
`bookid` int(11) NOT NULL,
`bookname` varchar(255) NOT NULL,
`authors` varchar(255) NOT NULL,
`info` varchar(255) DEFAULT NULL,
`comment` varchar(255) DEFAULT NULL,
`year_publication` year(4) NOT NULL,
KEY `year_publication` (`year_publication`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.00 sec)
mysql>
用explain 判断索引是否正在被使用
mysql> explain select * from book where year_publication=1999\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: book
partitions: NULL
type: ref
possible_keys: year_publication
key: year_publication
key_len: 1
ref: const
rows: 1
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from book where bookname="xxxx"\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: book
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)
mysql>
TYPE的取值范围有:System const ref eq_ref index all range
system>const>eq_ref>ref>range>index>ALL
越往左边,性能越高,比如system就比ALL类型性能要高出许多,其中system、const只是理想类型,基本达不到;
我们自己实际能优化到ref>range这两个类型,就是你自己写SQL,如果你没优化基本上就是ALL,如果你优化了,那就尽量达到ref>range这两个级别;
左边基本达不到!
所以,要对type优化的前提是,你需要有索引,如果你连索引都没有创建,那你就不用优化了,肯定是ALL…;
2.唯一索引 unique index
创建唯一索引:唯一索引主要原因是减少查询索引列操作的执行时间。尤其是对比比较庞大的数据表。与普通索引类似,不同点在于:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。
案例一:
Database changed
mysql> create table t1(
-> id int not null, #不能为空
-> name char(30) not null,
-> unique index UnidIdx(id)); #唯一索引
Query OK, 0 rows affected (0.64 sec)
mysql>
查看创建的索引
mysql> show create table t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int(11) NOT NULL,
`name` char(30) NOT NULL,
UNIQUE KEY `UnidIdx` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.00 sec)
mysql> desc t1;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | | #PRI自动创建的
| name | char(30) | NO | | NULL | |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> insert into t1 values(1,"zhao");
Query OK, 1 row affected (0.00 sec)
mysql> insert into t1(name) values("qian");
ERROR 1364 (HY000): Field 'id' doesn't have a default value
#报错原因:id不能为空,必须填写
mysql> insert into t1 values(1,"qian");
ERROR 1062 (23000): Duplicate entry '1' for key 'UnidIdx'
#报错原因:id为主键,不能重复
mysql>
案例二:
mysql> create table tt1(
-> id int , #可以为空
-> name char(30) not null,
-> unique index UnidIdx(id)); #唯一索引
Query OK, 0 rows affected (0.53 sec)
mysql>
查看创建的索引
mysql> show create table tt1\G
*************************** 1. row ***************************
Table: tt1
Create Table: CREATE TABLE `tt1` (
`id` int(11) DEFAULT NULL,
`name` char(30) NOT NULL,
UNIQUE KEY `UnidIdx` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.00 sec)
mysql> desc tt1;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id | int(11) | YES | UNI | NULL | | #唯一的
| name | char(30) | NO | | NULL | |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> insert into tt1 values(1,"zhao");
Query OK, 1 row affected (0.00 sec)
mysql> insert into tt1(name) values("qian"); #此时id可以为空
Query OK, 1 row affected (0.00 sec)
mysql> insert into tt1 values(1,"qian");
ERROR 1062 (23000): Duplicate entry '1' for key 'UnidIdx'
#报错原因:id为UnidIdx,是唯一的不能重复
mysql>
3.单列索引
单列索引:是在数据表中的某一字段上创建的索引,一个表中可以创建多个单列索引。
mysql> create table t2(
-> id int not null,
-> name char(30) null,
-> index singleIdx(name));
Query OK, 0 rows affected (0.02 sec)
mysql>
查看创建的索引
mysql> desc t2;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| name | char(30) | YES | MUL | NULL | | #MUL单列索引
+-------+----------+------+-----+---------+-------+
2 rows in set (0.02 sec)
mysql> show create table t2\G
*************************** 1. row ***************************
Table: t2
Create Table: CREATE TABLE `t2` (
`id` int(11) NOT NULL,
`name` char(30) DEFAULT NULL,
KEY `singleIdx` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.00 sec)
mysql> insert into t2 values(1,"zhao");
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2 values(1,"zhao");
Query OK,