<p>SQL Server中NEWID()可实现行级随机,因每次调用生成新GUID;常用ORDER BY NEWID()随机排序或抽样,如SELECT TOP 10 * FROM users ORDER BY NEWID();亦可用CHECKSUM(NEWID())生成随机数值插入测试数据。</p>

SQL Server 用 NEWID() 生成随机排序或随机抽样
SQL Server 没有原生的 RAND() 行级随机函数——直接写 SELECT RAND() FROM table 会返回同一个值,因为 RAND() 在查询执行时只计算一次。真正能按行触发随机行为的是 NEWID(),它每次调用都生成新 GUID,可用于隐式排序。
常见用法是配合 ORDER BY NEWID() 实现随机取数:
SELECT TOP 10 * FROM users ORDER BY NEWID();
插入随机测试数据时,可结合 INSERT INTO ... SELECT 构造多行:
INSERT INTO test_data (id, name, score)
SELECT ABS(CHECKSUM(NEWID())) % 1000,
'user_' + CAST(ABS(CHECKSUM(NEWID())) % 10000 AS VARCHAR),
ABS(CHECKSUM(NEWID())) % 101
FROM sys.objects o1, sys.objects o2
WHERE o1.object_id < 100 AND o2.object_id < 100;-
CHECKSUM(NEWID())是常用技巧,把 GUID 转成整数再取模,避免字符串拼接开销 -
sys.objects仅作行源,不关心实际内容;交叉连接(逗号语法)快速生成笛卡尔积,控制数量靠WHERE限制 - 不要用
TOP N加子查询来“控制条数”,容易因优化器提前截断导致实际插入不足
MySQL / PostgreSQL 用 RAND() 插入带分布的测试数据
MySQL 的 RAND() 支持行级计算,PostgreSQL 则需用 random()(注意大小写)。两者都能在 INSERT ... SELECT 中直接参与表达式运算。
例如 MySQL 批量插入 100 条带随机姓名、年龄、状态的数据:
INSERT INTO users (name, age, status)
SELECT
CONCAT('test_', FLOOR(RAND() * 1000)),
FLOOR(18 + RAND() * 60),
ELT(FLOOR(1 + RAND() * 3), 'active', 'inactive', 'pending')
FROM information_schema.columns
LIMIT 100;-
FLOOR(RAND() * N)是整数范围随机的核心模式,RAND()返回 [0,1) 浮点,乘法后向下取整得 [0,N-1] - MySQL 的
information_schema.columns表通常行数充足,比建临时表更轻量;PostgreSQL 可改用generate_series(1,100) - PostgreSQL 注意:
random()不是函数名RAND(),写错会报function rand() does not exist
用 RAND(seed) 复现相同随机序列(调试必需)
当需要反复验证插入逻辑是否稳定(比如 ETL 测试),固定种子能让每次运行生成完全一致的伪随机数。MySQL 和 SQL Server 都支持种子参数,但行为不同。
MySQL 中 RAND(N) 设置种子后,本次会话内后续 RAND() 全部复用该序列:
SET @seed = UNIX_TIMESTAMP(); SELECT RAND(@seed), RAND(), RAND(); -- 三次结果固定
而 SQL Server 的 RAND(@seed) 仅影响**下一次调用**,之后又回到默认行为,无法全局锁定:
SELECT RAND(123), RAND(), RAND(); -- 第一个是固定值,后两个仍是任意值
- 若需 SQL Server 完全可控,改用
CRYPT_GEN_RANDOM(4)+ 自定义映射,或干脆在应用层生成再批量 INSERT - 别在生产环境用固定种子做“假随机”,容易被误认为真随机,引发数据倾斜问题
- PostgreSQL 的
setseed()是会话级生效,调用一次即可,比 SQL Server 更可靠
性能陷阱:避免在大表上用 ORDER BY NEWID() 或高频 RAND()
对百万级以上表执行 ORDER BY NEWID(),SQL Server 会为每行计算 GUID 并全内存排序,极易触发 TempDB 压力和超时。同理,MySQL 在大结果集里频繁调用 RAND() 也会显著拖慢执行速度。
- 替代方案:先用主键范围估算,
WHERE id BETWEEN ? AND ?随机选区间,再用LIMIT抽样 - INSERT 场景下,优先构造内存内 VALUES 列表(如 MySQL 8.0+ 支持
VALUES ROW(), ROW()...),而非依赖子查询实时计算 - 如果只是填充空表测索引/统计信息,用
GO 1000循环 + 单条 INSERT 比一次性插十万条更稳,尤其在日志空间受限时
随机性只是手段,不是目的;真正关键的是让测试数据覆盖边界条件、符合字段约束、且插入过程不破坏事务一致性。别为了“看起来随机”而忽略 NOT NULL、CHECK、外键这些硬规则。

















