MySQL-索引优化篇(1)_安装演示库 & [前缀索引、联合索引、覆盖索引] & explain参数

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: MySQL-索引优化篇(1)_安装演示库 & [前缀索引、联合索引、覆盖索引] & explain参数

20200129003012618.png

生猛干货

带你搞定MySQL实战,轻松对应海量业务处理及高并发需求,从容应对大场面试


官方文档

https://dev.mysql.com/doc/


20200131202811239.png

如果英文不好的话,可以参考 searchdoc 翻译的中文版本

http://www.searchdoc.cn/rdbms/mysql/dev.mysql.com/doc/refman/5.7/en/index.com.coder114.cn.html


20200131203226295.png


安装演示数据库sakila

[root@artisan ~]# wget http://downloads.mysql.com/docs/sakila-db.tar.gz
.....
.....
.....
2020-02-01 21:31:15 (2.74 KB/s) - ‘sakila-db.tar.gz’ saved [732161/732161]
[root@artisan ~]# tar -xvzf sakila-db.tar.gz 
sakila-db/
sakila-db/sakila-data.sql
sakila-db/sakila-schema.sql
sakila-db/sakila.mwb
[root@artisan ~]# cd sakila-db
[root@artisan sakila-db]# ls
sakila-data.sql  sakila.mwb  sakila-schema.sql
[root@artisan sakila-db]# mysql -uroot -p < sakila-schema.sql 
Enter password: 
[root@artisan sakila-db]# mysql -uroot -p < sakila-data.sql 
Enter password: 
[root@artisan sakila-db]# 



20200201224419803.png


索引优化策略

索引列上不能使用表达式或者函数

举个例子

select  .... from t_order
where to_days(out_date) - to_days(current_date) < = 30 


20200201225525673.png


即使我们在out_date建立了 B树索引,因为使用了函数to_days,无法走索引。

那该如何改造呢? ------------> 如下

select  .... from t_order
where out_date <= data_add(current_date , interval 30 day) ; 


20200201225623202.png



前缀索引和索引列的选择性


当索引是很长的字符序列(比如BLOB,TEXT,或者很长的VARCHAR)时,这个索引将会很占内存,而且会很慢,这时候就会用到前缀索引了。所谓的前缀索引就是去索引的前面几个字母作为索引,但是要降低索引的重复率,索引我们还必须要判断前缀索引的重复率


前缀索引的创建


创建前缀索引

create index index_name on table(col_name(n));


注意建立索引的区别 col_name(n)

这个n的长度,取悦于存储引擎

  • innodb 最大767个字节
  • myIsam 最大1000个直接


索引列的选择性


索引的选择性是指不重复的索引值和表的记录数的比值

选择性越高,查询效率越快。 因为选择性高的索引可以让MySQL在查找时过滤掉更多的行。唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。


举个例子:

有4条记录


20200201231121857.png


如果前缀索引,我们创建的时候,长度设置的是2 , 那么

20200201231552160.png



不重复的索引为 2 ,总记录数为4 , 索引选择性 0.5


如果设置为 3 ,则


20200201231606171.png


不重复的索引为 4 ,总记录数为4 , 索引选择性1 . 此时,性能最高,因为不用过滤数据啊。


合理选择,对提高查询性能帮助很大


前缀索引的优缺点

优点:

  • 前缀索引是一种能使索引更小,更快的有效办法 。

缺点:

  • mysql无法使用其前缀索引做ORDER BY和GROUP BY,也无法使用前缀索引做覆盖扫描。


联合索引

如何选择索引列的顺序


  • 经常会被使用到的列优先,放到联合索引的最左边 。
  • 但也不是绝对的,举个例子 有个状态 state,就几个值, 选择性很差(因为根据每个state,筛选出来的数据太多了。。。)就不适合放到联合索引的最左边 ,放到了最左边,mysql也不一定使用
  • 选择性高的列优先 。
  • 啥叫选择性高的列? 比如根据这个列 经过筛选后,能够把大部分的数据都过滤掉,之剩下很少的数据,那么就可以把这列称为选择性高的列。
  • 宽度小的列优先
    当然了有个前提,不违反选择性。 宽度小意味着I/O 少,效率高


覆盖索引

定义

覆盖索引: 如果一个索引包含(或覆盖)所有需要查询的字段的值 ,简言之----->只需扫描索列而无须回表查非索引列的字段。


优点

  • 可优化缓存,减少磁盘I/O操作
    举个例子: 一个表 15个字段, 索引字段 3个, 我们就查询这3个索引列的值,而不用回表,查询的字段少,可以缓存更多的数据,同时从内存中获取,可以极大的减少磁盘I/O操作
  • 可以减少随机I/O, 变随机I/O为顺序I/O操作
  • 可以避免对Innodb主键索引的二次查询
  • 可以避免MyISAM表进行系统调用


