从0开始回顾MySQL---系列九

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: SQL优化1、一条sql语句执行很慢的原因有哪些? ⚡ 一个SQL执行的很慢,我们要分两种情况讨论:1. 大多数情况下很正常,偶尔很慢,则有如下原因:● 数据库在刷新脏页(内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页),例如redo log 写满了需要同步到磁盘。 ● 执行的时候,遇到锁,如表锁、行锁。 ● sql语句写的不好。 2. 这条SQL语句一直执行的很慢,则有如下原因:● 没有用上索引或者索引失效:比如该字段没有索引,由于对字段进行运算、函数操作导致无法用索引。 ● 有索引可能会走全表扫描: ○ 怎样判断是否走全表扫描? ○ 某

SQL优化


1、一条sql语句执行很慢的原因有哪些?


一个SQL执行的很慢,我们要分两种情况讨论:

  1. 大多数情况下很正常,偶尔很慢,则有如下原因
  • 数据库在刷新脏页(内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页),例如redo log 写满了需要同步到磁盘。
  • 执行的时候,遇到锁,如表锁、行锁。
  • sql语句写的不好。
  1. 这条SQL语句一直执行的很慢,则有如下原因
  • 没有用上索引或者索引失效:比如该字段没有索引,由于对字段进行运算、函数操作导致无法用索引。
  • 有索引可能会走全表扫描:
  • 怎样判断是否走全表扫描?
  • 某一列中不重复数据的个数称为基数,而数据量大时不可能全部扫描一遍得到基数,而是采样部分数据进行预测,那有可能预测错了,导致走全表扫描。
  • MySQL的索引都是排好序的。如果区分度高排序越快,区分度越低,排序慢;  

2、慢SQL如何定位呢?


慢SQL的监控主要通过两个途径:

  • 慢查询日志 :开启MySQL的慢查询日志,再通过一些工具比如mysqldumpslow去分析对应的慢查询日志,当然现在一般的云厂商都提供了可视化的平台。
  • 服务监控 :可以在业务的基建中加⼊对慢SQL的监控,常见的方案有字节码插桩、连接池扩展、ORM框架过程,对服务运行中的慢SQL进行监控和告警。
-- 查看慢查询日志配置信息
show variables like ‘slow_query%’;
-- 开启慢查询日志
set global slow_query_log = on;

3、explain执行计划


对于低性能的SQL语句的定位,最重要也是最有效的方法就是使用执行计划,MySQL提供了explain命令来查看语句的执行计划。

explain的作用

  1. 描述 MySQL 如何执行查询操作、执行顺序,使用到的索引,以及 MySQL 成功返回结果集需要执行的行数。
  2. 可以帮助我们分析 select 语句,让我们知道查询效率低下的原因,从而改进我们的查询,让查询优化器能够更好的工作。

语法

explain + select 语句;


在执行计划中,我们重点关注以下几列:

1、ID列 一组数字,表示 sql 语句中 select 的执行顺序,有几个 select 就有几个 id,按照 select 出现的顺序呈现结果。

  • id 相同,执行顺序由上而下;
  • id 不同,序号会递增。值越大优先级越高,就越先执行。

2、select_type 列:查询语句的类型

  • simple   简单查询;
  • primary 复杂查询;
  • subquery 子查询,在 select 中的子查询(不在 from 子句中);
  • derived 衍生查询,在 from 子句中子查询,MySQL 会将结果存放在一个临时表中,也称为派生表(derived 的英文含义)

3、type 列:表关联类型或访问类型,重要的一列,是判断查询是否高效的一句:也就是 MySQL 决定如何查找表中的行就看这个列。

type类型

解释

ALL

全表扫描,性能极差

index

全索引扫描,跟 ALL 差不多,不同的是 index 是扫描整棵索引树,比 ALL 要快些。

range

范围扫描,通常出现在 in (), between ,> ,<, >= 等操作中。使用一个索引来检索给定范围的行。

ref

索引查找,不使用唯一索引,使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。

eq_ref

最多只返回一条符合条件的记录。在使用唯一性索引或主键查找时会出现该值,非常高效。

const/system

