高性能 MySQL - 第六章 查询性能优化

news2025/1/12 5:54:01

最近阅读MySQL高性能,略有收获,好记忆不如烂笔头,记录一下。本期笔记主要是围绕高性能MySQL第六章查询性能优化。

整体结构

在这里插入图片描述

重点、亮点内容摘抄

第六章 查询性能优化

查询优化、索引优化、库表结构优化需要齐头并进,一个不落。在获得编写MySQL查询经验的同时,也将学习到何为高效的查询设计表和索引,也可以学习到优化库表结构时会影响到那些类型的查询。
本章从查询设计的一些基本原则开始,介绍一些查询优化的技巧以及MySQL优化器内部的机制,展示MySQL是如何执行查询的,如何改变一个查询的执行计划。

1. 查询执行的过程

在这里插入图片描述
执行路径:

  1. 客户端发送查询请求
  2. 服务器检查是否有缓存,未命中缓存则进入下一阶段,命中则直接返回
  3. 服务器端解析 SQL ,预处理,优化器生成对应的执行计划
    a. 解析器进行语法解析
    b. 预处理:判断解析树是否合法,验证权限
    c. 优化器生成执行计划:优化器基于成本模型做出认为的最优选择
    1. MySQL 认为的最优跟你想的最优可能不一样,并不一定是时间最短的查询
    2. 静态优化&动态优化 -> “编译时”优化&“运行时”优化
    3. 优化器优化类型:
      1. 重新定义关联表的顺序(驱动表)
      2. 外连接转为内连接
      3. 条件的等价转换
      4. 优化 count()
      5. 预估并转为常数表达式(关联查询时,根据第一层查询的结果预估第二层查询的类型,转为常数表达式类型)
      6. 覆盖索引扫描
      7. 子查询优化
      8. 提前终止查询(limit)
      9. 等值传播(连表健做条件时,条件可传播到两个表)
      10. in 查询 VS or 查询(MySQL 认为不等价,in 查询会先对列表做排序,再二分,Ologn 复杂度)
  4. MySQL 根据优化器生成的执行计划,调用存储引擎 API 执行查询
  5. 返回结果

2. 慢查询基础:优化数据访问

数据优化访问

  • Select * 取回全部列
    • select * 可以被允许,但永远不要忘记这样做的代价是什么。(在某些场景下 select * 能够简化代码,提高某些代码片段的复用性,但 select * 可能会带来额外的 IO、CPU、内存消耗)
  • 需要扫描大量行却只返回少量行的情况
    1. 使用覆盖索引,避免回表
    2. 改变库表结构,比如使用单独的汇总结果表
    3. 重写 SQL
  • 多表关联时返回了全部列
  • 确认MySQL服务器层是否在分析大量超过需要的数据行。
    • 响应时间:服务时间(执行的时间)+排队时间(IO等待、锁等待)
    • 扫描的行数
    • 返回的行数

用Explain中type确定索引类型

  • 索引效率:const > eq_ref > ref > range > index > all
    • const : 命中主键索引
    • eq_ref : 命中唯一索引扫描
    • ref : 非唯一索引扫描
    • range: 只检索给定范围的行,返回匹配指定区间的所有行,一般就是你的where子句中出现了如 between and , in , <,>等 的这种查询.
    • index :Full index Scan ,与all 不同的是,index 为index类型只遍历索引数,这通常比all快,因为索引文件通常比数据文件小. 也就是说虽然all和index都是读全表,但是index是从索引中读取的,而all是从磁盘读取的
    • all : 全表扫描,将遍历全表以找到匹配的行

3. 查询优化器的局限

