news 2026/2/7 22:22:21

MySQL的行号方言

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL的行号方言

SQL 通常分为三大类:

类型全称作用常见命令
DDLData Definition Language定义/修改结构CREATE,ALTER,DROP,TRUNCATE
DMLData Manipulation Language操作数据内容SELECT,INSERT,UPDATE,DELETE
DCLData Control Language控制访问权限GRANT,REVOKE

SELECT VERSION();
查看MySQL的版本

核心思想是:给按时间排序后的每一行分配一个连续序号,然后每隔一定间隔取一条(或按比例取),从而实现“时间轴上的均匀采样”。


✅ 推荐方法:使用ROW_NUMBER()+ 比例过滤(MySQL 8.0+)

✅ 要求:MySQL 8.0 或更高版本(支持窗口函数)

📌 最佳实践 SQL:

-- 方法1:精确抽取 30%(推荐) INSERT INTO target_table (id, user_id, amount, create_time, status) SELECT id, user_id, amount, create_time, status FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY create_time) AS rn, COUNT(*) OVER () AS total_rows FROM source_table WHERE status = 'paid' -- 可选:先过滤 ) t WHERE rn <= total_rows * 0.3;

🔍 原理解释:

  1. ROW_NUMBER() OVER (ORDER BY create_time)→ 按时间升序编号:1, 2, 3, ..., N
  2. COUNT(*) OVER ()→ 获取总行数N
  3. rn <= N * 0.3→ 取前 30% 的行
    • 因为已按时间排序,前 30% 就是时间最早的 30%❌(这不是“均匀”!)

⚠️ 注意:上面这个方法是“取前30%”,不是“均匀分布”!


✅ 正确实现“时间均匀分布”的方法

要实现在整个时间范围内均匀抽取 30%(比如每10分钟抽3条,而不是只抽前3个月),应该用等间距采样

✅ 方法2:等间距采样(真正均匀)

-- 真正的时间均匀采样:每隔 k 行取 1 行,使得最终约 30% INSERT INTO target_table (id, user_id, amount, create_time, status) SELECT id, user_id, amount, create_time, status FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY create_time) AS rn FROM source_table WHERE status = 'paid' ) t WHERE MOD(rn - 1, 3) = 0; -- 每3行取1行 ≈ 33.3%

但 33.3% ≠ 30%。要精确 30%,可这样:

✅ 方法3:精确 30% 均匀采样(最优解)

INSERT INTO target_table (id, user_id, amount, create_time, status) SELECT id, user_id, amount, create_time, status FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY create_time) AS rn, COUNT(*) OVER () AS total FROM source_table WHERE status = 'paid' ) t WHERE MOD(rn * 100, total) < 30;

但这较复杂。更简单且实用的做法是:

✅ 方法4:使用NTILE分桶(推荐!)

-- 将数据按时间分成 10 桶,每桶取 3 桶 → 精确 30% INSERT INTO target_table (id, user_id, amount, create_time, status) SELECT id, user_id, amount, create_time, status FROM ( SELECT *, NTILE(10) OVER (ORDER BY create_time) AS bucket FROM source_table WHERE status = 'paid' ) t WHERE bucket IN (1, 2, 3); -- 取前3桶 = 30%

这是最符合“时间均匀”要求的方法!

  • NTILE(10)把按时间排序的数据均分为10个连续时间段
  • 每个bucket包含约 10% 的数据
  • bucket IN (1,2,3)→ 覆盖整个时间范围的前30%时间段?❌

等等!这还是连续时间段,不是“均匀分布”。


✅ 终极正确方案:系统抽样(Systematic Sampling)

目标:在整个时间序列中等间隔抽取,确保样本覆盖全年,不聚集在某一段。

✅ 最佳 SQL(MySQL 8.0+):

-- 计算采样步长:每 k 行取 1 行,使得总数 ≈ 30% WITH numbered AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY create_time) AS rn FROM source_table WHERE status = 'paid' ), params AS ( SELECT MAX(rn) AS total, CEIL(MAX(rn) / (MAX(rn) * 0.3)) AS step -- 实际可简化 FROM numbered ) SELECT n.* FROM numbered n CROSS JOIN params p WHERE MOD(n.rn - 1, FLOOR(p.total / (p.total * 0.3))) = 0 LIMIT FLOOR((SELECT COUNT(*) FROM source_table WHERE status = 'paid') * 0.3);

太复杂了!


✅ 简洁高效方案(生产推荐)

直接用MOD(ROW_NUMBER(), k) = 0,选择合适的 k

假设总行数 ≈ 2,000,000,要抽 600,000 条(30%),则:

  • 采样间隔 k = 总行数 / 目标行数 ≈ 2000000 / 600000 ≈ 3.33
  • MOD只能用整数,所以取k = 3 或 4

为了更精确,我们可以动态计算:

✅ 最终推荐 SQL(简洁 + 均匀 + 高效):

