news 2026/4/28 10:10:01

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/4/23 12:31:13

基于Springboot+Vue的乡镇卫生所医用物资进销存系统源码文档部署文档代码讲解等

课题介绍 本课题旨在设计并实现一套基于SpringBootVue的乡镇卫生所医用物资进销存系统&#xff0c;解决当前乡镇卫生所医用物资采购无序、库存管控混乱、出入库登记繁琐、物资过期预警不足等问题&#xff0c;适配乡镇卫生所医用物资精细化管理的核心需求。系统采用前后端分离架…

作者头像 李华
网站建设 2026/4/18 2:05:34

MAVLink 通信协议 C++ 开发实战:从环境搭建到飞控通信全解析

前言 MAVLink&#xff08;Micro Air Vehicle Link&#xff09;是一款轻量级、低带宽、高可靠性的微小型无人机通信协议&#xff0c;由 PX4 团队主导设计&#xff0c;广泛应用于无人机、无人车、机器人等嵌入式系统的跨设备通信场景。其核心优势在于专为资源受限的硬件&#xf…

作者头像 李华
网站建设 2026/4/24 5:53:36

告别传统RAG的痛点!Agent Skills让知识库检索更智能(本地知识库搭建新思路:用Agent Skills实现渐进式检索)

文章目录 📖 介绍 📖 🏡 演示环境 🏡 📒 Agent Skills在知识库检索中的实践探索 📒 📝 传统RAG的局限性 📝 Agent Skills的核心设计理念 🎯 分层索引导航 🎯 先学习,再处理 🎯 渐进式检索 📝 实际应用场景对比 场景一:查询AI行业趋势 场景二:分析电…

作者头像 李华
网站建设 2026/4/23 16:47:59

基于multisim的波形发生与变换电路设计

设计正弦波振荡电路&#xff0c;要求产生1KHz的正弦波&#xff0c;并将1KHz的正弦波转换成1kHz的方波和三角波。 仿真图&#xff1a; 仿真演示与文件下载&#xff1a;基于multisim的波形发生与变换电路设计演示视频_哔哩哔哩_bilibili

作者头像 李华
网站建设 2026/4/18 1:59:41

淘宝评论数据采集 API 全解析【淘宝评论API】

一、官方 API 方案 1.1 核心接口概览 淘宝开放平台 (TOP) 提供的官方评论数据接口主要有以下 3 个&#xff0c;权限申请门槛较高&#xff0c;仅对企业 / 店铺商家开放&#xff0c;个人开发者无法申请&#xff1a; 接口名称功能描述适用场景taobao.item.review.get获取淘宝商…

作者头像 李华
网站建设 2026/4/19 19:47:36

打卡信奥刷题(2789)用C++实现信奥题 P3939 数颜色

P3939 数颜色 题目背景 大样例可在页面底部「附件」中下载。 题目描述 小 C 的兔子不是雪白的&#xff0c;而是五彩缤纷的。每只兔子都有一种颜色&#xff0c;不同的兔子可能有相同的颜色。小 C 把她标号从 1 到 nnn 的 nnn 只兔子排成长长的一排&#xff0c;来给他们喂胡萝…

作者头像 李华