MySQL45讲 第十六讲 “order by”是怎么工作的?

文章目录

  • MySQL45讲 第十六讲 “order by”是怎么工作的?
    • 一、引言
    • 二、全字段排序
      • (一)索引创建与执行情况分析
      • (二)执行流程
      • (三)查看是否使用临时文件
    • 三、rowid 排序
      • (一)参数控制与算法改变
      • (二)执行流程
      • (三)全字段排序和rowid 排序性能对比
    • 四、利用联合索引避免排序
      • (一)创建联合索引
      • (二)执行流程简化
      • (三)覆盖索引优化
    • 五、总结与思考

MySQL45讲 第十六讲 “order by”是怎么工作的?

一、引言

在应用开发中,经常需要根据指定字段排序显示结果。本文以查询城市为 “杭州” 的市民信息并按姓名排序为例,深入探讨 MySQL 中 “order by” 语句的执行流程、不同算法以及相关优化策略,避免在开发中出现性能问题。

例子:假设你要查询城市是“杭州”的所有人名字,并且按照姓名排序返回 前1000个人的姓名、年龄。

假设这个表的部分定义是这样的:

CREATE TABLE `t` (
`id` int(11) NOT NULL,
`city` varchar(16) NOT NULL,
`name` varchar(16) NOT NULL,
`age` int(11) NOT NULL,
`addr` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `city` (`city`)
) ENGINE=InnoDB;

这时,你的SQL语句可以这么写:

select city,name,age from t where city='杭州' order by name limit 1000;

二、全字段排序

(一)索引创建与执行情况分析

  1. MySQL会给每个线程分配一块内存用于排序,这块内存称为sort_buffer。为避免全表扫描,需在 city 字段创建索引。

    在这里插入图片描述

  2. 使用 explain 命令查看执行情况,Extra 字段中的 Using filesort 表示需要排序,MySQL 会为每个线程分配 sort_buffer 内存用于排序。
    在这里插入图片描述

(二)执行流程

  1. 初始化 sort_buffer,确定放入 namecityage 三个字段。
  2. city 索引找到满足条件的第一个主键 id
  3. 到主键 id 索引取出整行,取相关字段值存入 sort_buffer
  4. city 索引取下一个记录的主键 id,重复 3、4 步直到不满足条件。
  5. sort_buffer 中的数据按 name 字段做快速排序(可能在内存或使用外部排序,取决于 sort_buffer_size 参数和排序数据量)。
  6. 取前 1000 行返回给客户端。

(三)查看是否使用临时文件

  1. 通过设置 optimizer_traceenabled=on,计算执行语句前后 performance_schema.session_statusInnodb_rows_read 的差值,并查看 OPTIMIZER_TRACE 结果中的 number_of_tmp_files,可确定是否使用临时文件。若该值大于 0,表示使用了外部排序,MySQL 将数据分成多份排序后合并;若为0,表示可在内存中完成排序。

  2. 下图中的number_of_tmp_files=12代表MySQL将需要排序的数据分成12份,每一份单独排序后存在这些临时文件中。然后把这12个有序文件再合并成一个有序的大文件。

    在这里插入图片描述


三、rowid 排序

全字段排序算法过程里面,只对原表的数据读了一遍,剩下的操作都是在sort_buffer和临时文件中执行的。如果查询要返回的字段很多的话,那么sort_buffer里面要放的字段数太多,即行长度过长,这样内存里能够同时放下的行数很少,要分成很多个临时文件,排序的性能会很差。这时候就需要使用rowid排序

(一)参数控制与算法改变

SET max_length_for_sort_data = 16;

  1. max_length_for_sort_data 参数设置为较小值(如 16),且单行长度超过该值时,MySQL 采用 rowid排序算法。此算法放入 sort_buffer 的字段只有要排序的列(如 “name”)和主键 id

(二)执行流程

  1. 初始化 sort_buffer,确定放入 nameid 字段。

  2. city 索引找到满足条件的第一个主键 id

  3. 到主键 id 索引取出整行,取 nameid 字段存入 sort_buffer

  4. city 索引取下一个记录的主键 id,重复 3、4 步直到不满足条件。

  5. sort_buffer中的数据按 name 排序。

  6. 遍历排序结果取前 1000 行,按 id 值回原表取出 citynameage 字段返回给客户端。此算法多了一次回表操作,但在单行数据较大时,可在排序过程中一次排序更多行。

在这里插入图片描述

(三)全字段排序和rowid 排序性能对比

  1. 全字段排序在内存足够时优先选择,可直接从内存返回结果,减少磁盘访问
  2. rowid 排序在内存较小时使用,虽排序时能处理更多行,但需回表取数据,增加磁盘读操作。

四、利用联合索引避免排序

