读高性能MySQL(第4版)笔记10_查询性能优化(上)

2023-09-19 06:30:00

1. 三管齐下

1.1. 不做、少做、快速地做

1.2. 如果查询太大,服务端会拒绝接收更多的数据并抛出相应错误

1.3. 如果查询写得很糟糕,即使库表结构再合理、索引再合适,也无法实现高性能

1.4. 查询优化、索引优化、库表结构优化需要齐头并进,一个不落

1.5. Percona Toolkit中的pt-archiver工具

2. 响应时间

2.1. 如果把查询看作一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间

2.2. 如果要优化查询,实际上要优化其子任务,要么消除其中一些子任务,要么减少子任务的执行次数,要么让子任务运行得更快

2.3. 优化查询的目的就是减少和消除这些操作所花费的时间

2.4. 查询需要在不同的地方花费时间

2.4.1. 网络、CPU计算、生成统计信息和执行计划、锁等待(互斥等待)等操作

2.4.2. 尤其是向底层存储引擎检索数据的调用操作,这些调用需要在内存操作、CPU操作和内存不足时导致的I/O操作上消耗时间

2.5. 两部分之和:服务时间和排队时间

2.5.1. 服务时间是指数据库处理这个查询真正花了多长时间

2.5.2. 排队时间是指服务器因为等待某些资源而没有真正执行查询的时间——可能是等I/O操作完成,也可能是等待行锁

2.6. 响应时间既可能是一个问题的结果也可能是一个问题的原因,不同案例情况不同

2.7. 实际上可以使用“快速上限估计”法来估算查询的响应时间

2.7.1. 了解这个查询需要哪些索引以及它的执行计划是什么

2.7.2. 计算大概需要多少个顺序和随机I/O

2.7.3. 用其乘以在具体硬件条件下一次I/O的消耗时间

2.7.4. 把这些消耗都加起来

2.7.5. 获得一个大概参考值来判断当前响应时间是不是一个合理的值

3. 查询的生命周期

3.1. 从客户端到服务器,然后在服务器上进行语法解析,生成执行计划,执行,并给客户端返回结果

3.2. “执行”可以被认为是整个生命周期中最重要的阶段

4. 优化数据访问

4.1. 如果性能很差,最常见的原因是访问的数据太多

4.2. 是否在检索大量且不必要的数据

4.2.1. 访问了太多的行

4.2.2. 访问了太多的列

4.3. 确认MySQL服务器层是否在分析大量不需要的数据行

4.3.1. 会请求超过实际需要的数据,然后这些多余的数据会被应用程序丢弃

4.3.2. 消耗应用服务器的CPU和内存资源

4.4. 一个常见的错误是,常常会误以为MySQL只会返回需要的数据,实际上MySQL却是先返回全部结果集再进行计算

4.4.1. 最简单有效的解决方法就是在这样的查询后面加上LIMIT子句

4.5. 每次看到SELECT*的时候都需要用怀疑的眼光审视,是不是真的需要返回全部的列,很可能不是必需的

4.5.1. 取出全部列,会让优化器无法完成索引覆盖扫描这类优化

4.5.2. 严格禁止SELECT*的写法,这样做有时候还能避免某些列被修改而带来的问题

4.6. 查询返回超过需要的数据也不总是坏事

4.7. 重复查询相同的数据

4.7.1. 当初次查询的时候将这个数据缓存起来,需要的时候从缓存中取出,这样性能显然会更好

4.8. 检查慢日志记录是找出扫描行数过多的查询的好办法

4.9. 扫描的行数和返回的行数

4.9.1. 查看该查询扫描的行数能够说明该查询找到需要的数据的效率高不高

4.9.2. 理想情况下扫描的行数和返回的行数应该是相同的,但实际中这种“美事”并不多

4.9.3. 扫描的行数与返回的行数的比率通常很低,一般在1:1到10:1之间,不过有时候这个值也可能非常非常大

4.10. 访问类型有很多种,从全表扫描到索引扫描、范围扫描、唯一索引查询、常数引用等

4.10.1. 访问方式可能无须扫描就能返回结果

4.10.2. 访问方式可能需要扫描很多行才能返回一行结果

