order by rand() 实现随机获取消息

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: order by rand() 实现随机获取消息

业务场景

比如,要做一个学习单词的App,实现用户在打开首页的时候,随机显示三个单词:

// 创建单词表
mysql> create table words(
  `id` int NOT NULL AUTO_INCREMENT,
  `word` varchar(64) DEFAULT NULL,
  PRIMARY KEY(`id`)
)ENGINE=InnoDB;
// 插入10000行模拟数据
mysql> insert into words values(1, "abandon") (...) (...);
/********************************************************
*  @ order by rand() 
*  实现随机排序,随机选取三个单词
********************************************************/
mysql> select word from words order by rand() limit 3;
// 使用explain命令查看该语句的执行情况
mysql> explain select word from words order by rand() limit 3;

通过学习前面 Mysql数据库 order by 实现原理,我们知道,对于使用InnoDB引擎的表来说,全字段排序,可以不用回表,所以,会被优先采用。但是,对于内存表来说,数据已经读到内存了,无非是根据数据行的位置,直接访问内存的得到,不会再访问磁盘。所以,对于使用内存临时表进行的排序来说,优化器没有了回表的顾虑,rowid 排序会被优先采用。

内存临时表

explain结果,Extra字段 Using temporary表示使用临时表,Using filesort表示需要排序。

SQL语句执行流程

  1. 创建临时表,使用memory引擎。该临时表有两个字段,一个 double 类型字段,我们记为R,一个varchar(64)类型字段,我们记为W,表上没有索引。
  2. 根据主键id的顺序,从 words 表中读取 word 值。对于每个 word 值,调用rand()生成一个0~1之间的随机小数,放到R字段,并将对应的 word 放入W字段。
  3. 此时,临时表中有10000行数据,我们需要根据 R 的值进行排序;
  4. 初始化 sort_buffer,确定放入 doule 和 int 两个字段;(其中:double字段保存临时表的R值,int字段保存“位置信息”,后面我们解释为什么保存的是位置信息)
  5. 从内存临时表中一行一行读取R和 “位置信息”放入sort_buffer;
  6. 根据R字段进行排序,排序完,取前三行结果,依次到内存临时表根据位置信息取出word值,返回。

Mysql表是如何定位一条记录的

答案是:rowid,每个引擎用来唯一标记行信息的标识。

  • 对于创建了主键的 InnoDB 表来说,rowid 就是主键ID;
  • 没有创建主键的 InnoDB 表,系统会默认生成一个6字节的 rowid 作为主键;
  • 对于Memory引擎的表,“位置信息”可以理解为数组的下标。

磁盘临时表

临时表一定是内存临时表吗?不一定。

参数 tmp_table_size 限制了内存临时表的大小,默认16 M,如果超过最大限制,就会使用磁盘临时表,磁盘临时表使用的引擎默认是 InnoDB,当使用磁盘临时表的时候,对应的就是一个没有显示索引的InnoDB表的排序过程。

排序优化

经过上面的排序完成后,所有的数据都有序了,但是我们只需要前三个,有点浪费。所以Mysql在5.6版本之后引入新的排序算法:优先队列排序算法(堆排序)。

mysql> select word from words order by rand() limit 3;

如何得到严格的随机结果

  1. 扫描全表,得到总行数C
  2. 取得 Y=floor(C * rand())。floor取整。
  3. select * from words limit Y,1 取得一行

limit Y, 1; 和 id >= Y limit 1; 一样吗?

不一样,MySQL 处理 limit Y,1 的做法就是按顺序一个一个地读出来,丢掉前 Y 个,然后把下一个记录作为返回结果。

笔记参考于极客时间《MySQL实战45讲》

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
XML Dubbo fastjson
FastJson - 设置默认参数,全局配置方式及爬坑
FastJson - 设置默认参数,全局配置方式及爬坑
1997 0
CentOS7编译安装openssl1.1.1
centos7默认提供的openssl版本是1.0.2的,想要升级openssl版本则需要手动进行编译
|
4月前
|
传感器 人工智能 API
通义灵码2.5深度评测:编程智能体与MCP工具的革新体验
通义灵码2.5通过“智能体+MCP”组合,重新定义了AI编码助手的边界。其价值不仅在于代码生成效率,更在于通过工具链整合和环境感知,推动开发流程向“声明式编程”演进。对于开发者而言,它既是提升效率的利器,也是探索AI辅助开发边界的实验场。
327 8
|
11月前
|
存储 关系型数据库 MySQL
阿里云PolarDB解决游戏行业全球部署高并发问题
阿里云PolarDB解决游戏行业全球部署高并发问题
|
6月前
|
人工智能 自然语言处理 搜索推荐
WritingBench:阿里最新大模型写作能力多维测评工具,开源32B深度思考写作模型
近日,阿里研究团队联合中国人民大学和上海交通大学共同开源了WritingBench ——该评估基准覆盖6大领域、100个细分场景,共包含1239条评测数据,以期为生成式写作提供全面的评估。团队进一步发现,凭借思维链技术和动态评估体系的加持,基于Qwen开发的32B创作模型在创意型任务上表现接近顶尖模型R1,为高效能创作开辟了新路径。
408 5
|
机器学习/深度学习 PyTorch 算法框架/工具
数据平衡与采样:使用 DataLoader 解决类别不平衡问题
【8月更文第29天】在机器学习项目中,类别不平衡问题非常常见,特别是在二分类或多分类任务中。当数据集中某个类别的样本远少于其他类别时,模型可能会偏向于预测样本数较多的类别,导致少数类别的预测性能较差。为了解决这个问题,可以采用不同的策略来平衡数据集,包括过采样(oversampling)、欠采样(undersampling)以及合成样本生成等方法。本文将介绍如何利用 PyTorch 的 `DataLoader` 来处理类别不平衡问题,并给出具体的代码示例。
2354 2
|
人工智能 自然语言处理 测试技术
跨平台多模态智能体基准测试来了!但全班第一只考了35.26分
【8月更文挑战第31天】近日,Tianqi Xu等研究者在arXiv发布了题为《CRAB: Cross-environment Agent Benchmark for Multimodal Language Model Agents》的论文,提出了一种全新的智能体基准测试框架CRAB,旨在解决现有MLM智能体交互环境基准测试的局限性。CRAB支持跨环境任务,提供细粒度评价方法及高效的任务构建机制,并包含100个跨平台任务的Crab Benchmark-v0。实验结果显示,GPT-4o单智能体在该基准测试中表现最佳,任务完成率达35.26%。CRAB为未来跨环境智能体研究提供了重要参考。
205 1
|
SQL 关系型数据库 MySQL
Python系列:教你使用PyMySQL操作MySQL数据库
Python系列:教你使用PyMySQL操作MySQL数据库
644 8
|
JSON 数据格式
Hive----get_json_object() 函数
get_json_object() 函数
3498 0
|
Linux
`grep`命令搜索多个文件中的特定模式
`grep`命令搜索多个文件中的特定模式
619 2