MySQL 索引管理及执行计划(十)

1.1 什么是索引

索引就像一本书的目录,它可以让你更快的找到内容,并让获取的数据更有目的性,从而提高数据库检索数据的性能。

1.2 索引的设计理念

1.2.1 尽量获取更少更有意义的数据

集群因子:索引叶子节点获取的数据大于真实数据页的时候,索引是没有意义的。

1.2.2 尽量使用唯一性比较好的条件进行创建索引

  • 主键列:一旦某一列被指定为主键,MySQL会自动创建主键索引,将来使用此列作为条件进行查询的时候就有可能使用索引查询。
  • 走不走索引的决定权在优化器上

MySQL会根据用户输入的语句进行自动判断,符合条件才有可能使用索引查询。

提示:在where条件关键字后面的列建立索引才会加快查询速度。

1.3 数据库索引的设计原则

为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引。

  • 选择唯一性索引

唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录。

例如,学生表中学号是具有唯一性的字段。为该字段建立唯一性索引可以很快的确定某个学生的信息。如果使用姓名的话,可能存在同名现象,从而降低查询速度。

  • 为经常需要排序、分组和联合操作的字段建立索引

经常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作会浪费很多时间。如果为其建立索引,可以有效地避免排序操作。

  • 为常作为查询条件的字段建立索引

如果某个字段经常用来做查询条件,那么该字段的查询速度会影响整个表的查询速度。因此,

为这样的字段建立索引,可以提高整个表的查询速度。

  • 限制索引的数目

索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。

  • 尽量使用数据量少的索引

如果索引的值很长,那么查询的速度会受到影响。例如,对一个CHAR(100)类型的字段进行全文检索需要的时间肯定要比对CHAR(10)类型的字段需要的时间要多。

  • 尽量使用前缀来索引

如果索引字段的值很长,最好使用值的前缀来索引。例如,TEXT和BLOG类型的字段,进行全文检索会很浪费时间。如果只检索字段的前面的若干个字符,这样可以提高检索速度。

  • 删除不再使用或者很少使用的索引

表的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。

  • 小表不应建立索引
  • 包含大量的列并且不需要搜索非空值的时候可以考虑不建索引

1.4 不走索引的几种常见情况:

  1. 集群因子过大可能不走索引
  2. 结果集的条目占总数据量的30%的时候,优化器就觉得走全表扫描计划更好(没有where,<,>)
  3. 默认的order by单独使用的时候,优化器也觉得全表的方式更好(where和limit)
  4. 子查询尽量避免使用union或者union all
  5. select使用了不合理的条件或功能(没有where、逻辑计算符、算术运算符+-*/、函数sum等)
  6. 带有select * 可能不走索引
  7. where 条件中有like并且’%a%’,此时可能不会走索引
  8. 没有查询条件或查询条件没有建立索引
  9. 在查询条件上没有使用引导列
  10. 查询的数量是大表的大部分,应该是30%以上
  11. 索引本身失效
  12. 查询条件使用函数再索引列上,或者对索引列进行计算,运算包括(+,-,*,/,!等)
  13. 对小表查询
  14. 提示不使用索引
  15. 统计数据不真实
  16. 优化器计算走索引花费过大的情况
  17. 隐式转换导致索引失效(这一点应当引起重视,也是开发中经常会犯的错误)
  18. 由于表的字段a定义为varchar类型,但在查询时把该字段作为number类型以where条件传给数据库,这样会导致索引失效
  19. <>或><有时会用到,有时不会
  20. like “%” 百分号在前时
  21. 表没分析
  22. 单独引用复合索引里非第一位置的索引列
  23. 字符型字段为数字时在where条件里不添加引号
  24. 对索引列进行运算,需要建立函数索引
  25. not in,not exit
  26. 当变量采用的是times变量,而表的字段采用的是date变量时,或相反的情况
  27. B- tree索引is null不会走,is not null会走,位图索引is null,is not null 多会走
提示:全表扫描时是从头到尾扫描数据页,顺序IO。