无法使用覆盖索引的情况

  • 有些存储引擎不支持覆盖索引
  • 如果查询中使用了太多的列,尤其是那种查询全部字段的,或者 select * 的
  • 使用了双% 号的like查询


演示

我们用刚才导入的 sakila 数据 来演示下

select * 无法使用覆盖索引的演示:

[root@artisan sakila-db]# mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 63
Server version: 5.7.29-log MySQL Community Server (GPL)
.......
.......
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| artisan            |
| artisanBinLog      |
| data               |
| mysql              |
| performance_schema |
| sakila             |
| sys                |
+--------------------+
8 rows in set (0.01 sec)
mysql> use sakila;
No connection. Trying to reconnect...
Connection id:    64
Current database: *** NONE ***
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> show tables;
+----------------------------+
| Tables_in_sakila           |
+----------------------------+
| actor                      |
| actor_info                 |
| address                    |
| category                   |
| city                       |
| country                    |
| customer                   |
| customer_list              |
| film                       |
| film_actor                 |
| film_category              |
| film_list                  |
| film_text                  |
| inventory                  |
| language                   |
| nicer_but_slower_film_list |
| payment                    |
| rental                     |
| sales_by_film_category     |
| sales_by_store             |
| staff                      |
| staff_list                 |
| store                      |
+----------------------------+
23 rows in set (0.00 sec)
mysql> desc film;
+----------------------+---------------------------------------------------------------------+------+-----+-------------------+-----------------------------+
| Field                | Type                                                                | Null | Key | Default           | Extra                       |
+----------------------+---------------------------------------------------------------------+------+-----+-------------------+-----------------------------+
| film_id              | smallint(5) unsigned                                                | NO   | PRI | NULL              | auto_increment              |
| title                | varchar(128)                                                        | NO   | MUL | NULL              |                             |
| description          | text                                                                | YES  |     | NULL              |                             |
| release_year         | year(4)                                                             | YES  |     | NULL              |                             |
| language_id          | tinyint(3) unsigned                                                 | NO   | MUL | NULL              |                             |
| original_language_id | tinyint(3) unsigned                                                 | YES  | MUL | NULL              |                             |
| rental_duration      | tinyint(3) unsigned                                                 | NO   |     | 3                 |                             |
| rental_rate          | decimal(4,2)                                                        | NO   |     | 4.99              |                             |
| length               | smallint(5) unsigned                                                | YES  |     | NULL              |                             |
| replacement_cost     | decimal(5,2)                                                        | NO   |     | 19.99             |                             |
| rating               | enum('G','PG','PG-13','R','NC-17')                                  | YES  |     | G                 |                             |
| special_features     | set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') | YES  |     | NULL              |                             |
| last_update          | timestamp                                                           | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+----------------------+---------------------------------------------------------------------+------+-----+-------------------+-----------------------------+
13 rows in set (0.00 sec)
#  查询 索引列  language_id    重点看  Extra 
mysql> explain select language_id from film where language_id = 1 \G ;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film
   partitions: NULL
         type: ref
possible_keys: idx_fk_language_id  -----> 可能用的索引 
          key: idx_fk_language_id     ----------------> 实际使用的索引
      key_len: 1
          ref: const
         rows: 1000
     filtered: 100.00
        Extra: Using index  ---------------->使用了索引,因为仅查询了索引列,这里就是覆盖索引
1 row in set, 1 warning (0.07 sec)
ERROR: 
No query specified
# 查看执行计划   重点看  Extra 
mysql> explain select *  from film where language_id = 1 \G ;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film
   partitions: NULL
         type: ALL  ---------------------->  连接类型
possible_keys: idx_fk_language_id  -----> 可用的索引
          key: NULL    ----------------> 实际的索引
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 100.00
        Extra: Using where  -------------------->   using where:表示优化器需要通过索引回表查询数据;
1 row in set, 1 warning (0.00 sec)
ERROR: 
No query specified
mysql> 



在来看个例子

mysql> show create table actor \G ;
*************************** 1. row ***************************
       Table: actor