(一)创建联合索引

  1. 创建 cityname 的联合索引(如 city_user (city, name)),可确保从该索引取出行时按 name 递增排序,无需再进行排序操作。

    在这里插入图片描述

  2. 无需继续创建临时表和排序,使用explain指令查看,Extra字段已经没有Using filesort,证明

    在这里插入图片描述

(二)执行流程简化

  1. 从联合索引找到满足条件的第一个主键 id

  2. 到主键 id 索引取整行相关字段值直接返回。

  3. 从联合索引取下一个记录主键 id,重复 2 步直到满足条件结束。

    在这里插入图片描述

(三)覆盖索引优化

  1. 进一步创建 citynameage 的联合索引(如 city_user_age (city, name, age)),可利用覆盖索引,直接从索引获取数据返回,无需回表从主键索引取数据,性能更快,但需权衡索引维护代价。覆盖索引是指,索引上的信息足够满足查询请求,不需要回到主键索引上去取数据。

  2. 这样整个查询语句的执行流程就变成了:

    • 从索引(city,name,age)找到第一个满足city='杭州’条件的记录,取出其中的city、name和age 这三个字段的值,作为结果集的一部分直接返回;
    • 从索引(city,name,age)取下一个记录,同样取出这三个字段的值,作为结果集的一部分直接返回;
    • 重复执行步骤2,直到查到第1000条记录,或者是不满足city='杭州’条件时循环结束。

    在这里插入图片描述


五、总结与思考

MySQL 中 order by 语句有多种执行算法,开发人员应清楚其排序逻辑和系统资源消耗,根据实际情况选择合适方案。

  • 全字段排序可能需要使用临时表进行排序,在字段过多的情况下性能可能会很差。
  • 为了减少字段过长导致的排序性能下降,rowid排序算法放入 sort_buffer 的字段只有要排序的列(如 “name”)和主键 id
  • 如果需要进一步提高性能,可以采取联合索引乃至覆盖索引(字段已排序),这样就可以避免排序,但是需要消耗空间存储索引和维护索引为代价。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTML 基础标签——结构化标签<html>、<head>、<body>

文章目录 1. <html> 标签2. <head> 标签3. <body> 标签4. <div> 标签5. <span> 标签小结 在 HTML 文档中&#xff0c;使用特定的结构标签可以有效地组织和管理网页内容。这些标签不仅有助于浏览器正确解析和渲染页面&#xff0c;还能提高网页的可…

【原创】java+ssm+mysql电费管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

浅谈QT中Tab键的切换逻辑

浅谈QT中Tab键的切换逻辑 无意中发现在输入界面中按下Tab键时&#xff0c;没有按照预想的顺序切换焦点事件&#xff0c;如下图所示 这个现象还是很有趣&#xff0c;仔细观察了下&#xff0c;默认的切换顺序是按照控件拖入顺序&#xff0c;那么知道了这个问题想要解决起来就很简…

Linux系统编程学习 NO.10——进程的概念(1)

前言 本篇文章主要了解进程的概念。 #j 冯诺依曼体系结构 什么是冯诺依曼体系结构&#xff1f; 冯诺伊曼体系结构是计算机体系结构的一种经典范式&#xff0c;由计算机科学家约翰冯诺伊曼&#xff08;John von Neumann&#xff09;提出。该体系结构在计算机设计中起到了重要…

如何查看局域网内的浏览记录?总结五种方法,按步操作!一学就会!「管理小白须知」

如何查看局域网内的浏览记录&#xff1f; 你是否也曾为如何有效监控局域网内的浏览记录而苦恼&#xff1f; 监控局域网内电脑的浏览记录是确保员工工作效率、维护网络安全以及规范上网行为的重要手段。 别担心&#xff0c;今天我们就来聊聊这个话题&#xff0c;为你揭秘五种简…

室内场景建筑构成和常见物品识别图像分割系统:完整教学

室内场景建筑构成和常见物品识别图像分割系统源码&#xff06;数据集分享 [yolov8-seg-p6&#xff06;yolov8-seg-fasternet等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来…

前端vue3若依框架pnpm run dev启动报错

今天前端vue3若依框架pnpm run dev启动报错信息&#xff1a; > ruoyi3.8.8 dev D:\AYunShe\2024-11-6【无锡出门证】\wuxi-exit-permit-web > vite error when starting dev server: Error: listen EACCES: permission denied 0.0.0.0:80 at Server.setupListenHand…

nacos — 动态路由

Nacos 是一个阿里巴巴开源的服务注册中心&#xff0c;广泛用于微服务架构中。它除了支持服务注册和配置管理外&#xff0c;还可以配合网关实现动态路由。动态路由能够根据配置的实时更新动态调整路由规则&#xff0c;避免应用重启&#xff0c;实现路由的灵活管理。 网关的路由…

排序 (插入/选择排序)

