Order By Limit不稳定性

文章目录

    • 前置
    • 解决不确定性
    • 场景1 Order By索引
        • 1.1 背景
        • 1.2 不确定性产生原因
            • 1.2.1 正常情况下
            • 1.2.2 但是
        • 1.3 补充
        • 1.4 场景1总结
    • 场景2 Order by id
        • 2.1 背景
        • 2.2 不会产生不确定性
            • 原因1
            • 原因2
        • 2.3 推荐使用方式
    • 场景3 filesort
        • 3.1 背景
        • 3.2 不确定性产生原因
        • 3.3 内存排序和磁盘临时文件排序
        • 3.4 若上述SQL filesort使用了内存排序
            • 3.4.1 MySQL源码关于内存排序算法的选择
            • 3.4.2 问题1:什么情况下会使用优先队列
            • 3.4.3 问题2:如何快速判断是否使用了优先级队列
            • 3.4.4 问题3:如何前置判断,本次查询是否会使用优先队列
            • 3.4.5 问题4:我们写的sql是否会使用优先级队列
        • 3.5 若上述SQL filesort使用到了磁盘临时文件排序
            • 3.5.1 描述
            • 3.5.2 磁盘临时文件排序不确定性产生原因
      • 参考文档:

前置

MySQL 5.7官网给出了 order by limit一起使用,可能会产生不确定性:order by limit
不确定如图2.54
在这里插入图片描述

解决不确定性

order by limit一起使用时,order by后字段中需要有主键id或唯一键

场景1 Order By索引

1.1 背景
  • user表联合索引为city_name、主键id
select * from user where city = 'shanghai' order by name limit 0,5
  • user表联合索引city_name的叶子节点存储的数据如下
citynameid
beijingzhang三1
shanghaili四20
shanghaili四3
shanghaitian七40
shanghaiwang五5
shanghaiwang五60
shanghaizhu八7
xuzhouma朋80
1.2 不确定性产生原因
1.2.1 正常情况下
  • explain此SQL,Extra不会显示filesort即不需要排序;
  • 联合索引为city_name,所以数据在插入的时候就已经按照city_name排序好了;
  • 上述SQL取数时,直接从联合索引中拿出排序好的数据,并返回即可,所以存的时候是什么样顺序,取的时候也一定是什么样的顺序,不会产生不确定性。
1.2.2 但是

1)情况1

  • 假如两次查询期间发生了数据新增、删除、更新等操作,而且这些变更操作正好有city为shanghai的数据
  • 就可能导致联合索引city_name数据页发生了变化(重排数据顺序,甚至分页)等
  • 此时会导致查询的不确定性(漏查和重复查)
  • eg:第一次查询limit 0,5结果id为: [20,3,40,5,60]
    • 此时insert了一条数据(100,“shanghai”, “ma朋”)
    • 联合索引就可能发生了变化,id=100的这条数据,会排在id=40的数据前面(city同为shanghai,ma朋排序先于tiant)
    • 第二次查询limit0,5结果id集变为[20,3,100,40,5]

2)情况2

  • 假如user表除了city_name索引还有city_address联合索引,则查询会产生不确定性原因;
  • 两次查询可能会选择不同的联合索引,返回的数据自然不同。
1.3 补充

上述场景1和

先从db查询SQLselect *from t where city = 'shanghai' limit 0,5;
再Java程序中按照name排序返回

的这种查询方式区别:

  • 假如每次查询都force index city_name联合索引,则和场景1查询没有任何区别;
  • 本质都是使用city_name联合索引进行查询;
  • 若还有其他city_address索引,则补充SQL每次执行时可能选择city_address也可能选择city_name
1.4 场景1总结
  • 如果业务上可以保障查询期间不会有数据变更,并且每次查询都能使用相同的联合索引;

  • 则场景1不会产生数据不确定性并

  • 且下面两条SQL查询基本无区别代码块

    SELECT * from user where city = 'shanghai' order by name limit 0,5;
    SELECT * from user where city = 'shanghai'limit 0,5;
    

场景2 Order by id

2.1 背景
  • user表联合索引为:city_name、主键id、

    SELECT * from user where city ='shanghai' order by id limit 0,5;
    
2.2 不会产生不确定性
原因1

查询结果的展示顺序遵循以下描述

  • 如果查询使用到了索引,则结果按照索引字段顺序展示;

  • 如果查询没有使用到索引,则结果按照主键id顺序展示;

  • 如果查询使用到了索引,又order by id,则结果按照逐渐id顺序展示。

    所以场景2的查询,无论执行计划是什么样子的,查询结果总是按照主键id顺序展示,所以不会产生不确定性。

