当前位置: 首页 > news >正文

MySQL之查询性能优化(四)

查询性能优化

MySQL客户端/服务器通信协议

一般来说,不需要去理解MySQL通信协议的内部实现细节,只需要大致理解通信协议是如何工作的。MySQL客户端和服务器之间的通信协议是"半双工"的,这意味着,在任何一个时刻,要么是由服务器向客户端发送数据,要么是由客户端向服务器发送数据,这两个动作不能同时发生。所以,我们也无法也无须将一个消息切成小块独立来发送。这种协议让MySQL通信简单快速,但是也从很多地方限制了MySQL.一个明显的限制是,这意味着没法进行流量控制。一旦一端开始发送消息,另一端要接收完整个消息才能响应它。这就像来回抛球的游戏:在任何时刻,只有一个人能控制球,而且只有控制球的人才能将球抛回去(发送消息)。一旦客户端发送了请求,它能做的事情就只是等待结果了。相反的,一般服务器响应给用户的数据通常很多,由多个数据包组成。当服务器开始响应客户端请求时,客户端必须完整接收整个返回结果,而不能简单地只取前面几条结果,然后让服务器停止发送数据。这种情况下,客户端若接收完整的结果,然后取前面几条需要的结果,或者接收完几条结果后就"粗暴"地断开连接,都不是好注意。这也是在必要的时候一定要在查询中加上LIMIT限制的原因。换一种方式解释这种行为:当客户端从服务器取数据时,看起来是一个拉数据的过程,但实际上是MySQL在向客户端推送数据的过程。客户端不断地接收从服务器推送的数据,客户端也没法让服务器停下来。客户端像是"从消防管喝水"(这是一个术语)。多数连接MySQL的库函数都可以获得全部结果集并缓存到内存力,还可以逐行获取需要的数据。默认一般是获得全部结果集并缓存到内存中。MySQL通常需要等所有的数据都已经发生给客户端才能释放这条查询所占用的资源,所以接收全部结果并缓存通常可以减少服务器的压力,让查询能够早点结束、早点释放相应的资源。
当使用多数连接MySQL的库函数从MySQL获取数据时,其结果看起来都像时从MySQL服务器获取数据,而实际上都是从这个库函数的缓存获取数据。多数情况下这没什么问题,但是如果需要返回一个很大的结果集的时候,这样做并不好,因为库函数会花很多时间和内存来存储所有的结果集。如果能够尽早开始处理这些结果集,就能大大减少内存的消耗,这种情况下可以不适用缓存来记录结果而是直接处理。这样做的缺点是,对于服务器来说,需要查询完成后才能释放资源,所以在和客户端交互的整个过程中,服务器的资源都是被这个查询搜占用的(你可以使用SQL_BUFFER_RESULT)
我们看啊可能当使用PHP的时候是什么情况。首先,下面是我们连接MySQL的通常写法:

<?php
$link = mysql_connect('localhost','user','p4ssword');
$result = mysql_query('SELECT * FROM HUGE_TABLE', $link);
$while($row = mysql_fetch_array($result)) {
// Do something with result
}
?>

这段代码看起来像是只有当你需要的时候,才通过循环从服务器取出数据。而实际上,在上面的代码中,在调用mysql_query()的时候,PHP就已经将整个结果缓存到内存中。下面的while循环只是从这个缓存中逐行取出数据,相反如果使用下面的查询,用mysql_unbuffered_query()代替mysql_query(),PHP则不会缓存结果:

<?php
$link = mysql_connect('localhost', 'user', 'p4ssword');
$result = mysql_unbuffered_query('SELECT * FROM HUGE_TABLE', $link);
while($row = mysql_fetch_array($result)) {
//Do something with result
}
?>

不同的编程语言处理缓存的方式不同。例如,在Perl的DBD:mysql驱动中需要指定C连接库的mysql_use_result属性(默认是mysql_buffer_result)。下面是一个例子:

