MySQL45讲之随机查询和临时表

本文介绍 MySQL 随机查询的工作流程、优化随机查询的方式、和临时表。

工作流程

根据下表结构建立 words 表,并通过过程插入 10000 条模拟数据。

CREATE TABLE words (
  id int(11) NOT NULL AUTO_INCREMENT,
  word varchar(64) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB;

随机查询场景,”从上表中随机查询三个 wrod”。简单直接的查询方式就是, SELECT * FROM words ORDER BY rand() LIMIT 3;,下面分析下这条语句的工作流程。

内存临时表

这个排序需要使用临时表,当临时表数据量小于 tmp_table_size 时,会使用内存临时表。 tmp_table_size 默认是 16M。

一般情况下,会优先采用全字段排序方式,因为可以减少一次回表查询。不过,因为是使用的内存临时表,所以 rowid 方式回表也是直接查询内存,并且 rowid 方式因为只存储 rowid 和排序字段,在相同大小的 sort_buffer 下,可以存储更多的行,避免或减少外存文件的使用。所以,MySQL 会选择 rowid 排序方式。

如果不存在 LIMIT 关键字,工作流程:
1、创建一个临时表,采用内存 memory 引擎,包含一个 double 字段,表示 rand() 函数生成的随机数,另一个是 word 字段
2、从原表中根据主键取出 word 值,并执行 rand 函数生成一个 0 ~ 1 的数字写入到临时表,直至写完 10000 行,扫描行数 10000
3、初始化 sort_buffer,确定只有一个 double 和一个整形字段
4、从临时表中按行读取 double 字段,和位置信息,写入到 sort_buffer,扫描行数变为 20000
5、根据 double 字段排序
6、排序完后,根据前 3 行的位置信息到临时表中取对应的 word,返回客户端,扫描行数变为 20003

位置信息含义:

  • 对于有主键的InnoDB表来说,这个rowid就是主键ID;
  • 对于没有主键的InnoDB表来说,这个rowid就是由系统生成的;
  • MEMORY引擎不是索引组织表。在这个例子里面,你可以认为它就是一个数组。因此,这个rowid其实就是数组的下标。

如果语句中存在 LIMIT 关键字,所以还会使用 MySQL5.6 提供的优先队列的排序方式进行优化。

大致工作流程:
1、根据主键从原数据表中,先取前 3 行,构成一个堆
2、取一行剩余的数据添加到堆中,再调整
3、重复第二步,直至所有剩余的行插入完成

按优先级队列排序,仅扫描10003行。

[En]

Sort by priority queue, with only 10003 lines scanned.

磁盘临时表

当临时表的数据量大小大于 tmp_table_size 时,则会采用磁盘临时表。并且,这时候回表意味着随机读文件,所以会搭配全字段排序方式。

对于 SELECT * FROM words ORDER BY rand() LIMIT 3; 需要扫描 20003 行,随着数据量增大,它执行速度会越来越慢,有什么优化方式么?

方案1:

select max(id), min(id) into @M,@N from t ;
set @X= floor((@M-@N+1)*rand() + @N);
select * from t where id >= @X limit 1;

计算主键 id 的范围,然后在 id 范围内进行随机,再取不小于随机值的行(注意不能用 id = @X 的判断逻辑,否则可能 id 不存在)。

虽然这个方案可以随机,但是随机是不公平的。因为表可能会删除数据,id 不连续,存在空洞。

方案2:

select count(*) into @C from t;
set @Y1 = floor(@C * rand());
set @Y2 = floor(@C * rand());
set @Y3 = floor(@C * rand());
select * from t limit @Y1,1; //在应用代码里面取Y1、Y2、Y3值,拼出SQL后执行
select * from t limit @Y2,1;
select * from t limit @Y3,1;

为了保证随机是公平的,那么可以随机 [1, 总行数] 中的一个数,然后通过分页操作拿到对应的行。此时需要扫描 C + Y1 + Y2 + Y3 + 3 行。

进一步优化,可以采用下面的查询方式,只需要扫描 C + max(Y1, Y2, Y3) + 3 行。

前提,对 Y1、Y2、Y3 提前排序好
id1 = select * from t limit @Y1,1;
id2 = select * from t where id > id1 limit @Y2 - @Y1,1;
id3 = select * from t where id > id2 limit @Y3 - @Y2,1;

Original: https://www.cnblogs.com/flowers-bloom/p/mysql45-random-query-and-tmp-file.html
Author: flowers-bloom
Title: MySQL45讲之随机查询和临时表

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/508124/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • likeshop搭建商城系统,一步到位

    什么是商城系统?商城系统又称在线商城系统,是一个功能完善的在线购物系统,主要为在线销售和在线购物服务。 一般的商城系统运营模式有B2C单商户商城系统,B2B2C多商户商城系统以及S…

    数据库 2023年6月14日
    0147
  • 第07章 MySQL单行函数

    第07章 MySQL单行函数 1. 函数的理解 1.1 什么是函数 函数在计算机语言的使用中贯穿始终,函数的作用是什么呢?它可以把我们经常使用的代码封装起来,需要的时候直接调用即可…

    数据库 2023年5月24日
    070
  • DHCP:IP 并非与生俱来

    初识 DHCP 众所周知,因特网上的每台设备都规定了其全世界唯一的地址,也就是说 “IP 地址”,正是由于有了 IP 地址,才保证了用户在连网的计算机上操作…

    数据库 2023年6月6日
    0111
  • idea的使用技巧和必要的设置

    idea 如何开启多个线程 打开下面按钮,然后运行相同的代码即可 打开idea需要选择打开哪一个项目 设置如下,关闭下面选项即可 posted @2022-06-17 21:07 …

    数据库 2023年6月14日
    092
  • Exception Handling Considered Harmful

    Do, or do not. There is no try. — Yoda, The Empire Strikes Back(George Lucas) Recent progr…

    数据库 2023年6月9日
    090
  • Our Feeling

    走过春夏秋冬走过五湖四海就是没有走过你 看过日出日落看过潮起潮落就是看不到你 本文来自博客园,作者:ukyo–BlackJesus,转载请注明原文链接:https://…

    数据库 2023年6月11日
    095
  • 常见的限流算法

    通过限制并发访问数或者限制一个时间窗口内允许处理的请求数量来保护系统,例如,通过限流,你可以过滤掉产生流量峰值的客户和服务。 令牌桶算法 令牌桶算法是常见的一种限流算法。假设有一个…

    数据库 2023年6月16日
    081
  • 🤺全套MySQL数据库教程_Mysql基础入门教程,零基础小白自学MySQL数据库必备教程👾#001 # 第一单元 数据库概述 #

    二、本单元知识点概述 (Ⅰ)知识点概述 二、本单元目标 (Ⅰ)重点知识目标 1.什么是数据库2.市面上常见的数据库有哪些3.SQL和数据库的关系 (Ⅱ)能力目标 1.熟练安装MyS…

    数据库 2023年5月24日
    0111
  • Spring 学习笔记

    Spring 框架是由于软件开发的复杂性而创建的。Spring 使用的是基本的 JavaBean 来完成以前只可能由 EJB 完成的事情。 Spring 一. Spring Fra…

    数据库 2023年6月11日
    080
  • mysql中all用法和any的用法和内连接和外连接,全外连接,联合查询,自连接

    与子查询配合使用 在all的用法中,有三种 语法:select 列名 from 表名 where 列名 <> all(select 列名 from 表名 where 条…

    数据库 2023年5月24日
    0112
  • MySQL实战45讲 4,5

    04 | 深入浅出索引(上) 索引的出现其实就是为了提高数据查询的效率,就像书的目录一样 索引的常见模型 哈希表、有序数组和搜索树 哈希表 User2 和 User4 根据身份证号…

    数据库 2023年6月16日
    0112
  • JavaScript 获取 Url 上的参数(QueryString)值

    获取URL里面传的参数,在Js中不能像后台一样使用Request.QueryString来获取URL里面参数,下面介绍两种方式用来获取参数 方式一:使用split分隔来获取,这种方…

    数据库 2023年6月9日
    078
  • Java并发编程之AQS以及源码解析

    文章目录 概览 实现思路 实现原理 * 源自CLH锁 AQS数据模型 CAS操作 主要方法 * 自定义同步器的实现方法 AQS定义的模板方法 源码解读 * 等待状态释义 AQS获取…

    数据库 2023年6月6日
    077
  • MySQL学习(3)—MySQL常用命令

    ps:此随笔基于mysql 5.7.*版本。 准备 net start mysql 启动MySQL服务 net stop mysql 关闭MySQL服务 mysql [-h exi…

    数据库 2023年6月14日
    074
  • Linux安装nginx并配置ssl自签证书

    一、下载nginx压缩包:官网下载地址http://nginx.org/download/,点击进入选择合适自己系统的版本,本机已centos安装nginx-1.9.1.tar.g…

    数据库 2023年6月14日
    095
  • Java基础六—Java集合框架Map

    HashMap HashMap使用hash数组+单链表实现,数组中的每个元素都是链表,由Node内部类实现,当链表长度超过8时,转化为红黑树。 HashMap实现了Map接口,即允…

    数据库 2023年6月6日
    076
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球