1.5 无法使用索引的几种常见情况

  1. MyISAM 存储引擎索引键长度总和不能超过1000 字节;
  2. BLOB 和TEXT 类型的列只能创建前缀索引;
  3. MySQL 目前不支持函数索引;
  4. 使用不等于(!= 或者<>)的时候MySQL 无法使用索引;
  5. 过滤字段使用了函数运算后(如abs(column)),MySQL 无法使用索引;
  6. Join 语句中Join 条件字段类型不一致的时候MySQL 无法使用索引;
  7. 使用LIKE 操作的时候如果条件以通配符开始( ‘%abc…’)MySQL 无法使用索引;
  8. 使用非等值查询的时候MySQL 无法使用Hash 索引;

在我们使用索引的时候,需要注意上面的这些限制,尤其是要注意无法使用索引的情况,因为这很容易让我们因为疏忽而造成极大的性能隐患。

1.6 MySQL数据库中索引的类型介绍

  • BTREE:B+树索引
  • HASH:HASH索引
  • FULLTEXT:全文索引
  • RTREE:R树索引

第2章 索引管理

索引是建立在表的列上(字段)的,在where后面的列建立索引才会加快查询速度。

2.1 索引分类

2.1.1 普通索引

普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。因此,只为经常出现在查询条件(WHERE)或排序条件(ORDERBY)中的数据列创建索引。只要有可能,就应该选择一个数据最整齐、最紧凑的数据列(如一个整数类型的数据列)来创建索引。

提示:普通索引是加快查询速度,工作中优化数据库的关键,在合适的列上建立索引,可以让数据查询更高效。

2.1.2 唯一索引

唯一索引不允许两行具有相同的索引值。如果现有数据中存在重复的键值,则大多数数据库都不允许将新创建的唯一索引与表一起保存,当新数据将使表中的键值重复时,数据库也拒绝接受此数据。

例如,如果在 employee 表中的职员姓氏(lname) 列上创建了唯一索引,则所有职员不能同姓。

2.1.3 主键索引

在数据库关系图中为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型,其唯一索引名为primary,数据库表通常有一列或多列组合,其值用来唯一标识表中的每一行。。主键索引要求主键中的每个值是唯一的。当在查询中使用主键索引时,它还允许快速访问数据。

提示:表创建的时候至少要有一个主键索引,最好和业务无关。

2.2 索引相关命令

2.2.1 添加普通索引

2.2.1.1 alter创建索引

【语法】:

ALTER TABLE 表名 ADD 索引名(列名);

【示例】:

mysql> alter table test add index name_idx(name);

mysql> desc test;
+-------+------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| id    | int(4)     | NO   | PRI | NULL    | auto_increment |
| name  | char(20)   | NO   | MUL | NULL    |                |
| state | tinyint(2) | NO   |     | 1       |                |
+-------+------------+------+-----+---------+----------------+
3 rows in set (0.34 sec)

2.2.1.2 create创建索引

【语法】:

CREATE INDEX 索引名 ON 表(列名);

【示例】:

mysql> create index index_name on test(name);

2.2.2 添加唯一索引

【语法】:

CREATE UNIQUE INDEX 索引名 ON 表(列名);

【示例】:

mysql> create unique index name_idx on test(name);

mysql> desc test;
+-------+------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| id    | int(4)     | NO   | PRI | NULL    | auto_increment |
| name  | char(20)   | NO   | UNI | NULL    |                |
| state | tinyint(2) | NO   |     | 1       |                |
+-------+------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

2.2.3 创建主键索引

2.2.3.1 建立表时

mysql> CREATE TABLE `test2` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`name` char(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
Query OK, 0 rows affected (0.44 sec)

mysql> show index from test2;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test2 | 0          | PRIMARY  | 1            | id          | A         | 0           | NULL     | NULL   |      | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.01 sec)

2.2.3.2 建立表后增加

