Mysql高级篇学习总结9:创建索引、删除索引、降序索引、隐藏索引

1、索引的声明和使用

1.1 索引的分类

mysql的索引包括普通索引、唯一性索引、全文索引、单列索引、多列索引、空间索引。

  • 按照功能逻辑:索引主要有4种,分别是普通索引、唯一索引、主键索引、全文索引;
  • 按照物理实现方式:索引可以分为2种,聚簇索引和非聚簇索引;
  • 按照作用字段个数:分成单列索引和联合索引;

1.2 创建索引

Mysql支持多种方法在单个或多个列上创建索引:
1)在创建表的定义语句CREATE TABLE中指定索引列;
2)在已存在的表上,使用ALTER TABLE语句创建索引,或者使用CREATE INDEX语句在已存在的表上添加索引;

1.2.1 创建表的时候创建索引

1.2.1.1 隐式的方式创建索引

在声明有主键约束、唯一性约束、外键约束的字段上,会自动的添加相关的索引

CREATE TABLE dept(
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(20)
);

CREATE TABLE emp(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(20) UNIQUE,
dept_id INT,
CONSTRAINT emp_dept_id_fk FOREIGN KEY(dept_id) REFERENCES dept(dept_id)
);

可以通过命令查看索引
方式1:SHOW INDEX FROM 表名;

mysql> SHOW INDEX FROM emp;
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name       | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| emp   |          0 | PRIMARY        |            1 | emp_id      | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
| emp   |          0 | emp_name       |            1 | emp_name    | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
| emp   |          1 | emp_dept_id_fk |            1 | dept_id     | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.01 sec)

可以看到主键emp_id的索引名是PRIMARY,emp_name的索引名是emp_name,dept_id的索引名是emp_dept_id_fk。

方式2:SHOW CREATE TABLE 表名;