#!usr/bin/perl
use DBI;
my $dbh = DBI->connect('DBI:mysql:;host=localhost', 'user', 'p4ssword');
my $sth = $dbh->prepare('SELECT * FROM HUGE_TABLE', {mysql_use_result => 1});
$sth -> execute();
while (my $row = $sth->fetchrow_array()) {
# Do something with result
}

注意到上面的prepare()调用指定了mysql_use_result属性为1,所以应用将直接"使用"返回的结果集而不会将其缓存。也可以在连接MySQL的时候指定这个属性,这会让整个连接都使用不缓存的方式处理结果集:

my $dbh = DBI->connect('DBI:mysql:;mysql_use_result=1', 'user','p4ssword');

查询状态

在这里插入图片描述

对于一个MySQL连接,或者说一个线程,任何时刻都有一个状态,该状态标识了MySQL当前正在做什么。有很多种方式能查看当前的状态,最简单的是使用SHOW FULL PROCESSLIST命令(该命令返回结果中的Command列就表示当前的状态)。在一个查询的生命周期中,状态会变化很多次。MySQL官方手册中对这些状态值的含义有权威的解释,下面将这些状态列出来,并做一个简单的解释.

  • 1.Sleep
    线程正在等待客户端发送新的请求
  • 2.Query
    线程正在执行查询或者正在将结果发送给客户端
  • 3.Locked
    在MySQL服务器层,该线程正在等待表锁。存储引擎级别实现的锁,例如InnoDB的行锁,并不会体现在线程状态中。对于MyISAM来说这是一个比较典型的状态,但在其他没有行锁的一你请中也会经常出现
  • 4.Analyzing and statistics
    线程正在收集存储引擎的统计洗脑洗,并生成查询的执行计划
  • 5.Copying to tmp table [on disk]
    线程正在执行查询,并且将结果集都复制到一个临时表中,这种状态一般要么是在做GROUP BY操作,要么是文件排序操作,或者UNION操作。如果这个状态后面还有"on disk"标记,那表示MySQL正在将一个内存临时表放到磁盘上
  • 6.Sorting result
    线程正在对结果集进行排序
  • 7.Sending data
    这表示多种情况:线程可能在多个状态之间传送数据,或者在生成结果集,或者在向客户端返回数据。

了解这些状态的基本含义非常有用,这可以让我们很快地了解当前"谁正在持球"。在一个繁忙的服务器上,可能会看到大量的不正常的状态。例如statstics正占用大量的时间。这通常表示,某个地方有异常了

查询缓存(这里是指Query Cache)

在解析一个查询语句之前,如果查询缓存是打开的,那么MySQL会优先检查这个查询是否命中查询缓存中的数据。这个检查是通过一个对大小写敏感的哈希查找实现的。查询和缓存中的查询即使只有一个字节不同,那也不会匹配缓存结果(Percona版本的MySQL中提供了一个新的特性,可以在计算查询语句哈希值时,先将注释移除再计算哈希值,这对于不同注释的相同查询可以命中相同的查询缓存结果)。这种情况下查询就会进入下一个阶段的处理。如果当前的查询恰好命中了查询缓存,那么再返回查询结果之前MySQL会检查一次用户权限。这仍然时无须解析查询SQL语句的,因为在查询缓存中已经存放了当前查询需要访问的表信息。如果权限没有问题,MySQL会跳过所有其他阶段,直接从缓存中拿到结果并返回给客户端。这种情况下,查询不会被解析,不用生成执行计划,不会被执行

查询优化处理

查询的生命周期的下一步时将一个SQL转换成一个执行计划,MySQL再依照这个执行计划和存储引擎进行交互。这包括多个子阶段:解析SQL、预处理、优化SQL执行计划。这个过程中任何错误(例如语法错误)都可能终止查询。接下来选择性地介绍其中几个独立的部分,在实际执行中,这几部分可能一起执行也可能单独执行。目的是帮助大家理解MySQL是如何执行查询,以便写出更优秀的查询。

语法解析器和预处理