4.10.3. 没办法找到合适的访问类型,那么最好的解决办法通常就是增加一个合适的索引

4.11. 应用WHERE条件

4.11.1. 在索引中使用WHERE条件来过滤不匹配的记录

4.11.1.1. 在存储引擎层完成的

4.11.2. 使用索引覆盖扫描(在Extra列中出现了Using index)来返回记录

4.11.2.1. 直接从索引中过滤不需要的记录并返回命中的结
4.11.2.2. 在MySQL服务器层完成的,但无须再回表查询记录

4.11.3. 从数据表中返回数据,然后过滤不满足条件的记录(在Extra列中出现Using where)

4.11.3.1. 在MySQL服务器层完成
4.11.3.2. 需要先从数据表中读出记录然后过滤

4.12. 不是说增加索引就能让扫描的行数等于返回的行数

4.13. 优化

4.13.1. 使用索引覆盖扫描,把所有需要用的列都放到索引中,这样存储引擎无须回表获取对应行就可以返回结果了

4.13.2. 改变库表结构

4.13.2.1. 使用单独的汇总表

4.13.3. 重写这个复杂的查询,让MySQL优化器能够以更优化的方式执行

5. 重构查询的方式

5.1. 在优化有问题的查询时,目标应该是找到获得实际需要的结果的替代方法

5.1.1. 但这并不一定意味着从MySQL返回完全相同的结果集

5.1.2. 可以将查询转换为返回相同结果的等价形式,以获得更好的性能

5.2. 以前人们总是认为网络通信、查询解析和优化是一件代价很高的事情

5.2.1. 对于MySQL并不适用

5.2.2. MySQL从设计上让连接和断开连接都很轻量,在返回一个小的查询结果方面很高效

5.2.3. 现代的网络速度比以前要快很多,能在很大程度上降低延迟

5.3. 在MySQL内部,每秒能够扫描内存中上百万行的数据

5.3.1. MySQL响应数据给客户端就慢得多了

5.4. 在其他条件都相同的时候,使用尽可能少的查询当然是更好的

5.4.1. 将一个大查询分解为多个小查询是很有必要的

5.4.2. 如果在一个查询能够胜任时还将其写成多个独立的查询是不明智的

5.5. 切分查询

5.5.1. 删除旧的数据就是一个很好的例子

5.5.1.1. 定期清除大量数据时,如果用一个大的语句一次性完成的话,则可能需要一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询
5.5.1.2. 将一个大的DELETE语句切分成多个较小的查询可以尽可能小地影响MySQL的性能,同时还可以降低MySQL复制的延迟

5.5.2. 一次删除一万行数据一般来说是一个比较高效而且对服务器影响最小的做法(如果是事务型引擎,很多时候小事务能够更高效)

5.5.3. 如果每次删除数据后,都暂停一会儿再做下一次删除,也可以将服务器上原本一次性的压力分散到一个很长的时间段中,可以大大降低对服务器的影响,还可以大大减少删除时锁的持有时间

5.6. 分解联接查询

5.6.1. 很多高性能的应用都会对联接查询进行分解

5.6.2. 可以对每一个表进行一次单表查询,然后将结果在应用程序中进行联接

5.6.3. 让缓存的效率更高

5.6.4. 将查询分解后,执行单个查询可以减少锁的竞争

5.6.5. 在应用层做联接,可以更容易对数据库进行拆分,更容易做到高性能和可扩展

5.6.6. 查询本身的效率也可能会有所提升

5.6.6.1. 使用IN()代替联接查询,可以让MySQL按照ID顺序进行查询,这可能比随机的联接要更高效

5.6.7. 可以减少对冗余记录的访问

5.6.7.1. 在应用层做联接查询,意味着对于某条记录应用只需要查询一次,而在数据库中做联接查询,则可能需要重复地访问一部分数据
更多推荐

ESP32-IDF使用I2S驱动MAX98375--解析WAV文件