mysql> SHOW CREATE TABLE emp;
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                                             |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| emp   | CREATE TABLE `emp` (
  `emp_id` int(11) NOT NULL AUTO_INCREMENT,
  `emp_name` varchar(20) DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`emp_id`),
  UNIQUE KEY `emp_name` (`emp_name`),
  KEY `emp_dept_id_fk` (`dept_id`),
  CONSTRAINT `emp_dept_id_fk` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`dept_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

1.2.1.2 显式的方式创建索引

1)创建普通的索引

mysql> CREATE TABLE book(
    -> book_id INT ,
    -> book_name VARCHAR(100),
    -> AUTHORS VARCHAR(100),
    -> info VARCHAR(100) ,
    -> COMMENT VARCHAR(100),
    -> year_publication YEAR,
    -> #声明索引
    -> INDEX idx_bname(book_name)
    -> );
Query OK, 0 rows affected (0.21 sec)

还是可以通过show index from book来查看索引:

mysql> SHOW INDEX FROM book;
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| book  |          1 | idx_bname |            1 | book_name   | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

除此之外,还可以通过性能分析工具:EXPLAIN来查看是否使用到了索引

mysql> EXPLAIN SELECT * FROM book WHERE book_name = 'mysql';
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key       | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | book  | NULL       | ref  | idx_bname     | idx_bname | 103     | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

比如通过book_name进行检索,可以看到使用到的索引(key)是idx_bname,这就是刚刚上面建立的普通索引。

2)创建唯一索引
声明有唯一索引的字段,在添加数据时,要保证唯一性,但是可以添加null
比如,下面以注释comment作为唯一索引

CREATE TABLE book1(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR,
#声明索引
UNIQUE INDEX uk_idx_cmt(COMMENT)
);
mysql> SHOW INDEX FROM book1;
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| book1 |          0 | uk_idx_cmt |            1 | COMMENT     | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

3)主键索引
通过定义主键约束的方式定义主键索引

CREATE TABLE book2(
book_id INT PRIMARY KEY ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR
);
mysql> SHOW INDEX FROM book2;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| book2 |          0 | PRIMARY  |            1 | book_id     | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

4)创建单列索引

CREATE TABLE book3(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR,
#声明索引
UNIQUE INDEX idx_bname(book_name)
);

5)创建联合索引

CREATE TABLE book4(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR,
#声明索引
INDEX mul_bid_bname_info(book_id,book_name,info)
);
mysql> SHOW INDEX FROM book4;
+-------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name           | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| book4 |          1 | mul_bid_bname_info |            1 | book_id     | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
| book4 |          1 | mul_bid_bname_info |            2 | book_name   | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
| book4 |          1 | mul_bid_bname_info |            3 | info        | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

注意,使用联合索引要遵循最左前缀原则,也就是使用索引的话至少要包含联合索引的最左边的索引才能检索

比如下面的2条检索语句,在第2条语句中,由于直接以book_name进行检索,而联合索引的首先是以book_id进行排序检索的,它这里找不到,所以就没有成功用到我们刚刚建的联合索引了。

mysql> EXPLAIN SELECT * FROM book4 WHERE book_id = 1001 AND book_name = 'mysql';
+----+-------------+-------+------------+------+--------------------+--------------------+---------+-------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys      | key                | key_len | ref         | rows | filtered | Extra |
+----+-------------+-------+------------+------+--------------------+--------------------+---------+-------------+------+----------+-------+
|  1 | SIMPLE      | book4 | NULL       | ref  | mul_bid_bname_info | mul_bid_bname_info | 108     | const,const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+--------------------+--------------------+---------+-------------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT * FROM book4 WHERE book_name = 'mysql';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | book4 | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

6)创建全文索引

CREATE TABLE test4(
id INT NOT NULL,
NAME CHAR(30) NOT NULL,
age INT NOT NULL,
info VARCHAR(255),
FULLTEXT INDEX futxt_idx_info(info(50))
)

1.2.2 在已存在的表上创建索引

方式1:表已经创建好了,可以使用 **ALTER TABLE … ADD …**来添加索引

CREATE TABLE book5(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR
);

在创建了该表后,给该表添加索引:

ALTER TABLE book5 ADD INDEX idx_cmt(COMMENT);
ALTER TABLE book5 ADD UNIQUE uk_idx_bname(book_name);
ALTER TABLE book5 ADD INDEX mul_bid_bname_info(book_id,book_name,info);

方式2:表已经创建好了,还可以使用 **CREATE INDEX … ON …**来添加索引

CREATE TABLE book6(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR
);
CREATE INDEX idx_cmt ON book6(COMMENT);
CREATE UNIQUE INDEX  uk_idx_bname ON book6(book_name);
CREATE INDEX mul_bid_bname_info ON book6(book_id,book_name,info);

1.3 删除索引

方式1:ALTER TABLE … DROP INDEX …

ALTER TABLE book5 DROP INDEX idx_cmt;

方式2:DROP INDEX … ON …

DROP INDEX uk_idx_bname ON book5;

注意:删除表中的列时,如果要删除的列为索引的组成部分,则该列也会从索引中删除。如果组成索引的所有列都被删除,则整个索引将被删除。

2、Mysql8.0索引新特性

2.1 支持降序索引

Mysql在8.0版本之前创建的是升序索引,使用时进行反向扫描,这大大降低了数据库的效率

比如创建表ts1:

CREATE TABLE ts1(a INT,b INT,INDEX idx_a_b(a ASC,b DESC));

如果是经常使用b的降序进行检索,那么8.0版本可以成功使用索引,大大降低数据库检索时间。而8.0之前的版本,由于没有这个降序索引的特性,所以检索时间更长。

EXPLAIN SELECT * FROM ts1 ORDER BY a,b DESC LIMIT 5;

2.2 隐藏索引

有的时候,我们不确定索引是否有效,或者想验证下删除索引是否会造成什么影响,可以不直接删除索引,可以先隐藏索引。

从Mysql8.0开始支持隐藏索引(invisible indexes),只需要将待删除的索引设置为隐藏索引,使查询优化器不再使用这个索引。等确认将索引设置为隐藏索引后,系统不会造成任何影响,就可以彻底删除该索引。

隐藏索引的方式,也分为创建表时,和创建表后:
方式1:创建表时,隐藏索引

CREATE TABLE book7(
book_id INT ,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info VARCHAR(100) ,
COMMENT VARCHAR(100),
year_publication YEAR,
#创建不可见的索引
INDEX idx_cmt(COMMENT) invisible
);

方式2:创建表以后,隐藏索引

ALTER TABLE book7
ADD UNIQUE INDEX uk_idx_bname(book_name) invisible;

还可以修改索引的可见性
比如将索引idx_cmt由不可见改为可见:

ALTER TABLE book7 ALTER INDEX idx_cmt visible; 

然后再将索引idx_cmt由可见改为不可见:

ALTER TABLE book7 ALTER INDEX idx_cmt invisible; 

猜你喜欢

转载自blog.csdn.net/xueping_wu/article/details/125583631