原因2

即使有数据新增、删除、更新,也不会产生不确定性

  • 第一次查询limit 0,5,结果id为:[20,3,40,5,60];
  • 此时insert了一条数据(100,“shanghai”,“ma朋”),联合索引就可能发生了变化,id=100的这条数据,会排在id=40的数据前面(city同为shanghai,ma朋排序先于tian七)
  • 第二次查询limit 0,5结果id集仍为[20,3,40,5,60]
  • 即使数据新增(100,‘shanghai’, ‘ma朋’),即使联合索引city_name需要调整数据顺序,但order by id,数据仍是按照主键id排序然后返回
2.3 推荐使用方式

相较于上述SQL,更推荐使用下述性能更好的书写方式

SELECT * from user where city = 'shanghai' order by name, id limit 0,5;

原因:场景2的书写方式,MySQL在执行时,可能直接按照主键id进行全表扫描,explain显示type = index、Extra = using where

场景3 filesort

3.1 背景
  • user表联合索引为:city_name、主键id

    SELECT * from user where city = 'shanghai' order by address limit 0,5;
    
3.2 不确定性产生原因
  • 上述SQL在执行时,会产生排序,即explain结果Extra中显示filesort;
  • filesort可能为内存排序,也可能是磁盘临时文件排序;
  • filesort时,如果查询出来的数据按照order by的字段(比如address),有相同的数据,且排序算法是不稳定性算法,则会产生不确定性。

详见MySQL5.7官方文档

  • limit、order byOrder by limit一同使用时产生不确定性
3.3 内存排序和磁盘临时文件排序
filesort内存排序磁盘临时文件排序
触发条件参与排序的数据大小<= sort_buffer_size参与排序的数据大小>sort_buffer_size
使用到的排序算法插入排序算法、快速排序、堆排序多路归并排序算法
3.4 若上述SQL filesort使用了内存排序
内存排序算法使用场景是否为稳定性排序算法是否会产生不确定性
插入排序处理小数据集或近乎有序的数据集时,优先选择
堆排序如果记录数量非常大,MySQL会优先选择堆排序
快速排序或快排序

如果排序算法不是稳定性算法 并且 参与内存排序的数据按照order by字段有相同的数据时,则可能产生返回数据的不确定性

3.4.1 MySQL源码关于内存排序算法的选择

filesort.cc文件关于快速排序和堆排序(优先队列)的分析

3.4.2 问题1:什么情况下会使用优先队列
  • 当order by的字段重复率特别高的时候,且带着limit查询,MySQL在满足某些条件下就会使用优先队列(PQ,priority queue)
  • limit N -> 本质就是找TOP N->优先级队列->堆排序
  • 优先级队列是一种优化技术,用于提高ORDER BY和LIMIT组合查询的性能,其查询结果是不确定性的
3.4.3 问题2:如何快速判断是否使用了优先级队列
  • 查看执行计划结果(可以使用Sequel Pro客户端执行SQL)