一.简介本篇文章将介绍如何使用ESP32S3通过I2S发送WAV音频数据,驱动MAX98375A进行音频的播放。是EVE_V2项目开发的一部分工作。二.MAX98375A介绍芯片特性如下,可以在芯片手册上找到。单电源工作(2.5V至5.5V)3.2W输出功率:4Ω,5V2.4mA静态电流92%效率(RL=8Ω,POUT

商家收款一万手续费多少

目前微信和支付宝作为主流的支付平台,为商家提供了安全、便捷的支付解决方案。但是在正常情况下,商家需要向平台支付交易额0.6%至1%不等的手续费,这个费率看似很少,但长期积累下来的手续费支出也是一笔不小的开支。什么是收款手续费率?收款手续费率是指的是我们商家在用收款码收款的时候,每次收款都会被微信或者支付宝扣一笔费用,这

Linux日志管理-logrotate(crontab定时任务、Ceph日志转储)

文章目录一、logrotate概述二、logrotate基本用法三、logrotate运行机制logrotate参数四、logrotate是怎么做到滚动日志时不影响程序正常的日志输出呢?Linux文件操作机制方案一方案二五、logrotate实战--Ceph日志转储参考一、logrotate概述logrotate是一个

盛元广通农业种子检测实验室信息化管理系统LIMS

农业问题以及粮食安全关系着我们的基本民生,尤其是随着农业科技的发展,借助现代化实验室管理系统,在种子质量检验中能让实验室检验实现自动化运行,实现无纸化和信息化办公,让数据分析得到科学完整的管理,减少运行成本。盛元广通农业种子检测实验室信息化管理系统LIMS结合工作实际流程制作,从种子采购、种子入库、种子库存、更新提醒、

智云谷再获AR HUD新项目定点,打开HUD出口海外新通道

深圳前海智云谷科技有限公司(以下简称“智云谷”)于近日收到国内某新能源车企的《定点通知书》,选择智云谷作为其新车型ARHUD开发与量产供应商。智云谷获得定点的车型为海外出口车型,该车型预计在2024年下半年量产。中国汽车全产业链出海“圈粉”随着中国新能源车的强势崛起,中国车企纷纷开始拓展海外市场。海关总署数据显示,今年

单点登录原理及JWT实现

单点登录原理及JWT实现一、单点登录效果首先我们看通过一个具体的案例来加深对单点登录的理解。案例地址:https://gitee.com/xuxueli0323/xxl-sso?_from=gitee_search把案例代码直接导入到IDEA中然后分别修改下server和samples中的配置信息在host文件中配置1

【C语言】结构体内存对齐机制详解

目录一、前言二、结构体内存对齐规则三、实例解析一、前言在讲解结构体内存对齐机制之前,我们先来看1个例子:typedefstruct{charsex;//性别intid;//学号charname[20];//姓名floatscore;//成绩charaddr[30];//地址}STU;intmain(){STUstude

LeetCode 27. 移除元素(JavaScript 简单)

1.题目给你一个数组nums和一个值val,你需要原地移除所有数值等于val的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用O(1)额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。说明:为什么返回数值是整数,但输出的答案是数组呢?请注意,输入数组是以「引用」

使用延迟队列解决分布式事务问题——以订单未支付过期,解锁库存为例

目录一、前言二、库存三、订单一、前言上一篇使用springcloud-seata解决分布式事务问题-2PC模式我们说到了使用springcloud-seata解决分布式的缺点——不适用于高并发场景因此我们使用延迟队列来解决分布式事务问题,即使用柔性事务-可靠消息-最终一致性方案(异步确保型)以下是下订单的代码//@Gl

ctfshow web入门(1)

web1查看页面源代码web2ctr+uweb3因为查看源码没有东西,网络查看下数据包,找到flagweb4robots协议其他都没啥信息,就看下robots.txt,这个文件可能会泄露部分网站目录访问下,看到了web5phps泄露也没啥信息,在响应头里面看到了X-Powered-By:PHP/7.3.11得知-网站是

Grom 如何解决 SQL 注入问题

什么是SQL注入SQL注入是一种常见的数据库攻击手段,SQL注入漏洞也是网络世界中最普遍的漏洞之一。SQL注入就是恶意用户通过在表单中填写包含SQL关键字的数据来使数据库执行非常规代码的过程。这个问题的来源就是,SQL数据库的操作是通过SQL命令执行的,无论是执行代码还是数据项都必须卸载SQL语句中,这就导致如果我们在

热文推荐