(一)什么是索引??
索引(Index)是在数据库的字段上添加的,是为了提高查询的效率存在的一种机制。一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引。索引相当于是一本书的目录,主要是为缩小扫描范围而存在的一种机制。
(二)查询的分类
① 全表扫描(缺点:效率比较低,查询速度比较慢)
② 索引定位(优点:查询速度比较快,效率比较高)
说明:对于通过索引的这一种查询方式,索引也是需要排序的,并且索引的排序和TreeSet数据结构相同。TreeSet(TreeMap)底层是一个自平衡二叉树!在mysql中索引是一个B-Tree的数据结构。
(三)索引的实现原理
假设存在一张用户表 t_user
id(PK) name 每一行记录在硬盘上都有物理存储编号
------------------------------------------------------------------------------------
100 张三 0x1111
120 李四 0x2222
99 王五 0x8888
88 赵六 0x9999
101 小胡 0x6666
55 小明 0x5555
130 小红 0x7777
说明:
I.在任何数据库当中主键上会自动添加索引对象,id字段上有自动索引。一个字段上如果有unique约束的话,也会自动创建索引对象。
II.在任何数据库当中,任何一张表的任何一条记录都在硬盘上存储都有一个硬盘上的物理编号。
III.在mysql中,所以是一个单独的对象,不同的存储引擎以不同的形式存在,在MYSQL存储引擎中,索引存储在一个.MYI文件中。在InnoDB存储引擎中,索引存储在一个逻辑名称叫做tablespace当中。在MEMORY存储引擎中索引被存储在内存当中。不管索引存储在哪里,索引在mysql中都是一个树的形式存在(自平衡二叉树:B-Tree)
构建与查找图示如下:
(四)应用场景
① 数据量庞大
② 该字段经常出现在where的后面
③ 该字段进行很少的DML(insert 、delete、update)操作。
(频繁的DML操作会导致索引重新排序,降低效率)
注意:索引是不可以进行随意添加的,索引是需要维护的,索引太多反而会影响系统的性能,通过主键查询或通过unique约束的字段进行查询,效率很高。
(五)如何使用
I.索引的创建
mysql> create index emp_ename_index on emp(ename);
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
II.索引的删除
mysql> drop index emp_ename_index on emp;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
III.查看索引方式
mysql> explain select * from emp where ename = 'KING';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> create index emp_ename_index on emp(ename);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain select * from emp where ename = 'KING';
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | emp | NULL | ref | emp_ename_index | emp_ename_index | 33 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
说明:MYSQL索引底层是B-Tree
IV.索引失效
情况一:explain select * from emp where ename like '%T';
mysql> explain select * from emp where ename like '%T';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 11.11 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
失效原因:模糊匹配当中条件使用了“%”开头(应该尽量避免)
情况二:explain select * from emp where ename = 'KING' or job='MANAGER';
mysql> explain select * from emp where ename = 'KING' or job='MANAGER';
+----+-------------+-------+------------+------+-----------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+-----------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | emp_ename_index | NULL | NULL | NULL | 14 | 19.00 | Using where |
+----+-------------+-------+------------+------+-----------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
失效原因:在使用or时候,要求其两边的条件字段都需要有索引,才会通过索引进行检索,反之不可以。
#通过使用union来实现
mysql> explain select * from emp where ename = 'KING' union select * from emp where job='MANAGER';
+----+--------------+------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-----------------+
| 1 | PRIMARY | emp | NULL | ref | emp_ename_index | emp_ename_index | 33 | const | 1 | 100.00 | NULL |
| 2 | UNION | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 10.00 | Using where |
| NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-----------------+
3 rows in set, 1 warning (0.00 sec)
情况三:create index emp_job_sal_index on emp(job,sal);
#创建索引
mysql> create index emp_job_sal_index on emp(job,sal);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
#查看索引次数
mysql> explain select * from emp where job='MANAGER';
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | emp | NULL | ref | emp_job_sal_index | emp_job_sal_index | 30 | const | 3 | 100.00 | NULL |
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
#查看索引次数
mysql> explain select * from emp where sal = 800;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
失效原因:在复合索引(两个及以上字段联合起来添加索引)中。没有使用左侧的列查找,索引失效。
情况四:explain select * from emp where sal+1=800;
mysql> create index emp_sal_index on emp(sal);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain select * from emp where sal=800;
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | emp | NULL | ref | emp_sal_index | emp_sal_index | 9 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from emp where sal+1=800;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
失效原因:在where中索引参与了运算。
情况五:explain select * from emp where lower(ename)='smith';
mysql> explain select * from emp where lower(ename)='smith';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
失效原因: 在where中索引使用了函数
V.索引分类
① 单一索引:一个字段上添加索引。
②复合索引: 两个及以上字段上添加索引。