mysql> CREATE TABLE `test3` (
`id` int(4) NOT NULL,
`name` char(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
Query OK, 0 rows affected (0.27 sec)

mysql> show index from test3;
Empty set (0.03 sec)

mysql> alter table test3 change id id int(4) primary key not null auto_increment;
Query OK, 0 rows affected (0.50 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from test3;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test3 | 0          | PRIMARY  | 1            | id          | A         | 0           | NULL     | NULL   |      | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.14 sec)

2.2.4 查询索引信息

2.2.4.1 desc查询索引

【语法】:

DESC 表名;

2.2.4.2 show查询索引

【语法】:

SHOW INDEX FROM 表名\G

2.2.5 删除索引

【语法】:

ALTER TABLE 表名 DROP 索引名(列名);

【示例】:

mysql> alter table test drop index name_idx;

2.3 使用字段前缀创建索引及联合索引

2.3.1 前缀索引

根据字段的前N个字符建立索引。

【语法】:

CREATE INDEX 索引名 ON 表(列名);

【示例】:

mysql> create index name_idx on test(name(8));

mysql> show index from test;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test | 0           | PRIMARY  | 1            | id          | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
| test | 1           | name_idx | 1            | name        | A         | 5           | 8        | NULL   |      | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec)

2.3.2 联合索引

使用多个字段建立一个索引。

【语法】:

ALTER TABLE 表名 ADD INDEX 索引名(列名1,列名2...);

2.3.2.1 普通联合索引

mysql> alter table test add index idname_idx(id,name);
Query OK, 0 rows affected (0.41 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc test;
+-------+------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| id    | int(4)     | NO   | PRI | NULL    | auto_increment |
| name  | char(20)   | NO   | MUL | NULL    |                |
| state | tinyint(2) | NO   |     | 1       |                |
+-------+------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> show index from test;
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test | 0           | PRIMARY      | 1            | id          | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
| test | 1           | name_sex_idx | 1            | name        | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
| test | 1           | name_sex_idx | 2            | sex         | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
提示:联合索引是前缀生效模式,所以把最常用来作为条件查询的列放在前面可以使用索引查询,否则可能不走索引查询。如查询条件为:where a and b and c,此时:
  1. a,ab,abc 可能走索引
  2. b ac bc c 可能不走索引

 

实例 2-1 联合索引示例

mysql> alter table test add sex char(4) not null after name;
Query OK, 0 rows affected (0.41 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc test;
+-------+------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| id    | int(4)     | NO   | PRI | NULL    | auto_increment |
| name  | char(20)   | NO   |     | NULL    |                |
| sex   | char(4)    | NO   |     | NULL    |                |
| state | tinyint(2) | NO   |     | 1       |                |
+-------+------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql> select id,name,sex from test;
+----+---------+-----+
| id | name    | sex |
+----+---------+-----+
|  1 | leon    | nan |
|  4 | meinv   | nv  |
|  2 | shadow  | nan |
|  3 | shuaige | nan |
|  5 | wangzi  | nan |
+----+---------+-----+
5 rows in set (0.00 sec)

mysql> create index name_sex_idx on test(name,sex);
Query OK, 0 rows affected (16.22 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from test;
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test  | 0          | PRIMARY      | 1            | id          | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
| test  | 1          | name_sex_idx | 1            | name        | A         | 5           | 8        | NULL   |      | BTREE      |         |               |
| test  | 1          | name_sex_idx | 2            | sex         | A         | 5           | 2        | NULL   |      | BTREE      |         |               |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
mysql> explain select id,name from test where name='leon';
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test  | 0          | PRIMARY     | 1            | id          | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
| test  | 1          | name_sex_idx| 1            | name        | A         | 5           | 8        | NULL   |      | BTREE      |         |               |
| test  | 1          | id_name_idx | 2            | name        | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

mysql> explain select id,name from test where sex='nv';
+----+-------------+-------+-------+---------------+--------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys | key          | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+--------------+---------+------+------+--------------------------+
| 1  | SIMPLE      | test  | index | NULL          | name_sex_idx | 72      | NULL | 5    | Using where; Using index |
+----+-------------+-------+-------+---------------+--------------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

mysql> explain select id,name from test where name='meinv' and sex='nv';
+----+-------------+-------+------+---------------+--------------+---------+-------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key          | key_len | ref         | rows | Extra                    |
+----+-------------+-------+------+---------------+--------------+---------+-------------+------+--------------------------+
| 1  | SIMPLE      | test  | ref  | name_sex_idx  | name_sex_idx | 72      | const,const | 1    | Using where; Using index |
+----+-------------+-------+------+---------------+--------------+---------+-------------+------+--------------------------+
1 row in set (0.03 sec)

# 不使用索引查询的情况
mysql> explain select id,name from test where id=1;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| 1  | SIMPLE      | test  | const | PRIMARY       | PRIMARY | 4       | const | 1    | NULL  |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
1 row in set (0.00 sec)

2.3.2.2 联合主键是联合索引的特殊形式

mysql> create index id_name_idx on test(id,name);
Query OK, 0 rows affected (0.25 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from test;
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test  | 0          | PRIMARY      | 1            | id          | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
| test  | 1          | name_sex_idx | 1            | name        | A         | 5           | 8        | NULL   |      | BTREE      |         |               |
| test  | 1          | name_sex_idx | 2            | sex         | A         | 5           | 2        | NULL   |      | BTREE      |         |               |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

2.3.2.3 前缀加联合索引

mysql> create index name_sex_idx on test(name(8),sex(2));
Query OK, 0 rows affected (0.24 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from test;
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test  | 0          | PRIMARY     | 1            | id          | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
| test  | 1          | id_name_idx | 1            | id          | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
| test  | 1          | id_name_idx | 2            | name        | A         | 5           | NULL     | NULL   |      | BTREE      |         |               |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

第3章 索引的企业应用场景

3.1 企业SQL优化思路

把一个大的不使用索引的SQL语句按照功能进行拆分

  • 【列多的情况】

意味着将来需要按照查询需求建立更多的索引,维护(如insert、delete等)很麻烦,数据增删的时候索引会有较大自动调整,性能问题可能会造成索引失效,会给业务查询造成灾难性后果。

【解决方法】:根据业务逻辑,纵向拆分大表

create t1
insert into ti as select id,name from t2;
  • 【行多的情况】:

意味着将来叶子节点就会很多,导致将来在获取数据页指针的时候需要优化更多的时间去遍历索引树。

【解决方法】:根据业务逻辑,横向拆分大表

表分区或分表
  • 长的SQL语句无法使用索引,能不能变成2条短的SQL语句让它分别使用上索引
  • 对SQL语句功能的拆分和修改
  • 减少“烂”SQL,由运维(DBA)和开发交流(确认),共同确定如何改,最终由DBA执行
  • 制定开发流程

3.2 不适合走索引的场景

  1. 唯一值少的列上不适合建立索引或者建立索引效率低。例如:性别列
  2. 小表可以不建立索引,100条记录以内
  3. 对于数据仓库,大量全表扫描的情况,建索引反而会慢
  4. 索引没有存放null指针,索引自己就会失效。

3.3 如何选择合适的索引行

使用count(*)统计所有行数和count(distinct 列名)统计去除重复行后的行数量进行比较,如果数量相同则适合做索引,否则可以在选择其他行一起统计,直到去除重复行后和总数相同时为止,使用统计的行做联合索引。

mysql> create user root@'172.16.1.%' identified by '123456';
Query OK, 0 rows affected (0.34 sec)

mysql> select user,host from mysql.user;
+--------+-------------+
| user   | host        |
+--------+-------------+
| blog   | 172.16.1.%  |
| leon   | 172.16.1.%  |
| root   | 172.16.1.%  |
| shadow | 172.16.1.4% |
| root   | localhost   |
| system | localhost   |
+--------+-------------+
6 rows in set (0.00 sec)
# 统计总行数
mysql> select count(*) from mysql.user;
+----------+
| count(*) |
+----------+
|        6 |
+----------+
1 row in set (0.16 sec)
# 统计单行去重后数量,和总行数不相同则继续增加字段重新统计
mysql> select count(distinct user) from mysql.user;
+----------------------+
| count(distinct user) |
+----------------------+
|                    5 |
+----------------------+
1 row in set (0.19 sec)
# 统计多行去重后数量,和总数相同则使用此多行创建联合索引
mysql> select count(distinct user,host) from mysql.user;
+---------------------------+
| count(distinct user,host) |
+---------------------------+
|                         6 |
+---------------------------+
1 row in set (0.31 sec)

3.4 创建索引流程

3.4.1 找到慢SQL

记录慢查询日志:

show processlist;

3.4.2 explain select句

explain select ...

3.4.3 查看表的唯一值数量

select count(*) from 表;
select count(列1,列2...) from 表;
提示:条件列多时可以考虑建立联合索引。

3.4.4 建立索引

在流量低谷时创建索引。

force index

3.5 企业生产创建索引模拟

3.5.1 查找慢SQL语句

mysql> use world;
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> select name from country where name like 'c%' limit 10;
+---------------------------------------+
| name                                  |
+---------------------------------------+
| Central African Republic              |
| Canada                                |
| Cocos (Keeling) Islands               |
| Chile                                 |
| China                                 |
| C te d’Ivoire                         |
| Cameroon                              |
| Congo, The Democratic Republic of the |
| Congo                                 |
| Cook Islands                          |
+---------------------------------------+
10 rows in set (0.05 sec)

3.5.2 查看查询慢的原因

查看表结构发现没有创建索引:

mysql> desc country;
+----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+
| Field          | Type                                                                                  | Null | Key | Default | Extra |
+----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+
| Code           | char(3)                                                                               | NO   | PRI |         |       |
| Name           | char(52)                                                                              | NO   |     |         |       |
| Continent      | enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') | NO   |     | Asia    |       |
| Region         | char(26)                                                                              | NO   |     |         |       |
| SurfaceArea    | float(10,2)                                                                           | NO   |     | 0.00    |       |
| IndepYear      | smallint(6)                                                                           | YES  |     | NULL    |       |
| Population     | int(11)                                                                               | NO   |     | 0       |       |
| LifeExpectancy | float(3,1)                                                                            | YES  |     | NULL    |       |
| GNP            | float(10,2)                                                                           | YES  |     | NULL    |       |
| GNPOld         | float(10,2)                                                                           | YES  |     | NULL    |       |
| LocalName      | char(45)                                                                              | NO   |     |         |       |
| GovernmentForm | char(45)                                                                              | NO   |     |         |       |
| HeadOfState    | char(60)                                                                              | YES  |     | NULL    |       |
| Capital        | int(11)                                                                               | YES  |     | NULL    |       |
| Code2          | char(2)                                                                               | NO   |     |         |       |
+----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+
15 rows in set (0.00 sec)
mysql> explain select name from country where name like 'c%' limit 10;
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| 1  | SIMPLE      | country | ALL  | NULL          | NULL | NULL    | NULL | 239  | Using where |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

3.5.3 检查创建索引的条件

发现单列满足索引条件:

mysql> select count(*) from country;
+----------+
| count(*) |
+----------+
|      239 |
+----------+
1 row in set (0.11 sec)

mysql> select count(distinct name ) from country;
+-----------------------+
| count(distinct name ) |
+-----------------------+
|                   239 |
+-----------------------+
1 row in set (0.00 sec)

3.5.4 创建索引

mysql> alter table country add index name_idx(name);
Query OK, 0 rows affected (0.28 sec)
Records: 0  Duplicates: 0  Warnings: 0

3.5.5 查看索引建立后查询情况

发现已经使用索引,并加快了查询速度:

mysql> select name from country where name like 'c%' limit 10;
+--------------------------+
| name                     |
+--------------------------+
| Cambodia                 |
| Cameroon                 |
| Canada                   |
| Cape Verde               |
| Cayman Islands           |
| Central African Republic |
| Chad                     |
| Chile                    |
| China                    |
| Christmas Island         |
+--------------------------+
10 rows in set (0.00 sec)

mysql> explain select name from country where name like 'c%' limit 10;
+----+-------------+---------+-------+---------------+----------+---------+------+------+--------------------------+
| id | select_type | table   | type  | possible_keys | key      | key_len | ref  | rows | Extra                    |
+----+-------------+---------+-------+---------------+----------+---------+------+------+--------------------------+
| 1  | SIMPLE      | country | range | name_idx      | name_idx | 52      | NULL | 22   | Using where; Using index |
+----+-------------+---------+-------+---------------+----------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

 

温馨提示:本文最后更新于2022-12-20 20:57:51,已超过493天没有更新。某些文章具有时效性,若文章内容或图片资源有错误或已失效,请联系站长。谢谢!
转载请注明本文链接:https://blog.leonshadow.cn/763482/738.html
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享