首先,MySQL通过关键字将SQL语句进行解析,并生成一棵对应的"解析树",MySQL解析器将使用MySQL语法规则验证和解析查询,例如,它将验证是否使用错误的关键字,或者使用关键字的顺序是否正确等,再或者它还会验证引号是否能前后匹配。预处理器则根据一些MySQL规则进一步检查解析树是否合法,例如,这里将检查数据表和数据列是否存在,还会解析名字和别名,看看它们是否有歧义,下一步预处理器会验证权限。这通常很快,除非服务器上有很多的权限配置。

查询优化器

现在语法书被认为是合法的了,并且由优化器将其转化成执行计划。一条查询可以有很多种执行方式,最后都返回相同的结果。优化器的作用就是找到这其中最好的执行计划。MySQL使用基于成本的优化器,它将尝试预测一个查询使用某种执行计划时的成本,并选择其中成本最小的一个。最初,成本的最小单位是随机读取一个4K数据页的成本,后来(成本计算公式)变得更加复杂,并且引入了一些"因子"来估算某些操作的代价,如当执行一次WHERE条件比较的成本.可以通过查询当前会话的Last_query_cost的值来得知MySQL计算的当前查询的成本;

mysql> SELECT SQL_NO_CACHE COUNT(*) FROM film_actor;
+----------+
| COUNT(*) |
+----------+
|     5462 |
+----------+
1 row in set (0.07 sec)
mysql> SHOW STATUS LIKE 'Last_query_cost';
+-----------------+-------------+
| Variable_name   | Value       |
+-----------------+-------------+
| Last_query_cost | 1104.399000 |
+-----------------+-------------+
1 row in set (0.07 sec)

这个结果表示MySQL的优化器认为大概需要做1040个数据页的随机查找才能完成上面的查询。这是根据一系列的统计信息计算得来的:每个表或者索引的页面个数、索引的基数(索引中不同值得数量)、索引和数据行得长度、索引分布情况。优化器再评估成本的时候并不考虑任何层面的缓存,它假设读取任何数据都需要一次磁盘IO.有很多种原因会导致MySQL优化器选择错误的执行计划,如下所示:

  • 1.统计信息不准确。MySQL依赖存储引擎提供的统计信息来评估成本,但是有的存储引擎提供的信息是准确的,有的偏差可能非常大。例如,InnoDB因为其MVCC的架构,并不能维护一个数据表的行数的精确统计信息
  • 2.执行计划种的成本估算不等同于实际执行的成本,所以即使统计信息准确,优化器给出的执行计划也可能不是最优的。例如有时候某个执行计划虽然需要读取更多的页面,但是它的成本却更小。因为如果这些页面都是顺序读或者这些页面已经在内存种的花,那么它的访问成本将很小。MySQL层面并不知道哪些页面在内存中、哪些在磁盘上,所以查询实际执行过程中到底需要多少次物理IO是无法得知的。
  • 3.MySQL的最优可能和你想的最优不一样。你可能希望执行时间尽可能的短,但是MySQL只是基于其成本模型选择最优的执行计划,而有些时候这并不是最快的执行方式。所以,这里我们看到的根据执行成本来选择执行计划并不是完美的模型
  • 4.MySQL从不考虑其他并发执行的查询,这可能会影响到当前查询的速度
  • 5.MySQL也并不是任何时候都是基于成本的优化。有时也会给予一些固定的规则,例如,如果存在全文搜索的MATCH()子句,则在存在全文索引的时候就使用全文索引。即使有时候使用别的索引和WHERE条件可以远比这种方式要快,MySQL也仍然会使用对应的全文索引。
  • 6.MySQL不会考虑不受其控制的操作的成本,例如执行存储过程或者用户自定义函数的成本
  • 7.后面我们还会看到,优化器有时候无法去估算所有可能的执行计划,所以它可能错过实际上最优的执行计划

相关文章:

MySQL之查询性能优化(四)