Create Table: CREATE TABLE `actor` (
  `actor_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `first_name` varchar(45) NOT NULL,
  `last_name` varchar(45) NOT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`actor_id`),
  KEY `idx_actor_last_name` (`last_name`)
) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
ERROR: 
No query specified
mysql> explain select actor_id , last_name from actor where last_name = 'Joe' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: actor
   partitions: NULL
         type: ref
possible_keys: idx_actor_last_name
          key: idx_actor_last_name
      key_len: 182
          ref: const
         rows: 1
     filtered: 100.00
        Extra: Using index   ------> using index 表示直接访问索引就足够获取到所需要的数据,不需要通过索引回表;
1 row in set, 1 warning (0.30 sec)


主键 actor_id ,默认就是索引 ,所以虽然增加了 actor_id , last_name也是索引列(创建primary key的时候肯定会创建一个unique index。),所以这个查询也是使用了覆盖索引。


explain的几个参数的说明

        id: 1
  select_type: SIMPLE
        table: actor
   partitions: NULL
         type: ref
possible_keys: idx_actor_last_name
          key: idx_actor_last_name
      key_len: 182
          ref: const
         rows: 1
     filtered: 100.00
        Extra: Using index 



id


select_type: 查询中每个select子句的类型


(1) SIMPLE(简单SELECT,不使用UNION或子查询等)


(2) PRIMARY(查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)


(3) UNION(UNION中的第二个或后面的SELECT语句)


(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)


(5) UNION RESULT(UNION的结果)


(6) SUBQUERY(子查询中的第一个SELECT)


(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,取决于外面的查询)


(8) DERIVED(派生表的SELECT, FROM子句的子查询)


(9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)


type 代表连接类型


常用的类型有: ALL, index, range, ref, eq_ref, const, system, NULL


从左到右,性能从差到好 , ALL 最差, NULL最好


ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行


index: Full Index Scan,index与ALL区别为index类型只遍历索引树


range:只检索给定范围的行,使用一个索引来选择行


ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值


eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件


const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system


NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。


possible_keys: 可用的索引 ,实际不一定用


keys : MyQL实际的索引


key_len: 表示索引中使用的字节数


extra (需重点关注)

1) using tempoaray : 中间使用了临时表

2) using index 表示直接访问索引就足够获取到所需要的数据,不需要通过索引回表;

3) using index condition:5.6加入 ,会先条件过滤索引,过滤完索引后找到所有符合索引条件的数据行,随后用 WHERE 子句中的其他条件去过滤这些数据行;

4) using where: 未使用索引,通过where条件过滤


搞定MySQL


https://artisan.blog.csdn.net/article/details/104139438?spm=1001.2014.3001.5502

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
11天前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
94 9
|
3天前
|
关系型数据库 MySQL 数据库
【MySQL基础篇】MySQL概述、Windows下载MySQL8.0超详细图文安装教程
在这一章节,主要介绍两个部分,数据库相关概念及MySQL数据库的介绍、下载、安装、启动及连接。接着,详细描述了MySQL 8.0的版本选择与下载,推荐使用社区版(免费)。安装过程包括自定义安装路径、配置环境变量、启动和停止服务、以及客户端连接测试。此外,还提供了在同一台电脑上安装多个MySQL版本的方法及卸载步骤。最后,解释了关系型数据库(RDBMS)的特点,即基于二维表存储数据,使用SQL语言进行操作,格式统一且便于维护。通过具体的结构图展示了MySQL的数据模型,说明了数据库服务器、数据库、表和记录之间的层次关系。
【MySQL基础篇】MySQL概述、Windows下载MySQL8.0超详细图文安装教程
|
9天前
|
关系型数据库 MySQL 数据库
docker高级篇(大厂进阶):安装mysql主从复制
docker高级篇(大厂进阶):安装mysql主从复制
71 24
|
4天前
|
NoSQL 关系型数据库 MySQL
Linux安装jdk、mysql、redis
Linux安装jdk、mysql、redis
69 7
|
8天前
|
存储 Oracle 关系型数据库
索引在手,查询无忧:MySQL索引简介
MySQL 是一款广泛使用的关系型数据库管理系统,在2024年5月的DB-Engines排名中得分1084,仅次于Oracle。本文介绍MySQL索引的工作原理和类型,包括B+Tree、Hash、Full-text索引,以及主键、唯一、普通索引等,帮助开发者优化查询性能。索引类似于图书馆的分类系统,能快速定位数据行,极大提高检索效率。
34 8
|
13天前
|
缓存 关系型数据库 MySQL
MySQL 索引优化与慢查询优化:原理与实践
通过本文的介绍,希望您能够深入理解MySQL索引优化与慢查询优化的原理和实践方法,并在实际项目中灵活运用这些技术,提升数据库的整体性能。
46 5
|
2天前
|
存储 关系型数据库 MySQL
【MYSQL】 ——索引(B树B+树)、设计栈
索引的特点,使用场景,操作,底层结构,B树B+树,MYSQL设计栈
|
5天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
19 3
|
5天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
24 3
|
5天前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE &#39;log_%&#39;;`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
29 2