分类 | 说明 |
---|---|
(BTREE)B树 | 将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,依次遍历node,获取leaf。这是MySQL里默认和最常用的索引类型 |
(RTREE)R树 | 在MySQL很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。相对于BTREE,RTREE的优势在于范围查找 |
Hash | 可以一次定位,不需要像树形索引那样逐层查找,但是,这种高效只在“=”和“in”条件下高效,对于范围查询、排序及组合索引仍然效率不高 |
FULLTEXT | 全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引 |
GIS 索引 | InnoDB支持空间索引,通过R树来实现,使得空间搜索变得高效。 InnoDB空间索引也支持MyISAM引擎现有的空间索引的语法,此外,InnoDB空间索引支持完整的事务特性以及隔离级别 |
索引类别 | 辅助索引 | 聚集索引 | 联合索引 |
---|---|---|---|
说明 | 提取索引列的所有值,进行排序;将排好序的值,均匀的存放在叶子节点,进一步生成枝节点和根节点;在叶子节点中的值,都会对应存储主键ID | MySQL 会自动选择主键作为聚集索引列,没有主键会选择唯一键,如果都没有会生成隐藏的;MySQL进行存储数据时,会按照聚集索引列值得顺序,有序存储数据行; 聚集索引直接将原表数据页,作为叶子节点,然后提取聚集索引列向上生成枝和根 | 指对表上的多个列进行索引 |
区别 | 表中任何一个列都可以创建辅助索引,在你有需要的时候,只要名字不同即可;辅助索引,叶子节点只存储索引列的有序值+聚集索引列值 | 在一张表中,聚集索引只能有一个,一般是主键;聚集索引,叶子节点存储的时有序的整行数据;MySQL 的表数据存储是聚集索引组织表 | 最左匹配原则:按照联合索引的顺序,从前往后依次使用生效,如果中间某个索引没有使用,那么断点前面的索引部分起作用,断点后面的索引没有起作用 |
参数 | 说明 |
---|---|
PRI | 主键索引 |
MUL | 辅助索引 |
UNI | 唯一索引 |
mysql> use world;
Database changed
mysql> desc city;
+-------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| Name | char(35) | NO | | | |
| CountryCode | char(3) | NO | MUL | | |
| District | char(20) | NO | | | |
| Population | int(11) | NO | | 0 | |
+-------------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql> show index from city;
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| city | 0 | PRIMARY | 1 | ID | A | 4046 | NULL | NULL | | BTREE | | |
| city | 1 | CountryCode | 1 | CountryCode | A | 232 | NULL | NULL | | BTREE | | |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec)
1、单列的辅助索引
mysql> alter table city add index idx_name(name);
2、多列的联合索引
mysql> alter table city add index idx_c_p(countrycode,population);
3、唯一索引
mysql> alter table city add unique index uidx_dis(district);
4、前缀索引
mysql> alter table city add index idx_dis(district(5));
5、删除索引
mysql> alter table city drop index idx_name;
将优化器选择后的执行计划截取出来,便于管理管判断语句得执行效率。
mysql> desc select * from test.t_100w where k2='MN89';
+----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| 1 | SIMPLE | t_100w | NULL | ALL | NULL | NULL | NULL | NULL | 997246 | 10.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.03 sec)
表名
值 | 含义 | 性能 | 补充 |
---|---|---|---|
NULL | 无数据 | 高 | |
const(system) | 主键或者唯一键的等值查询 | ↓ | != 和not in等语句走range |
eq_ref | 多表连接时,子表使用主键列或唯一列作为连接条件 | ↓ | |
ref | 辅助索引等值查询 | ↓ | 包括带有union,union all[^1]的查询语句 |
range | 索引范围扫描 | ↓ | > < >= <= , between and ,or,in,like |
index | 全索引扫描 | ↓ | |
ALL | 全表扫描 | 低 | !=(不等于)和not in等不等值语句不走索引 |
[^1]: union:合并两个或多个SELECT 语句的结果集,并对结果去重且排序;union all允许重复 |
指出MySQL能使用哪些索引来优化查询,查询所涉及的列上的索引都会被列出,但不一定会被使用
查询优化器优化查询实际所使用的索引,如果没有可用的索引,则显示为NULL,如查询使用了覆盖索引,则该索引仅出现在Key列中
表示索引字段的最大可能长度,KEY_LEN的长度由字段定义计算而来,并非数据的实际长度,字符长度取决于中文所占字节长度,utf8mb4为4字节,utf8为3字节。
例如varchar(20) utf8mb4
1、能存20个任意字符
2、不管存储的时字符、数字、中文,都1个字符最大预留长度是4个字节
3、对于中文,1个占4个字节
4、对于数字和字母,1个实际占用大小是1个字节
索引长度计算(ken_len越长,说明索引使用的越充分)
类型 | 计算方法(utf8mb4环境下) |
---|---|
int | int最长4字节+非空1字节=5字节 |
char | ()中数字乘4+非空1字节 |
varchar | 开始1字节+()中数字乘4+非空1字节+结束1字节 |
联合索引覆盖长度=所应用索引长度相加 |
Using filesort:在查询中有关排序的条件列没有合理的应用索引,多见于order by、group by、distinct、 union
[root@mysql-1 ~]# mysql -uroot -p1
mysql> create database test charset utf8mb4 collate utf8mb4_bin;
Query OK, 1 row affected (0.00 sec)
mysql> use test;
Database changed
mysql> create table t100w (id int,num int,k1 char(2),k2 char(4),dt timestamp);
Query OK, 0 rows affected (0.01 sec)
mysql> delimiter //
mysql> create procedure rand_data(in num int)
-> begin
-> declare str char(62) default 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
-> declare str2 char(2);
-> declare str4 char(4);
-> declare i int default 0;
-> while i<num do
-> set str2=concat(substring(str,1+floor(rand()*61),1),substring(str,1+floor(rand()*61),1));
-> set str4=concat(substring(str,1+floor(rand()*61),2),substring(str,1+floor(rand()*61),2));
-> set i=i+1;
-> insert into t100w values (i,floor(rand()*num),str2,str4,now());
-> end while;
-> end;
-> //
Query OK, 0 rows affected (0.01 sec)
mysql> delimiter ;
ysql> call rand_data(1000000);
Query OK, 1 row affected (3 min 50.61 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select count(*) from t100w;
+----------+
| count(*) |
+----------+
| 1000000 |
+----------+
1 row in set (0.24 sec)
mysql> desc t100w;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-----------------------------+
| id | int(11) | YES | | NULL | |
| num | int(11) | YES | | NULL | |
| k1 | char(2) | YES | | NULL | |
| k2 | char(4) | YES | MUL | NULL | |
| dt | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
5 rows in set (0.00 sec)
[root@mysql-1 ~]# mysqlslap --defaults-file=/etc/my.cnf \
--concurrency=100 --iterations=1 --create-schema='test' \
--query="select * from test.t100w where k2='6734'" engine=innodb \
--number-of-queries=2000 -uroot -p1 -verbose
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
Benchmark
Running for engine rbose //运行引擎rbose
Average number of seconds to run all queries: 395.284 seconds //运行查询的平均秒数
Minimum number of seconds to run all queries: 395.284 seconds //运行查询的最小秒数
Maximum number of seconds to run all queries: 395.284 seconds //运行查询的最大秒数
Number of clients running queries: 100 //运行查询的客户机数量
Average number of queries per client: 20 //每个客户机的平均查询数
参数 | 说明 |
---|---|
–concurrency | 表示并发量,也就是模拟多少个客户端同时执行query |
–iterations | 测试执行的迭代次数,代表要在不同的并发环境中,各自运行测试多少次 |
–create-schema | 代表自定义的测试库名称 |
–query | 使用自定义脚本或语句执行测试 |
engine | 代表要测试的引擎 |
–number-of-queries | 总的测试查询次数(并发客户数×每客户查询次数) |
-verbose | 日志输出 |
[root@mysql-1 ~]# mysql -uroot -p1
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> alter table t100w add index idx_k2(k2);
Query OK, 0 rows affected (1.46 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> exit
[root@mysql-1 ~]# mysqlslap --defaults-file=/etc/my.cnf --concurrency=100 --iterations=1 --create-schema='test' --query="select * from test.t100w where k2='6734'" engine=innodb --number-of-queries=2000 -uroot -p1 -verbose
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
Benchmark
Running for engine rbose
Average number of seconds to run all queries: 0.803 seconds
Minimum number of seconds to run all queries: 0.803 seconds
Maximum number of seconds to run all queries: 0.803 seconds
Number of clients running queries: 100
Average number of queries per client: 20