SET optimizer_trace='enabled=on';
SELECT * FROM ratings ORDER BY category LIMIT 300,31;
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`;
SET optimizer_trace='enabled=off';
  • 分析执行计划结果
"filesort_priority_queue_optimization":{
	"limit": 331, //limit m,n(m+n)
	"rows_estimate":992// 即MySQL源码中max_rows < num_rows / PO_slowness中的num_rows,MySQL优化器对需要进行排序的行的数量所做的估计。优化器对需要进行排序的行的数量所做的估计,动态变化值影响因素有:可用内存、系统负载、查询复杂性、表的统计信息、	
	"row_size":13,//一行数据的大小	
	"memory_available": 8388608,//sort_buffer_szie =8m(默认1M)	
	"chosen": false,//没有选择优先队列,为true则表示选择了PQ优先队列,没有cause原因	
	"cause":"quicksort_is_cheaper"//原因:快排性价比更高
}

"filesort_summary":{	
	"rows": 60,// 排序过程中会持有的行数	
	"examined_rows": 60,//sql语句where条件count(*)	
	"number_of_tmp_files": 0,//磁盘排序,使用的临时文件个数=0表示内存排序	
	"sort buffer size":20832,//使用内存排序时,使用到的内存大小
}

网上类似执行计划结果图如图2.55右图:使用了优先队列
在这里插入图片描述

chosen:true表示选择了优先级队列

3.4.4 问题3:如何前置判断,本次查询是否会使用优先队列

1)参考MySQL源码:MySQL Sever源码判断什么时候使用优先队列,简介:

  • s首先确定排序逻辑所处代码文件:filesort.cc
  • 然后在文件filesort.cc中搜索关键字:priority_queue
  • 找到check_if_pq_applicable方法,此方法的返回结果表明排序过程中是否使用到了优先队列(堆排序),同时此方法内容也有判断什么时候使用堆排序,什么时候使用快排

注意:

为了便于理解,后续filesort.cc源码中字段的值,我直接一一对应为执行计划结果filesort_priority_queue_optimization中的字段值

2)源码分析

// memory_available: 本质是sort_buff_size,对应执行计划中memory_available字段,默认1M
// max_record_length():即单行数据的大小,对应执行计划中的row_size
// sizeof(char*):指针的大小=8字节
const ulong num_available_keys = memory_available / (param->max_record_length() + sizeof(char *));

param->max_rows_per_buffer = (uint)param->max_rows +1;

// 情况一:整个rows_estimate是否都可以放入内存中,即内存够用
// num_rows:对应执行计划中rows_estimate	
if (num_rows < num_available_keys) {	
// max_rows 就是limit中M+N,对应执行计划中limit值	
// num_rows:对应执行计划中rows_estimate	
// PQ_slowness = 3	
	if (param->max_rows < num_rows / PQ_slowness) {	
		filesort_info->set_max_size(memory_available, param->max_record_length());
		trace_filesort.add("chosen",true);//选择PQ
		return filesort_info->max_size_in_bytes()>0;//true表示排序操作将在内存中执行;false则可能表示排序操作将使用磁盘上的临时文件来辅助排序
	} else {	
		// PO will be slower.不是优先级队列,直接使用快排	
		// 会一批一批的给sort buffer进行内存快速排序,结果放入排序临时文件,最终使对所有排好序的临时文件进行归并排序,得到最终的结果	
		trace_filesort.add("chosen", false).add_alnum("cause","sort_is_cheaper"); 
        return false;
}
    
//情况二:	
// Do we have space for LIMIT rows in memory?
// 即使整个源数据集不适合内存排序,如果至少有足够的空间来存储查询限制的行数(M+N),代码将仍然选择使用PQ
if (param->max_rows_per_buffer < num_available_keys) {
	filesort_info->set_max_size(memory_available,param->max_record_length());	
	trace_filesort.add("chosen",true);
	return filesort_info->max_size_in_bytes()>0;	
}

文字解释上述源码如下:

情况一:
1、内存够(我司默认sort_buffer_size=8M)
	即num_rows < num_available_keys
	即num_rows < sort_buffer_size /每行数据的size(执行计划结果中的filesort_priority_queue_optimization下的row_size)
    含义:内存8M、每行数据13bytes,指针大小8字节,总共可以放入x条数据,假如num_rows<x,则说明内存够!
    代入执行计划中的数值:992<8388608/ (13+8)

2、max_rows < num_rows / PQ_slowness
	当满足1时,MySQL会对比优先级队列排序和快排序的开销,选择一个比较合适的排序算法
	快速排序算法效率高于堆排序,但是堆排序实现的优先级队列,无需排序完所有的元素,就可以得到order by limit的结果
    MySQL官方认为快速排序的速度是堆排序的3倍
	所以,在满足1、的情况下&&满足公式max_rows < num_rows / PQ_slowness时会使用优先队列即使用堆排
	堆排序时,MySQL会把sort buffer作为priority queue
    如果不满足公式则仍用快排序。
	代入执行计划中的数值:331<992/3,显然不满足,则chosen:false
满足1、且满足2、时,则情况一在内存中使用buffer_sort作为优先级队列进行堆排序。只满足1、则使用内存快排

情况二:
	如果不满足场情况一中的1、则判断:Limit M+N < num_available_keys
	代入数值:331<8388608/ (13+8)
	如果满足,也可以使用buffer_sort作为PQ,在内存中进行堆排序
3.4.5 问题4:我们写的sql是否会使用优先级队列
select * from t where x order by xxx limit 200,200;	
SET optimizer_trace='enabled=on';
select * from t where x order by xxx limit 200,200;
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`;
SET optimizer_trace='enabled=off';

执行结果分析
"filesort_priority_queue_optimization":{
	"limit": 400,//limit m,n(m+n)
	"rows_estimate": 992, // 即max_rows < num_rows / P0_slowness中的num_rows (Estimate of 							number of rows in source record set即原表中预估计满足查询条件的行数)
	"row_size": 13,//一行数据的大小	
	"memory_available":8388608,//sort_buffer_szie =8m"chosen": false,//没有选择优先队列
	"cause": "quicksort_is_cheaper"//原因	
}