查询性能优化 MySQL客户端/服务器通信协议 一般来说&#xff0c;不需要去理解MySQL通信协议的内部实现细节&#xff0c;只需要大致理解通信协议是如何工作的。MySQL客户端和服务器之间的通信协议是"半双工"的&#xff0c;这意味着&#xff0c;在任何一个时刻&#…...

定时任务详解

文章目录 定时任务详解JDK自带第三方任务调度框架java有哪些定时任务的框架为什么需要定时任务定时任务扫表的方案有什么缺点Quartzxxl-jobxxl-job详解 elastic-job 定时任务详解 在定时任务中&#xff0c;操作系统或应用程序会利用计时器或定时器来定期检查当前时间是否达到了…...

OnlyOffice DocumentServer 8.0.1编译破解版本(¥100)

OnlyOffice DocumentServer 8.0.1编译破解版本&#xff08;&#xffe5;100&#xff09; 破解20人数限制 更换中文字体 修改源码&#xff0c;根据业务自定义服务 根据源码在本机启动项目&#xff0c;便于开发 将编译好的服务打包docker镜像运行 提供各种docker镜像包&…...

Android 应用权限

文章目录 权限声明uses-permissionpermissionpermission-grouppermission-tree其他uses-feature 权限配置 权限声明 Android权限在AndroidManifest.xml中声明&#xff0c;<permission>、 <permission-group> 、<permission-tree> 和<uses-permission>…...

MATLAB 匿名函数

定义匿名函数定义匿名函数的基本语法如下&#xff1a;示例示例 1&#xff1a;简单数学运算示例 2&#xff1a;字符串操作示例 3&#xff1a;作为参数传递 匿名函数的高级用法使用函数句柄定义多输出函数使用局部变量使用嵌套匿名函数 注意事项 匿名函数&#xff08; Anonymous…...

Java 新手入门:基础知识点一览

Java 新手入门&#xff1a;基础知识点一览 想要踏入 Java 的编程世界&#xff1f;别担心&#xff0c;这篇文章将用简单易懂的表格形式&#xff0c;带你快速了解 Java 的基础知识点。 一、Java 是什么&#xff1f; 概念解释Java一种面向对象的编程语言&#xff0c;拥有跨平台、…...

三维模型轻量化工具:手工模型、BIM、倾斜摄影等皆可用!

老子云是全球领先的数字孪生引擎技术及服务提供商&#xff0c;它专注于让一切3D模型在全网多端轻量化处理与展示&#xff0c;为行业数字化转型升级与数字孪生应用提供成套的3D可视化技术、产品与服务。 老子云是全球领先的数字孪生引擎技术及服务提供商&#xff0c;它专注于让…...

小程序CI/CD之自动化打包预览并钉钉通知发布进程

小程序打包方式分为两种&#xff1a;手动打包、自动打包 那如何实现 自动打包 呐&#xff1f;我们今天就来聊一聊&#xff01; 首先&#xff0c;很重要&#xff0c;看 官方文档 这里提到今天我们要聊的“主角” miniprogram-ci miniprogram-ci 是从微信开发者工具中抽离的关于…...

C++使用QtHttpServer开发服务端Server的Http POST接口和客户端Client示例

Client HTTP POST 假设http://127.0.0.1:8888/post/是一个能够接受POST请求的路径&#xff0c;我们想要向它提交一段json数据&#xff0c;用Qt可以这样实现&#xff1a; Suppose we want to make an HTTP POST with json body to http://127.0.0.1:8888/post/. QCoreApplica…...

计算机基础(8)——音频数字化(模电与数电)

&#x1f497;计算机基础系列文章&#x1f497; &#x1f449;&#x1f340;计算机基础&#xff08;1&#xff09;——计算机的发展史&#x1f340;&#x1f449;&#x1f340;计算机基础&#xff08;2&#xff09;——冯诺依曼体系结构&#x1f340;&#x1f449;&#x1f34…...

手搓单链表(无哨兵位)(C语言)