目录 一 . 排序概念及运用 1.1 排序的概念 1.2 排序的应用 1.3 常见的排序算法 二 . 插入排序 2.1 直接插入排序 2.1 复杂度分析 2.3 希尔排序 2.4 希尔排序时间复杂度分析 三 . 选择排序 3.1 直接选择排序 3.2 堆排序 一 . 排序概念及运用 1.1 排序的概念 排序 : 所…

Unity网络开发基础(part5.网络协议)

目录 前言 网络协议概述 OSI模型 OSI模型的规则 第一部分 物理层 数据链路层 网络层 传输层 第二部分 ​编辑 应用层 表示层 会话层 每层的职能 TCP/IP协议 TCP/IP协议的规则 TCP/IP协议每层的职能 TCP/IP协议中的重要协议 TCP协议 三次握手 四次挥手 U…

框架学习01-Spring

一、Spring框架概述 Spring是一个开源的轻量级Java开发框架&#xff0c;它的主要目的是为了简化企业级应用程序的开发。它提供了一系列的功能&#xff0c;包括控制反转&#xff08;IOC&#xff09;、注入&#xff08;DI&#xff09;、面向切面编程&#xff08;AOP&#xff09;…

Late Chunking×Milvus:如何提高RAG准确率

01. 背景 在RAG应用开发中&#xff0c;第一步就是对于文档进行chunking&#xff08;分块&#xff09;&#xff0c;高效的文档分块&#xff0c;可以有效的提高后续的召回内容的准确性。而对于如何高效的分块是个讨论的热点&#xff0c;有诸如固定大小分块&#xff0c;随机大小分…

【深度学习】InstantIR:图片高清化修复

InstantIR——借助即时生成参考的盲图像修复新方法 作者:Jen-Yuan Huang 等 近年来,随着深度学习和计算机视觉技术的飞速发展,图像修复技术取得了令人瞩目的进步。然而,对于未知或复杂退化的图像进行修复,仍然是一个充满挑战的任务。针对这一难题,研究者们提出了 Insta…

qt获取本机IP和定位

前言&#xff1a; 在写一个天气预报模块时&#xff0c;需要一个定位功能&#xff0c;在网上翻来翻去才找着&#xff0c;放在这里留着回顾下&#xff0c;也帮下有需要的人 正文&#xff1a; 一开始我想着直接调用百度地图的API来定位&#xff0c; 然后我就想先获取本机IP的方…

(C++回溯算法)微信小程序“开局托儿所”游戏

问题描述 给定一个矩阵 A ( a i j ) m n \bm A(a_{ij})_{m\times n} A(aij​)mn​&#xff0c;其中 a i j ∈ { 1 , 2 , ⋯ , 9 } a_{ij}\in\{1,2,\cdots,9\} aij​∈{1,2,⋯,9}&#xff0c;且满足 ∑ i 1 m ∑ j 1 n a i j \sum\limits_{i1}^m\sum\limits_{j1}^na_{ij} i…

数字隔离器与光隔离器有何不同?---腾恩科技

在电子隔离中&#xff0c;两种常用的解决方案是数字隔离器和光学隔离器。两者都旨在电气隔离电路的各个部分&#xff0c;以保护敏感元件免受高压干扰&#xff0c;但它们通过不同的技术实现这一目标。本文探讨了这些隔离器之间的差异&#xff0c;重点介绍了它们的工作原理、优势…

什么是多因素身份验证(MFA)的安全性?

多因素身份验证(MFA)简介 什么是MFA 多因素身份验证(MFA)是一种安全过程&#xff0c;要求用户在授予对系统、应用程序或账户的访问权限之前提供两种或多种形式的验证。仅使用单个因素&#xff08;通常是用户名和密码&#xff09;保护资源会使它们容易受到泄露&#xff0c;添加…

10天进阶webpack---(2)webpack模块兼容性处理

回顾CMJ和ESM的区别 CMJ的本质可以使用一个函数概括 // require函数的伪代码 function require(path){if(该模块有缓存吗){return 缓存结果;}function _run(exports, require, module, __filename, __dirname){// 模块代码会放到这里}var module {exports: {}}_run.call(mod…

Spring源码学习(五):Spring AOP

免责声明 本人还处于学习阶段&#xff0c;如果内容有错误麻烦指出&#xff0c;敬请见谅&#xff01;&#xff01;&#xff01;Demo <dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.8<…

【全面解析】Stable Diffusion AI绘画入门教程,轻松掌握,让绘画新手也能快速上手!

前言&#xff1a; 随着人工智能技术的飞速发展&#xff0c;AI绘画领域迎来了一场革命。StableDiffusion作为一款强大的AI绘画工具&#xff0c;以其稳定的图像生成能力和卓越的创造力赢得了广泛关注。本文将向您介绍StableDiffusion的核心特点及其在绘画创作中的广泛应用。同时…