news 2026/5/15 21:56:57

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/5/10 7:07:25

AI原生应用领域思维树的创新模式探讨

AI原生应用领域思维树的创新模式探讨 关键词&#xff1a;AI原生应用、思维树&#xff08;Tree of Thoughts, ToT&#xff09;、大语言模型&#xff08;LLM&#xff09;、多步推理、生成式AI 摘要&#xff1a;随着生成式AI技术的爆发&#xff0c;“AI原生应用”&#xff08;AI-N…

作者头像 李华
网站建设 2026/5/10 3:43:52

游戏在 HarmonyOS 上如何“活”?

子玥酱 &#xff08;掘金 / 知乎 / CSDN / 简书 同名&#xff09; 大家好&#xff0c;我是 子玥酱&#xff0c;一名长期深耕在一线的前端程序媛 &#x1f469;‍&#x1f4bb;。曾就职于多家知名互联网大厂&#xff0c;目前在某国企负责前端软件研发相关工作&#xff0c;主要聚…

作者头像 李华
网站建设 2026/5/12 7:14:01

基于multisim的可控直流稳压电源的设计与仿真

具体参数要求:输入电压:220V:输出电压:1.25-15V可调直流电压;输出电流:最大电流为1.5A:保护电路:过流保护、短路保护。 仿真图&#xff1a; 仿真演示与文件下载&#xff1a;基于multisim的可控直流稳压电源的设计与仿真演示视频_哔哩哔哩_bilibili

作者头像 李华
网站建设 2026/5/12 9:12:46

数据可视化高级技巧:Matplotlib + Seaborn实战大全

目录 摘要 1 引言&#xff1a;为什么数据可视化是数据科学的"最后一公里" 1.1 数据可视化的核心价值定位 1.2 数据可视化技术演进路线 2 Matplotlib与Seaborn架构深度解析 2.1 可视化架构设计理念 2.1.1 Matplotlib对象层级架构 2.1.2 Matplotlib架构图 2.2…

作者头像 李华
网站建设 2026/5/10 8:18:09

WebSocket+cpolar让实时通信不卡顿随时随地可用

WebSocket 作为基于 TCP 协议的双向通信技术&#xff0c;核心功能是实现客户端与服务器的全双工实时数据传输&#xff0c;无需反复建立连接&#xff0c;数据传输延迟低、轻量化&#xff0c;适配 Windows、macOS、Linux 等多操作系统&#xff0c;还能嵌入物联网设备&#xff0c;…

作者头像 李华