-- 方案A:固定间隔(简单有效) INSERT INTO target_table SELECT id, user_id, amount, create_time, status FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY create_time) AS rn FROM source_table WHERE status = 'paid' ) t WHERE MOD(rn, 3) = 1; -- 每3行取1行 → ~33.3%,接近30%

如果一定要严格 30%,且接受轻微不均匀,可用:

✅ 方案B:结合 LIMIT(精确数量 + 均匀起点)

-- 先确定起始偏移,再等间隔取 SET @total = (SELECT COUNT(*) FROM source_table WHERE status = 'paid'); SET @target = FLOOR(@total * 0.3); SET @step = CEIL(@total / @target); PREPARE stmt FROM ' INSERT INTO target_table SELECT id, user_id, amount, create_time, status FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY create_time) AS rn FROM source_table WHERE status = "paid" ) t WHERE MOD(rn - 1, ?) = 0 LIMIT ? '; EXECUTE stmt USING @step, @target; DEALLOCATE PREPARE stmt;

✅ 这个方案:

  • 按时间排序
  • 从第1行开始,每隔@step行取1条
  • 最多取@target条(精确 30%)
  • 样本均匀分布在整个时间轴上

📊 效果对比

表格

方法是否均匀是否精确30%性能复杂度
ORDER BY RAND() LIMIT❌ 随机聚集⚠️ 极差
ROW_NUMBER() <= 0.3*N❌ 只取早期✅ 高
MOD(rn, 3) = 1✅ 均匀❌ ~33%✅✅ 极高
动态步长 + LIMIT✅ 均匀✅ 精确✅ 高

✅ 结论:用哪条?

如果你接受≈30%(如33%),用这条(最简单高效):

INSERT INTO target_table SELECT id, user_id, amount, create_time, status FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY create_time) AS rn FROM source_table WHERE status = 'paid' ) t WHERE MOD(rn, 3) = 1;

如果你必须严格30% + 均匀,用动态步长方案(见上文)。

💡绝大多数场景下,MOD(rn, 3) = 1已足够好:它简单、快、真正时间均匀,且比例接近30%。

只要你的 MySQL 是8.0+,这些方案都能高效运行(200万行通常 < 30秒)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/7 7:35:03

基于Springboot+Vue的图书馆在线占座系统源码文档部署文档代码讲解等

课题介绍 本课题旨在设计并实现一套基于SpringBootVue的图书馆在线占座系统&#xff0c;解决校园图书馆座位资源紧张、人工占座混乱、座位利用率低、管理员管控不便等问题&#xff0c;适配学生自主占座与图书馆规范化管理的核心需求。系统采用前后端分离架构&#xff0c;后端以…

作者头像 李华
网站建设 2026/2/7 2:37:37

基于Springboot+Vue的图书馆座位预约系统源码文档部署文档代码讲解等

课题介绍 本课题旨在设计并实现一套基于SpringBootVue的图书馆座位预约系统&#xff0c;解决校园图书馆座位资源分配不均、人工预约繁琐、座位浪费严重及管理员管控低效等问题&#xff0c;适配学生座位预约与图书馆规范化管理的核心需求。系统采用前后端分离架构&#xff0c;后…

作者头像 李华
网站建设 2026/2/7 15:30:11

UI 设计组件的价值与实践+常用 UI 设计组件核心规范清单

在数字产品的界面世界里&#xff0c;设计组件就像是建筑中的标准化砖石&#xff0c;既支撑起界面的稳固性&#xff0c;又决定了体验的流畅度。从一张信息卡片到一条进度条&#xff0c;从一个分页控件到一整块瓷片区&#xff0c;这些看似微小的元素&#xff0c;正是构成优秀 UI …

作者头像 李华
网站建设 2026/2/6 0:33:19

2024年AI内容审核最新趋势:原生应用深度解析

2024 年 AI 内容审核最新趋势&#xff1a;原生应用深度解析 关键词&#xff1a;AI 内容审核、原生应用、图像识别、自然语言处理、机器学习模型、多模态融合、自动化 摘要&#xff1a;本文深入探讨 2024 年 AI 内容审核在原生应用领域的最新趋势。首先介绍 AI 内容审核的背景…

作者头像 李华
网站建设 2026/2/5 7:44:41

基于SpringBoot的智能医疗辅助系统(源码+lw+部署文档+讲解等)

课题介绍 本课题旨在设计并实现一套基于SpringBoot的智能医疗辅助系统&#xff0c;解决当前基层医疗中咨询响应滞后、健康档案管理零散、医疗知识普及不足、医护工作效率偏低等问题&#xff0c;适配基层医疗机构、社区卫生服务中心及家庭健康管理的智能辅助需求。系统以SpringB…

作者头像 李华
网站建设 2026/2/7 15:20:14

raft算法

raft算法学习视频

作者头像 李华