目录 SLT.h SLT.c SLTtest.c 测试示例 单链表优劣分析 SLT.h #pragma once#include <stdio.h> #include <assert.h> #include <stdlib.h>typedef int SLTDataType;typedef struct SListNode {SLTDataType data;struct SListNode* next; }SLTNode;//打印…...

代码随想录算法训练营第18天|二叉树

513. 找树左下角的值 最左边的结点的特性 1.只能是叶子结点&#xff0c; 2.必须考虑是最底层&#xff0c;所以要考虑树的深度 3.同样的深度考虑左子树 考虑迭代法,层序遍历 递归优点难搞的 /*** Definition for a binary tree node.* function TreeNode(val, left, righ…...

使用tftpd更新开发板内核

我们升级内核可以通过原厂提供的升级软件来进行&#xff0c;比如瑞芯微的RKDevTool.exe&#xff0c;只不过这种方式必须通过指定的OTG升级口&#xff0c;还得借助按键进入loader模式后才可以。 其实还可以利用一些通用的工具来进行升级&#xff0c;比如tftpd工具。 下载地址p…...

MySQL数据库整体知识点简述

目录 第一章&#xff1a;数据库系统概述 第二章&#xff1a;信息与数据模型 第3章 关系模型与关系规范化理论 第四章——数据库设计方法 第六-七章——MySQL存储引擎与数据库操作管理 第九章——索引 第10章——视图 第11章——MySQL存储过程与函数 第12章——MySQL 触…...

深入理解MySQL索引下推优化

在MySQL中&#xff0c;索引的使用对于查询性能至关重要。然而&#xff0c;即使有合适的索引&#xff0c;有时查询性能仍然不尽如人意。索引下推&#xff08;Index Condition Pushdown&#xff0c;ICP&#xff09;是一项能够进一步优化查询性能的技术。本文将详细讲解索引下推的…...

论文降重技巧:AI工具如何助力论文原创性提升?

论文降重一直是困扰各界毕业生的“拦路虎”&#xff0c;还不容易熬过修改的苦&#xff0c;又要迎来降重的痛。 其实想要给论文降重达标&#xff0c;我有一些独家秘诀。话不多说直接上干货&#xff01; 1、同义词改写&#xff08;针对整段整句重复&#xff09; 这是最靠谱也是…...

el-date-picker的使用,及解决切换type时面板样式错乱问题

这里选择器的类型可以选择日月年和时间范围&#xff0c;根据类型不同&#xff0c;el-date-picker的面板也展示不同&#xff0c;但是会出现el-date-picker错位&#xff0c;或者面板位置和层级等问题。 源代码&#xff1a; <el-selectv-model"dateType"placeholder&…...

Flutter 中的 ToggleButtonsTheme 小部件:全面指南

Flutter 中的 ToggleButtonsTheme 小部件&#xff1a;全面指南 Flutter&#xff0c;作为由 Google 开发的跨平台 UI 框架&#xff0c;为开发者提供了丰富的组件来构建现代化的应用程序。ToggleButtons 是 Material Design 组件库中的一个组件&#xff0c;它允许用户从一组选项…...

新手教程之使用LLaMa-Factory微调LLaMa3

文章目录 为什么要用LLaMa-Factory什么是LLaMa-FactoryLLaMa-Factory环境搭建微调LLaMA3参考博文 为什么要用LLaMa-Factory 如果你尝试过微调大模型&#xff0c;你就会知道&#xff0c;大模型的环境配置是非常繁琐的&#xff0c;需要安装大量的第三方库和依赖&#xff0c;甚至…...

Java函数笔记

1. Statement.executeQuery 和 Statement.executeUpdate 作用&#xff1a; 用于执行SQL查询和更新操作。 问题&#xff1a; 容易导致SQL注入攻击。 解决方法&#xff1a; 使用PreparedStatement进行参数化查询。 // 不安全的做法 Statement stmt connection.createStat…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

nnUNet V2修改网络——暴力替换网络为UNet++

更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...