MySQL 查询优化器并不是银弹,在某些场景下查询优化器也具有局限性

  1. 关联子查询:where 条件中包含 in() 的子查询
  • 建议:改写成内连查询
  • 举例:select * from film where film_id IN (select film_id from film_actor where actor_id =1)
  • 建议写法:select film.* from film INNER JOIN film_actor USING(film_id) where actor_id =1.
  1. UNION 的限制:有时候 MySQL 无法将查询条件从外层下推到内层, 这样导致原本能通过limit来限制部门返回结果的条件无法应用到内层查询的优化上。
  • 举例:( select columnA, clolumnB from tableA order by create_time desc) union all ( select columnA,columnB from tableB order by create_time desc) limit 100;
  • 建议写法:( select columnA,clolumnB from tableA order by create_time desc limit 100) union all ( select columnA,columnB from tableB order by create_time desc limit 100) limit 100;
  1. 等值传播:等值传递在某些场景下会带来较大的意想不到的性能损耗
    • 等值传播:
      在这里插入图片描述在这里插入图片描述
  • 举例:在连接查询中,查询条件中 in() 列表很大,如果优化器发现这个字段在 where、on、using 字句中可以等值传递,那么优化器会将该条件等值传递到关联的各个表中,导致每个表都需要做一次 in() 大列表的查询,带来额外的性能损耗
  • 建议写法:改写 SQL,即使是单表查询,也不推荐一次 in() 的个数过多,因为那样会导致索引失效。
  1. 并行查询:MySQL 不支持并行查询。
  2. hash 关联:MySQL 不支持 hash 关联
  3. 松散索引扫描:MySQL 目前不支持松散索引扫描
    • MySQL 无法按照不连续的方式扫描一个索引,只支持按顺序扫描,以联合索引 (a,b) 为例,最左匹配原则,如果查询条件仅有字段 b,那字段 b 的查询无法使用到索引,只能全表扫描。
      在这里插入图片描述
    • 如果 MySQL 能支持跳跃查找(松散索引的查找方式,类似 oracle 的跳跃索引扫描),那它的额查询方式应该是类似下图
      在这里插入图片描述
      使那些在where条件中没有对目标索引的前导列指定查询条件但同时又对该 索引的非前导列指定了查询条件的目标SQL依然可以用上该索引,这就像是在扫描该索引时跳过了它的前导列,直接从该索引的非前导列开始扫描一样。

4. 查询优化方式

优化通常不只是从技术手段上进行优化,也包括从产品形态、系统交互等层面综合考虑,权衡后得出最优解。

  • 重构查询(主要是分治的思想)

    • 一个复杂查询可以拆分成多个简单查询
    • 切分查询:使用索引字段分段查询
    • 分解关联查询:拆分 join(有排序分页的 SQL 不适用)
  • 优化特定类型的查询

    1. 优化count() 查询
    • count(column) 统计的是该列值不为 NULL 的数量,count(*) 统计行数
    • 某些情况下,“快速、精确和实现简单”三者只能满足其二(任何情况下都是在做权衡)
      • 某些分页列表查询接口,需要展示总记录数,在总数量较大的情况下,不展示精确数量。如飞书审批在任务量超过99时展示 99+
      • 在这里插入图片描述
    1. 优化关联查询
    • 确保连表键有索引
    • 确保 group by 和 order by 中只涉及到一个表中的列,这样 MySQL 才有可能使用索引来优化查询过程
    1. 优化子查询
    • 建议尽可能使用关联查询代替子查询
    1. 优化 group by 和 distinct
    • 建议使用索引进行优化
    • 如果 group by 字段没有索引,MySQL 会用临时表或者文件排序来进行分组
    1. 优化 limit 分页
    • 深分页问题:偏移量很大的情况下(如 select * from table limit 100000,10),mysql 需要查出100010条记录后只返回10条,偏移量越大,代价越高。
    • 解法:
      • 场景1:迁移数据场景,需要分页遍历某个大表所有数据,可对索引字段排序并做条件,可解( select * from table where columnA < ${lastMaxColumnAValue} order by columnA desc limit 10)
      • 场景2:用户列表页,分支查询大量数据。可限制不允许随机翻页,仅支持顺序翻页,加上游标查询,可解。
    1. 优化 union 查询
    • 写 SQL 时可以手动下推一些外层条件到子语句中(不一定普适,需要结合场景判断)
    • 注意 union 和 union all 的区别,如果不是强要求去重,建议一定使用 union all,否则 MySQL 会对临时表做一次全表的 distinct。