该表至多有一个匹配行,在查询开始时读取,或者该表是系统表,只有一行匹配。其中 const 用于在和 primary key 或 unique 索引中有固定值比较的情形。

  • ALL 是最差的,system 是最好的,性能最佳,阿里巴巴开发规约中要求最差也得到 range 级别,而不能有 index、ALL。

4、Extra 列:额外信息,也非常重要

  • Using index:使用覆盖索引,表示查询索引就可查到所需数据,不用回表,说明性能不错。
  • Using where:在存储引擎检索行后再进行过滤,就是先读取整行数据,再按 where 条件进行取舍。
  • Using temporary:mysql 需要创建一张临时表来处理查询,一般是因为查询语句中有排序、分组、和多表 join 的情况,一般是要进行优化的。
  • Using filesort:文件排序,一般在内存中进行排序,占用CPU较多。如果待排结果较大,会产生临时文件I/O到磁盘进行排序,效率较低

4、MySQL优化


索引

  1. 尽量使用 覆盖索引 进行查询,避免 回表 带来的性能损耗。(一个索引包含(覆盖)所有需要查询字段的值,被称之为"覆盖索引")
  2. 组合索引符合最左匹配原则;
  3. 写多读少,选用普通索引更好,可以利用change buffer进行性能优化减少磁盘lO,将更新操作记录到change bufer,等查询来了将数据读到内存再进行修改;
  4. 尽量避免索引失效
  5. 索引建立原则:
  • 为列的基数大的列创建索引;
  • 索引列的类型尽量小;
  • 只为用于搜索、排序或分组的列创建索引;
  • 尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
  • 为了尽可能少的让 聚簇索引 发生页面分裂和记录移位的情况,建议让主键拥有 AUTO_INCREMENT 属性。
  • 对于插入、更新、删除等 DML 操作比较频繁的表,不适合建立索引

SQL语句

  1. 不使用 SELECT * 查询,而是使用 SELECT <字段列表> 查询;
  2. WHERE 从句中不对列进行函数转换和计算(避免索引失效);
  3. 避免数据类型的隐式转换( 隐式转换会导致索引失效如:  where id = '111')
  4. 避免使用 JOIN 关联太多的表( 对于关联操作来说,会产生临时表操作,影响查询效率  )

  1. 使用较低的隔离级别 ,因为隔离级别越低,事务请求的锁越少;
  2. 不同的程序访问一组表的时候,应尽量约定一个相同的顺序访问各表,对于一个表而言,尽可能的固定顺序的获取表中的行,这样可以大大的减少死锁的机会;
  3. 尽量控制事务大小,减少锁定资源量和时间长度;
  4. 数据查询的时候不是必要,不要使用加锁。MySQL的MVCC可以实现事务中的查询不用加锁,优化事务性能:MVCC只在committed read(读提交)和 repeatable read (可重复读)两种隔离级别  。

数据库结构优化

  1. 考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。  
  2. 对于经常联合查询的表,可以考虑建立中间表

5、超大分页查询如何优化?

问题:

select * from table where age > 20 limit 1000000,10;  -- age有索引

需要加载一百万条数据,然后基本上全部丢弃,取10条。

说明MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,那当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。

如何解决?

利用延迟关联或者主键阈值法优化超多分页场景。

  1. 延迟关联法
  • 我们先查询出符合要求的主键( 由于查询的字段有索引,该索引的叶子节点就是主键,通过索引覆盖我们可以省去一次回表操作)
    然后再通过主键索引查询数据,这就省去了遍历数据找初始位置数据的过程。
select * from table where id in (select id from table where age > 20)limit 1000000,10;

2. 主键阈值法

  • 如果你的主键是自增的,那么就可以通过条件推算出符合条件的主键最大值&最小值(这里也是通过索引覆盖省去了一次回表操作)
    然后再根据阈值,取数据即可,同样省去了遍历数据找初始位置数据的过程 。
select * from table where id >= (select id from table where age > 20 limit 1000000, 1) limit 10;