"filesort_summary":{
	"rows": 60,// 排序过程中会持有的行数	
	"examined_rows": 60,//参与排序的行数	
	"number_of_tmp_files": 0,//磁盘排序,使用的临时文件个数=0表示内存排序	
	"sort_buffer_size":20832,//使用内存排序时,使用到的内存大小	
	"sort_mode": "<sort_key,rowid>"//排序方式(rowid或者全字段排序)	
}
.

根据执行计划结果,先判断3.5.3中情况一、再判断是否满足情况二

3.5 若上述SQL filesort使用到了磁盘临时文件排序
3.5.1 描述
  • 当数据无法全部加载到内存排序时,会使用磁盘临时文件排序;
  • 这个过程会将涉及到数据分割成多个“块”,如果每个“块”也需要进行排序,则可能会使用快速排序或堆排序来分割和重组数据;
  • 然后在外部磁盘临时文件排序阶段使用归并排序,将多个已排序好的“块”合并成一个有序的块。
  • 综上:“多路归并排序”(muli-way merge sort)的技术,是一种结合了快速排序维排序和归并排序特点的方法,即在内存排序阶段,它可能会使用快速排序或堆排序来分割和重组数据,然后在外部排序阶段使用归并排序来合并来自不同临时文件的数据
3.5.2 磁盘临时文件排序不确定性产生原因

即使最终合并多个“块”时使用到了稳定的排序算法归并排序,但每个“块”在排序阶段,可能使用到快排和堆排序,鉴于二者都是不稳定性排序算法,故不稳定原因同上3.5

参考文档:

什么情况下order by limit会使用优先队列

filesort_priority_queue_optimization

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

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

相关文章

内衣洗衣机哪个牌子好用?甄选安利四款优质好用的内衣洗衣机

内衣洗衣机是近几年新兴的一种家用电器产品&#xff0c;正日益引起人们的重视。但是&#xff0c;面对市面上品牌繁多、款式繁多的内衣洗衣机&#xff0c;使得很多人都不知道该如何选择。身为一个数码家电博主&#xff0c;我知道这类产品在挑选方面有着比较深入的了解。为此&…

数据结构2月25日

第一道&#xff1a; 第二道&#xff1a; 1、插入到prev和next中间 1.new(struct list_head*)malloc(sizeof(struct list_head*)); if(newNULL) { printf("失败\n"); return; } new->nextprev->next; prev->nextnew; return; 2、删除prve和next…

redis——客户端

Redis是一个典型一对多服务器程序&#xff0c;一个服务器可以与多个客户端进行网络连接&#xff0c;每隔客户端可以向服务器发送命令请求&#xff0c;而服务器则接收并处理客户端发送的命令请求&#xff0c;并向客户端返回命令请求。 通过是一个I/O多路复用技术实现的文件事件处…

3分钟快速实现串口PLC远程下载程序操作说明

3分钟快速实现串口PLC远程下载程序操作说明 搜索蓝蜂物联网官网&#xff0c;即可免费领取样机使用&#xff01;&#xff01;先到先得&#xff01;&#xff01;&#xff01; 一. 适用产品型号 其余型号网关此功能正在开发中&#xff0c;敬请期待。 二. 远程下载功能使用流程 …

数据结构--双向链表专题

目录 1. 双向链表的结构2. 实现双向链表预先的准备初始化尾插、头插尾删、头删查找在pos位置之后插⼊数据删除pos位置的数据 3. 顺序表和双向链表的分析 1. 双向链表的结构 注意&#xff1a;这里的“带头”跟前面我们说的“头结点”是两个概念&#xff0c;为了更好的理解直接称…

Nginx的反向代理:实现灵活的请求转发和内容缓存

一、引言&#xff1a;代理服务器的简介 本节介绍代理服务器的基本配置。学习如何通过不同协议将 NGINX 请求传递给代理的服务器&#xff0c;修改发送到代理服务器的客户端请求标头&#xff0c;以及配置来自代理服务器的响应缓冲。 代理通常用于在多个服务器之间分配负载&…

tigramite教程(二)生物地球科学案例研究

文章目录 数据生成与绘图因果发现分析平稳性假设、确定性、潜在混杂因素结构假设参数假设使用PCMCIplus的滑动窗口分析聚合因果图非参数因果效应估计假设的图形和调整集干预的真实情况假设的参数模型和因果效应的估计使用关于图的不同假设进行估计非因果估计项目地址 这个文件…

力扣随笔之颜色分类(中等75)

思路&#xff1a;定义两个指针划分left&#xff0c;right划分三个区域left左边是红色区域&#xff0c;right右边是蓝色区域&#xff0c;left和right之间是白色区域&#xff1b;定义一个遍历指针遍历整个数组&#xff0c;遇到红色与left所指位置数字交换&#xff0c;并将left自加…