阅读思考

  1. 日常工作中遇到的慢查询,大都可以根据慢查询的原理来映射到对应的场景上面(访问了不需要的数据、查询扫描行数过多、查询返回行数过多等),除此之外,因为 MySQL 回表访问数据的时候是按照行读取的,如果遇到表的字段比较多,导致一行数据分布在多个磁盘数据块(数据行存储分裂,访问时需要额外一次磁盘寻址IO),也会导致查询性能下降,这个也是我们在设计 Schema 时拒绝宽表的原因。
  2. 除了上述场景,5.4之后的 MySQL 中 BLOB 、TEXT 字段使用的是指针链式存储(访问时需要额外一次磁盘寻址IO),在有 BLOB 、TEXT 字段的表中查询数据,如果不是明确对 BLOB 、TEXT 字段有访问需求,需要特别注意不要查询 BLOB 、TEXT 字段。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/19706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nodejs express 的基本使用

测试需要快速过一遍express的基本使用方法 直接安装express使用 express和koa的区别](https://zhuanlan.zhihu.com/p/372128788)egg.js企业级开发框架 npm install exress --save可以使用express-generator生成项目框架 $ npx express-generatorwarning: the default view …

call()、apply()、bind() 区别、使用场景、实现方式

目录 1. call()、apply()、bind() 三者区别 1.1 作用 1.2 参数 1.3 执行时机 2. call()、apply() 使用场景 2.1 使用 Array.prototype.push.apply(arr1, arr2) 合并两个数组 2.1.1 原理&#xff08;看了手写方法&#xff0c;或许会更有助于理解&#xff09; 2.1.2 如何…

微电网两阶段鲁棒优化(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

LeetCode刷题复盘笔记—一文搞懂62. 不同路径 63. 不同路径 II(动态规划系列第三篇)

今日主要总结一下动态规划的两道题目&#xff0c;62. 不同路径 && 63. 不同路径 II 题目一&#xff1a;62. 不同路径 题目描述&#xff1a; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或…

HTML CSS 网页设计作业「体育小站」(梅西足球 6页 )

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 校园篮球网页设计 | 足球体育运动 | 体育游泳运动 | 兵乓球 | 网球 | 等网站的设计与制作| HTML期末大学生网页设计作业&#xff0c;Web大学生网页 HT…

JavaScript之PC端网页特效(55th)

在前面学习了JS基础、DOM 和 BOM 的基本操作后&#xff0c;这部分主要学习这些知识的拓展应用 1、元素偏移量 offset 系列 1、offset 概述 offset 翻译过来就是偏移量&#xff0c;我们使用 offset 系列相关属性可以动态的得到该元素的位置&#xff08;偏移&#xff09;、大小…

SpringBoot SpringBoot 开发实用篇 4 数据层解决方案 4.7 SpringBoot 操作 Redis 客户端实现技术切换【jedis】

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 开发实用篇 文章目录SpringBootSpringBoot 开发实用篇4 数据层解决方案4.7 SpringBoot 操作 Redis 客户端实现技术切换【je…

数据结构实验教程-第二套

5.一棵左子树为空的二叉树在先序线索化后&#xff0c;其中空的链域的个数是 a&#xff0e;不确定 b.0 c.1 d.2在先序线索化之后&#xff0c;相当于只有开始节点没有前驱&#xff0c;最后的节点没有后继&#xff0c;因此空链域只有2个&#xff0c;分别是开始节点的左孩子和最后节…

【笔试题】【day23】

文章目录第一题&#xff08;二叉树度结点的计算&#xff09;第二题&#xff08;平衡查找二叉树&#xff09;第三题&#xff08;堆的插入&#xff09;第四题&#xff08;哈希表的查找&#xff09;第五题&#xff08;大数排序&#xff09;第一题&#xff08;二叉树度结点的计算&a…

功能测试

功能测试 按照是否覆盖源代码 黑盒测试&#xff08;输入和输出&#xff09; 白盒测试&#xff08;代码内部实现逻辑&#xff09; 灰盒测试&#xff08;输入输出和代码逻辑&#xff09; 介于白盒测试和黑盒测试之间的测试&#xff0c;多用于集成阶段&#xff0c;不仅关注输入输…

智能制造与数字化工厂

智能制造是基于新一代信息技术&#xff0c;贯穿设计、生产、管理、服务等制造活动各个环节&#xff0c;具有信息深度自感知、智慧优化自决策、精准控制自执行等功能的先进制造过程、系统与模式的总称。具有以智能工厂为载体&#xff0c;以关键制造环节智能化为核心&#xff0c;…

通信用多模光纤主要有哪些类型?OM1~OM5有什么区别

1 前言 根据光纤内光信号传输模式的不同&#xff0c;光纤可分为单模光纤和多模光纤&#xff0c;见《常用通信光纤是如何分类的》一文。 在传送网和有线接入网中&#xff0c;我们接触到的光纤类型主要有&#xff1a;G.652、G.654和G.657&#xff0c;这些都是单模光纤。多模光纤…

Linux 系统启动过程

linux启动时我们会看到许多启动信息。 Linux系统的启动过程并不是大家想象中的那么复杂&#xff0c;其过程可以分为5个阶段&#xff1a; 内核的引导。运行 init。系统初始化。建立终端 。用户登录系统。init程序的类型&#xff1a; SysV: init, CentOS 5之前, 配置文件&#…

通关算法题之 ⌈二叉树⌋ 上

二叉树深度 104、求二叉树最大深度 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数&#xff0c;叶子节点是指没有子节点的节点。 示例&#xff1a; 给定二叉树[3,9,20,null,null,15,7]&#xff0c; 3/ \9 20/ \15 7返回它的最大深度 3。 解法一&#xff1a;递…

Linux进阶-Shell编程

目录 定义变量&#xff1a; 使用变量&#xff1a; 将命令的结果赋值给变量&#xff1a; 删除变量&#xff1a;unset 退出当前进程&#xff1a;exit 读取从键盘输入的数据 &#xff1a;read 对整数进行数字运算&#xff1a;(()) 逻辑与或&#xff1a; 检测某个条件是否成…

Qt QSqlQueryModel详解

1.功能概述 QSqlQueryModel是QSqlTableModel的父类。QSqlQueryModel封装了执行SELECT语句从数据库查询数据的功能&#xff0c;但是QSqlQueryModel只能作为只读数据源使用&#xff0c;不可以编辑数据。 2.常用API void clear() //清除数据模型&#xff0c;释放所有获得的数据…

投资有风险,入市需谨慎

投资有风险&#xff0c;入市需谨慎投资有风险&#xff0c;入市需谨慎股票的分类股票的分时图股票K线图股票交易规则股票趋势股票买卖机制投资有风险&#xff0c;入市需谨慎 感谢平台和大家支持&#xff0c;今天不聊技术&#xff0c;了解了解其他方面&#xff0c;比如股市&…

编程思维是一种什么思维?

hello wordl&#xff01;    keep coding&#xff01;&#x1f3c3; 学编程不是将来要当程序猿&#xff0c;而是在学习编程思维。比尔盖茨、扎克伯格、乔布斯用经验告诉我们&#xff0c;拥有编程思维的人&#xff0c;就相当于成功了一半——不但逻辑清晰心思缜密&#xff0c;…

vue + el-checkbox 单选功能

需求: 用 el-checkboc 实现单选功能并且当选中某一项时则回填到input框里,当点击 enter 键或者是 按下搜索图标按键,来实现页面搜索内容的同步展示;如图: <el-checkbox-group placeholder"请选择"size"small"v-model"checkedCols"clearablefi…

Android BLE HIDS Data ,从问询DB 到写入Android 节点的flow之二

问题点4&#xff1a;Android BLE具体连接flow 并问询DB的API flow 之第一阶段问询&#xff1b; 当前确认原生BT当作为GATT Client 连接上GATT Server时&#xff0c;在连接上后会有自动启动问询的动作(以下Tracing 基于Android 9(P), 测试 8.1的代码和Android 8.0有差异&#x…