为什么使用索引速度更快
B+树查找时采用多分查找,速度更快。
底层索引结构
B+树索引
B+树是一个多叉搜索树,数据都存在叶子节点的data域中,非叶子节点中没有数据,只有对应的key的值,这样可以保证每个数据查询的平均效率是一样的。并且叶子节点之间用链表相连接,使得获得全表数据更容易。所有叶子节点都在一层。
B树
B树也是一个多叉搜索树,但是数据存放在节点中,所有叶子节点都在一层。
使用B+树的原因:
- 是因为B+树查询效率更稳定(数据都在叶子节点)。
- B+树支持预读取。
- B+树扫库更方便,叶子节点相连。
- 范围查找更高效。
不用二叉树原因:
- 二叉树高度较高,因为查询速度和高度相关,所以二叉树速度更慢。
Hash索引
通过建立对应的hash表结构建立索引。
能以O(1)的速度进行查找,但是失去了有序性,且不支持范围查找。
概念索引
聚簇索引
聚簇索引是指在索引中保存了数据,从而避免了读取磁盘,提高了效率。
在聚簇索引的叶子节点的data域中记录着完整的数据记录(行记录)。一般默认为主键建立聚簇索引。
有序的。
非聚簇索引(辅助索引)
Innodb
innodb的辅助索引的叶子节点中不存储数据,而是保存的指向主键的位置的指针(这里会有一次IO,通过指针找到对应的主键),然后通过主键,使用聚簇索引,找到对应的数据。
MyISAM
MyISAM存储时,数据和索引是分开存储的,数据存储在一个地方,索引存储在一个地方,所以它的叶子节点存储的是指向data的指针,直接找到数据。(MyISAM的聚簇索引和非聚簇索引没什么差别)。
应用索引
主键索引
它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引(一般对应聚簇索引)
唯一索引
MySQL数据库索引列的值必须唯一,但允许有空值。
全文索引
使用MyISAM支持
普通索引
基本的索引,它没有任何限制。
联合索引
mysql> CREATE TABLE `t_mobilesms_11` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userId` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户id,创建任务时的userid',
`mobile` varchar(24) NOT NULL DEFAULT '' COMMENT '手机号码',
`billMonth` varchar(32) DEFAULT NULL COMMENT '账单月',
`time` varchar(32) DEFAULT NULL COMMENT '收/发短信时间',
`peerNumber` varchar(64) NOT NULL COMMENT '对方号码',
`location` varchar(64) DEFAULT NULL COMMENT '通信地(自己的)',
`sendType` varchar(16) DEFAULT NULL COMMENT 'SEND-发送; RECEIVE-收取',
`msgType` varchar(8) DEFAULT NULL COMMENT 'SMS-短信; MSS-彩信',
`serviceName` varchar(256) DEFAULT NULL COMMENT '业务名称. e.g. 点对点(网内)',
`fee` int(11) DEFAULT NULL COMMENT '通信费(单位分)',
`createTime` datetime DEFAULT NULL COMMENT '创建时间',
`lastModifyTime` datetime DEFAULT NULL COMMENT '最后修改时间',
PRIMARY KEY (`id`),
KEY `联合索引` (`userId`,`mobile`,`billMonth`)
) ENGINE=InnoDB AUTO_INCREMENT=71185 DEFAULT CHARSET=utf8 COMMENT='手机短信详情';
Query OK, 0 rows affected (0.43 sec)
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222';
+----+-------------+----------------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+---------------+----------+---------+-------+------+-----------------------+
| 1 | SIMPLE | t_mobilesms_11 | ref | 联合索引 | 联合索引 | 767 | const | 1 | Using index condition |
+----+-------------+----------------+------+---------------+----------+---------+-------+------+-----------------------+
1 row in set (0.07 sec)
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972'
-> ;
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | t_mobilesms_11 | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE billMonth='2018-04'
-> ;
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | t_mobilesms_11 | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' AND mobile='13281899972'
-> ;
+----+-------------+----------------+------+---------------+----------+---------+-------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+---------------+----------+---------+-------------+------+-----------------------+
| 1 | SIMPLE | t_mobilesms_11 | ref | 联合索引 | 联合索引 | 841 | const,const | 1 | Using index condition |
+----+-------------+----------------+------+---------------+----------+---------+-------------+------+-----------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972' AND userid='2222'
-> ;
+----+-------------+----------------+------+---------------+----------+---------+-------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+---------------+----------+---------+-------------+------+-----------------------+
| 1 | SIMPLE | t_mobilesms_11 | ref | 联合索引 | 联合索引 | 841 | const,const | 1 | Using index condition |
+----+-------------+----------------+------+---------------+----------+---------+-------------+------+-----------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972' AND billMonth='2018-04'
-> ;
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | t_mobilesms_11 | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid>'2222' AND mobile like '%123';
+----+-------------+----------------+-------+---------------+----------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+-------+---------------+----------+---------+------+------+-----------------------+
| 1 | SIMPLE | t_mobilesms_11 | range | 联合索引 | 联合索引 | 767 | NULL | 1 | Using index condition |
+----+-------------+----------------+-------+---------------+----------+---------+------+------+-----------------------+
1 row in set
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid>'2222' AND mobile like '123%';
+----+-------------+----------------+-------+---------------+----------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+-------+---------------+----------+---------+------+------+-----------------------+
| 1 | SIMPLE | t_mobilesms_11 | range | 联合索引 | 联合索引 | 767 | NULL | 1 | Using index condition |
+----+-------------+----------------+-------+---------------+----------+---------+------+------+-----------------------+
1 row in set
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE
mobile like '123%';
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | t_mobilesms_11 | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
+----+-------------+----------------+------+---------------+------+---------+------+------+-------------+
1 row in set
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile like '123%' AND userid>'2222';
+----+-------------+----------------+-------+---------------+----------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+-------+---------------+----------+---------+------+------+-----------------------+
| 1 | SIMPLE | t_mobilesms_11 | range | 联合索引 | 联合索引 | 767 | NULL | 1 | Using index condition |
+----+-------------+----------------+-------+---------------+----------+---------+------+------+-----------------------+
三个单列索引
mysql> CREATE TABLE `t_mobilesms_11` (
-> `id` bigint(20) NOT NULL AUTO_INCREMENT,
-> `userId` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户id,创建任务时的userid',
-> `mobile` varchar(24) NOT NULL DEFAULT '' COMMENT '手机号码',
-> `billMonth` varchar(32) DEFAULT NULL COMMENT '账单月',
-> `time` varchar(32) DEFAULT NULL COMMENT '收/发短信时间',
-> `peerNumber` varchar(64) NOT NULL COMMENT '对方号码',
-> `location` varchar(64) DEFAULT NULL COMMENT '通信地(自己的)',
-> `sendType` varchar(16) DEFAULT NULL COMMENT 'SEND-发送; RECEIVE-收取',
-> `msgType` varchar(8) DEFAULT NULL COMMENT 'SMS-短信; MSS-彩信',
-> `serviceName` varchar(256) DEFAULT NULL COMMENT '业务名称. e.g. 点对点(网内)',
-> `fee` int(11) DEFAULT NULL COMMENT '通信费(单位分)',
-> `createTime` datetime DEFAULT NULL COMMENT '创建时间',
-> `lastModifyTime` datetime DEFAULT NULL COMMENT '最后修改时间',
-> PRIMARY KEY (`id`),
-> INDEX id_index(`userId`),
-> INDEX mobile_index(`mobile`),
-> INDEX billMonth_index(`billMonth`)
-> ) ENGINE=InnoDB AUTO_INCREMENT=71185 DEFAULT CHARSET=utf8 COMMENT='手机短信详情'
-> ;
Query OK, 0 rows affected (0.32 sec)
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' AND mobile='13281899972' AND billMonth='2018-04'
-> ;
+----+-------------+----------------+------+---------------------------------------+----------+---------+-------+------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+---------------------------------------+----------+---------+-------+------+------------------------------------+
| 1 | SIMPLE | t_mobilesms_11 | ref | id_index,mobile_index,billMonth_index | id_index | 767 | const | 1 | Using index condition; Using where |
+----+-------------+----------------+------+---------------------------------------+----------+---------+-------+------+------------------------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE mobile='13281899972' AND billMonth='2018-04'
-> ;
+----+-------------+----------------+------+------------------------------+--------------+---------+-------+------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+------------------------------+--------------+---------+-------+------+------------------------------------+
| 1 | SIMPLE | t_mobilesms_11 | ref | mobile_index,billMonth_index | mobile_index | 74 | const | 1 | Using index condition; Using where |
+----+-------------+----------------+------+------------------------------+--------------+---------+-------+------+------------------------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid='2222' OR mobile='13281899972'
-> ;
+----+-------------+----------------+------+-----------------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+-----------------------+------+---------+------+------+-------------+
| 1 | SIMPLE | t_mobilesms_11 | ALL | id_index,mobile_index | NULL | NULL | NULL | 1 | Using where |
+----+-------------+----------------+------+-----------------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
覆盖索引
索引失效情况
- 使用OR语句的时候会发生索引失效。
原因:对于or左右的两个字段,如果第一个加了索引,第二个没加,那么查找的顺序为(索引+全表+合并),那么既然要全表扫描了,何不直接一次全表扫描得到需要的数据。
但如果or的左右列都加了索引,那么索引还是可能走的。 - 使用like通配符科恩那个会导致索引失效
使用like %123此种情况时,会导致索引失效
但是使用 like 123%这种情况的时候,不会导致索引失效。 - 联合索引查序顺序和定义顺序不同会失效
比如一个索引 idx_name_age(name,age)
那么where name=“…” and age="…“有效;
where name=“…” 有效
where age=”…" 无效 - 使用mysql的内置函数会是索引无效
- 对索引列加运算(=,+,-,/)
- 对索引列使用in not in时会失效
- 对索引列使用!=或<>时会失效
- 对索引列使用is null或is not null时会失效
- 对索引进行表达式操作时会失效
10.mysql估计使用全表扫描要比使用索引快,则不使用索引