总结: 无论是延迟关联法,还是主键阈值法。思想都是一样的,先把符合条件的主键找到,然后通过主键去定位符合条件的数据,这里优化了2个点:

  1. 通过索引覆盖避免了回表;
  2. 通过主键直接定位数据的方法,省去了在数据集中查询初始位置的过程。

当然还有其他的解决方法,比如说我们可以将数据可预测性的提前缓存到Redis中,等到查询时,直接返回即可。

6、为什么select * 会导致查询效率低?

  1. 不需要的列会增加数据传输时间和网络开销:
  • 用SELECT * 数据库需要解析更多的对象、字段、权限、属性等相关内容,在 SQL 语句复杂,硬解析较多的情况下,会对数据库造成沉重的负担。
  • 增大网络开销,* 有时会误带上如log、IconMD5之类的无用且大文本字段,数据传输size会几何增涨。如果DB和应用程序不在同一台机器,这种开销非常明显。即使 MySQL 服务器和客户端是在同一台机器上,使用的协议还是 tcp,通信也是需要额外的时间。
  1. 对于无用的大字段,如 varchar、blob、text,会增加 io 操作:
  • 如果记录中包含超过 728 字节的数据,MySQL 将这些数据存储在一个额外的位置,并在记录中保存一个指向这些数据的指针。这意味着在读取记录时,MySQL 需要执行额外的一次 I/O 操作来获取超过 728 字节的数据。
  1. 失去MySQL优化器“覆盖索引”策略优化的可能性:
  • SELECT * 杜绝了覆盖索引的可能性,而基于MySQL优化器的“覆盖索引”策略又是速度极快,效率极高,业界极为推荐的查询优化方式。
  • 如果用户使用select *,获取了不需要的数据,则首先通过非聚簇索引过滤数据,然后再通过聚集索引获取所有的列,这就多了一次b+树查询,速度必然会慢很多。
  • 由于辅助索引的数据比聚集索引少很多,很多情况下,通过辅助索引进行覆盖索引(通过索引就能获取用户需要的所有列),都不需要读磁盘,直接从内存取,而聚集索引很可能数据在磁盘(外存)中(取决于buffer pool的大小和命中率),这种情况下,一个是内存读,一个是磁盘读,速度差异就很显著了,几乎是数量级的差异。
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
关系型数据库 MySQL AndFix
MySQL 8.0是MySQL
MySQL 8.0是MySQL发展的一个重要里程碑。在这个版本中,MySQL Server层的整体架构得到了质的飞跃,通过持续每三个月的迭代和重构工作,使得MySQL在性能和功能上都有了显著的提升。本文将基于MySQL 8.0.25源码,详细介绍MySQL 8.0的最新架构和一些重要的变化。
93 1
|
存储 关系型数据库 MySQL
|
关系型数据库 MySQL Linux
mysql 如何 才是真正的mysql
mysql 如何 才是真正的mysql
48 0
|
SQL 关系型数据库 MySQL
【必知必会的MySQL知识】②使用MySQL
【必知必会的MySQL知识】②使用MySQL
110 0
【必知必会的MySQL知识】②使用MySQL
|
存储 SQL JSON
mysql8.0 与mysql 5.7 对比
mysql8.0 与mysql 5.7 对比
768 0
|
存储 SQL Oracle
Mysql的前世今生,Hello,Mysql
1.什么是数据库? 数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。 每个数据库都有一个或多个不同的 API 用于创建,访问,管理,搜索和复制所保存的数据。 我们也可以将数据存储在文件中,但是在文件中读写数据速度相对较慢。
118 0
Mysql的前世今生,Hello,Mysql
|
关系型数据库 MySQL
07_mysql中having的使用_having与where的对比
mysql中having的使用 having与where的对比
180 0
07_mysql中having的使用_having与where的对比
|
SQL 关系型数据库 MySQL
MySQL5.7及以上 转 MySQL5.5
MySQL5.7及以上 转 MySQL5.5
162 0
|
存储 关系型数据库 MySQL
【MySQL】MySQL知识总结
【MySQL】MySQL知识总结
1028 0
【MySQL】MySQL知识总结
|
关系型数据库 MySQL
MySQL练习13——where in和not in
MySQL练习13——where in和not in!