鸿蒙开发实战-手写一个Openharmony投屏工具

实战手写一个Openharmony投屏工具&#xff0c;实现代码分享如下&#xff1a; java import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOExcepti…

一篇文章告诉你ELK Stack是什么

目录 ELK Stack简介 ELK Stack优点 ELK Stack组成 Elasticsearch Elasticsearch简介 Elasticsearch主要特点 Elasticsearch核心概念 Elasticsearch的配置 Logstash Logstash简介 Logstash过滤器之grok正则匹配 Logstash过滤器之mutate数据修改 Logstash过滤器之Ge…

如何快速将每个图片做二维码?批量生成图片码的步骤

现在很多商品的包装上扫码都会展现出物品的图片信息&#xff0c;每个物品都会有单独的一张物品信息图片。那么当导出一批图片后&#xff0c;如何快速将每张图片单独生成一个二维码来使用呢&#xff1f;本文小编将通过图文内容给大家讲解一下图片二维码生成器的批量建码功能该如…

automatic_mine_sweeper —— A project review to improve myself

1. How to understand the whole structure of the project? 1.Cbutton.h 和 Cbutton.cpp文件&#xff1a; Cbutton.h文件- // Cbutton.h : main header file for the CBUTTON application //#if !defined(AFX_CBUTTON_H__240DD99D_BEDE_49BD_A960_3268C3644816__INCLUDED_…

Python实用技巧:处理JSON文件写入换行问题

Python实用技巧&#xff1a;处理JSON文件写入换行问题 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 &#x1f448; 希望得到您的订阅…

05 Flink 的 WordCount

前言 本文对应于 spark 系列的 Spark 的 WordCount 这里主要是 从宏观上面来看一下 flink 这边的几个角色, 以及其调度的整个流程 一个宏观 大局上的任务的处理, 执行 基于 一个本地的 flink 集群 测试用例 /*** com.hx.test.Test01WordCount** author Jerry.X.He* ver…

架构设计:流式处理与实时计算

引言 随着大数据技术的不断发展&#xff0c;流式处理和实时计算在各行各业中变得越来越重要。那么什么是流式处理呢&#xff1f;我们又该怎么使用它&#xff1f;流式处理允许我们对数据流进行实时分析和处理&#xff0c;而实时计算则使我们能够以低延迟和高吞吐量处理数据。本…

Bert基础(四)--解码器(上)

1 理解解码器 假设我们想把英语句子I am good&#xff08;原句&#xff09;翻译成法语句子Je vais bien&#xff08;目标句&#xff09;。首先&#xff0c;将原句I am good送入编码器&#xff0c;使编码器学习原句&#xff0c;并计算特征值。在前文中&#xff0c;我们学习了编…

4.测试教程 - 用例篇

文章目录 1.测试用例的基本要素2.测试用例的给我们带来的好处3.测试用例的设计方法3.1基于需求进行测试用例的设计3.1.1功能需求测试分析3.1.2非功能需求测试分析 3.2具体的设计方法3.2.1等价类3.2.2边界值3.2.3错误猜测法3.2.4判定表3.2.5场景设计法3.2.6因果图3.2.7因果图的需…

c++:vector的相关oj题(136. 只出现一次的数字、118. 杨辉三角、26. 删除有序数组中的重复项、JZ39 数组中出现次数超过一半的数字)

文章目录 1. 136. 只出现一次的数字题目详情代码(直接来异或&#xff09;思路 2. 118. 杨辉三角题目详情代码1思路代码2思路2 3. 26. 删除有序数组中的重复项题目详情代码思路 4. JZ39 数组中出现次数超过一半的数字题目详情代码1&#xff08;暴力&#xff09;思路1代码2&#…

A Visual Guide to Mamba and State Space Models

用于语言建模的 Transformers 的替代方案 Transformer 架构一直是大型语言模型 &#xff08;LLMs&#xff09; 成功的主要组成部分。它已被用于当今几乎所有LLMs正在使用的产品&#xff0c;从 Mistral 等开源模型到 ChatGPT 等闭源模型。 为了进一步改进LLMs&#xff0c;开发…

【HarmonyOS】鸿蒙开发之Stage模型-基本概念——第4.1章

Stage模型-基本概念 名词解释 AbilityStage:应用组件的“舞台“ UIAbility:包含UI界面的应用组件&#xff0c;是系统调度的基本单元 WindowStage:组件内窗口的“舞台“ Window&#xff1a;用来绘制UI页面的窗口 HAP:Harmony Ability Package(鸿蒙能力类型的包) HSP:Harmony Sh…
最新文章