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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 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的大小和命中率),这种情况下,一个是内存读,一个是磁盘读,速度差异就很显著了,几乎是数量级的差异。
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
15小时前
|
存储 SQL 关系型数据库
从0开始回顾MySQL---系列八
分库分表 1、为什么要分库分表? 1. 数据库中的数据量不一定是可控的,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地数据操作,例如 增删改查的开销 也会越来越大;另外,若不进行分布式部署,而一台服务器的 资源 (CPU、磁盘、内存、IO 等)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。 2. 所以,从 性能 和 可用性 角度考虑,会进行数据库拆分处理,具体地说,把原本存储于一个库的数据分块存储到多个库上,把原本存储于一个表的数据分块存储到多个表上,即 分库分表。 2、分库分表的具体实施策略 分库分表有 垂直切分 和 水平切分 两种方式,在
|
15小时前
|
存储 关系型数据库 MySQL
从0开始回顾MySQL---系列三
索引 1、没有索引如何查找数据? 在一个页中的查找,分为两种情况: 以主键为搜索条件 可以在 页目录 中使用二分法快速定位到对应的槽,然后再遍历该槽对应 分组中的记录即可快速找到指定的记录。 以其他列作为搜索条件 对非主键列的查找的过程可就不这么幸运了,因为在数据页中并没有对非主键列建立所谓的 页目录 ,所以 我们无法通过二分法快速定位相应的 槽 。这种情况下只能从 最小记录 开始依次遍历单链表中的每条记录, 然后对比每条记录是不是符合搜索条件。很显然,这种查找的效率是非常低的。 在很多页中的查找,可以分为两个步骤: 定位到记录所在的页。 从所在的页内中查找相应的记录。 在没有索引的情
|
15小时前
|
存储 SQL 关系型数据库
从0开始回顾MySQL---系列五
事务 1、什么是数据库事务? 事务(Transaction)是访问和更新数据库的程序执行单元,是逻辑上的一组操作,要么都执行,要么都不执行。如果任意一个操作失败,那么整组操作即为失败,会回到操作前状态或者是上一个节点。 因此,事务是保持 逻辑数据一致性 和 可恢复性 的重要利器。而锁是实现事务的关键,可以保证事务的完整性和并发性。 事务控制语句: ● BEGIN 或 START TRANSACTION 显式地开启一个事务; ● COMMIT 也可以使用 COMMIT WORK,不过二者是等价的。COMMIT 会提交事务,并使已对数据库进行的所有修改成为永久性的; ● ROLLBAC
|
15小时前
|
存储 SQL 关系型数据库
从0开始回顾MySQL---系列四
9、什么是回表(使用索引查询完整数据过程)? 当我们需要查询一条完整的数据的时候: ● 如果是通过聚簇索引来查询数据,例如 select * from user where id=100,那么此时只需要搜索聚簇索引的 B+Tree 就可以找到数据。 ● 如果是通过非聚簇索引来查询数据,例如 select * from user where username=zhangsan',那么此时需要先搜索 username 这一列索引的 B+树,搜索完成后得到主键的值,然后再去搜索聚簇索引的 B+树,就可以获取到一行完整的数据。 对于第二种查询方式而言,一共搜索了两棵 B+树,第一次搜索 B+树 拿到
|
15小时前
|
存储 关系型数据库 MySQL
从0开始回顾MySQL---系列一
基础 1、数据库的三范式是什么? 数据库范式是设计数据库时,需要遵循的一些规范。各种范式是条件递增的联系,越高的范式数据库冗余越小。常用的数据库三大范式为: 1. 第一范式(1NF):每个列都不可以再拆分,强调的是列的原子性,即数据库表的每一列都是不可分割的原 子数据项。 2. 第二范式(2NF):在满足第一范式的基础上,非主属性完全依赖于主码(主关键字、主键),消除非主属性对主码的部分函数依赖。 3. 第三范式(3NF):在满足第二范式的基础上,表中的任何属性不依赖于其它非主属性,消除传递依赖。简而言之,非主键都直接依赖于主键,而不是通过其它的键来间接依赖于主键。 2、MySQL 支持哪
|
15小时前
|
存储 关系型数据库 MySQL
从0开始回顾MySQL---系列六
11、什么是MVCC? MVCC 全称 Multi-Version Concurrency Control,即多版本并发控制,用来解决读写冲突的无锁并发控制,可以在发生读写请求冲突时不用加锁解决,这个读是指的快照读(也叫一致性读或一致性无锁读),而不是当前读: ● 快照读:实现基于 MVCC,因为是多版本并发,所以快照读读到的数据不一定是当前最新的数据,有可能是历史版本的数据; ● 当前读:读取数据库记录是当前最新的版本(产生幻读、不可重复读),可以对读取的数据进行加锁,防止其他事务修改数据,是悲观锁的一种操作,读写操作加共享锁或者排他锁和串行化事务的隔离级别都是当前读。 -- 简单的sel
|
15小时前
|
存储 关系型数据库 MySQL
从0开始回顾MySQL---系列七
锁 1、为什么要加锁? 1. 当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况,若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。 2. 因此加锁是为了在多用户环境下保证数据库完整性和一致性。 2、MySQL都有哪些锁呢? 锁的分类: ● 按操作分类: ○ 共享锁:也叫读锁。对同一份数据,多个事务读操作可以同时加锁而不互相影响 ,但不能修改数据 ○ 排他锁:也叫写锁。当前的操作没有完成前,会阻断其他操作的读取和写入 ● 按粒度分类: ○ 表级锁:会锁定整个表,开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并
|
15小时前
|
存储 缓存 关系型数据库
从0开始回顾MySQL---系列二
InnoDB记录结构 1、InnoDB行格式 ? ● 我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为 行格式 或者 记录格式 。 ● 设计InnoDB 存储引擎的作者到现在为止设计了4种不同类型的 行格式 ,分别是 Compact 、Redundant 、Dynamic 和 Compressed 行格式。 2、COMPACT行格式 ? 一条完整的记录其实可以被分为 记录的额外信息 和 记录的真实数据 两大部分。 记录的额外信息 这部分信息是服务器为了描述这条记录而不得不额外添加的一些信息,这些额外信息分为3类,分别是 变长字段长度列表 、 NULL值列表 和
|
9月前
|
存储 SQL JSON
MySQL学习---17、MySQL8其它新特性
MySQL学习---17、MySQL8其它新特性
|
SQL 存储 安全
MySQL --- SQL基础知识
MySQL --- SQL基础知识
MySQL --- SQL基础知识