Carry の Blog Carry の Blog
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • Python
  • Shell
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carry の Blog

好记性不如烂键盘
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • Python
  • Shell
  • MySQL8-SOP手册
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL8-SOP

  • MySQL实战45讲学习笔记

    • MySQL45讲学习笔记
    • MySQL基础架构
    • MySQL日志系统 (Redo Log 与 Binlog)
    • MySQL字符串字段索引优化
    • MySQL索引原理与优化
    • MySQL锁机制详解
    • MySQL事务与MVCC机制
    • MySQL普通索引与唯一索引的选择
    • MySQL优化器如何选择索引
    • MySQL抖动刷脏页
    • 表空间管理与回收
    • count函数详解
    • 日志索引
    • orderby工作原理
    • 随机排序实现
      • 1. 随机排序基础概念
        • 1.1 随机排序的定义
        • 1.2 随机排序的使用场景
      • 2. ORDER BY RAND()实现机制
        • 2.1 RAND()函数工作原理
        • 2.2 RAND()函数的性能影响
      • 3. 随机排序优化策略
        • 3.1 采样优化
        • 3.2 索引优化
        • 3.3 分页随机排序优化
      • 4. 高效随机排序实现
        • 4.1 基于随机ID的实现
        • 4.2 基于UUID的随机排序
        • 4.3 基于时间戳的随机排序
      • 5. 随机排序的高级技巧
        • 5.1 随机权重排序
        • 5.2 分层随机排序
        • 5.3 多维度随机排序
      • 6. 随机排序性能监控
        • 6.1 性能指标监控
        • 6.2 查询执行计划分析
        • 6.3 性能测试脚本
      • 7. 随机排序最佳实践
        • 7.1 适用场景选择
        • 7.2 随机种子管理
        • 7.3 缓存机制
      • 8. 随机排序的注意事项
        • 8.1 内存使用考虑
        • 8.2 并发处理考虑
        • 8.3 数据一致性考虑
      • 9. 总结
    • SQL性能差异函数与转换
    • 慢查询分析锁与版本
    • 幻读与间隙锁
    • 加锁规则分析
    • 应急性能优化方法
    • 数据持久化保证
    • 主备一致性原理
    • 高可用架构与切换
    • 备库延迟分析与优化
    • 主备切换GTID
    • 读写分离实践与问题
    • 数据库健康检查
    • 锁与死锁
    • 数据误删恢复
    • Kill命令详解
    • 查询与内存使用分析
    • Join原理与选择
    • 临时表原理与应用
    • 内部临时表详解
    • Memory引擎详解
    • 自增ID详解
    • Insert加锁分析
    • 表复制方法比较
    • Grant与权限管理
    • 分区表详解
    • SQL语句中的Join问题
    • 自增ID用尽问题
  • 专题系列
  • MySQL实战45讲学习笔记
Carry の Blog
2024-07-27
目录

随机排序实现

# 随机排序实现

在数据库应用中,随机排序是一个常见但具有挑战性的需求。从简单的随机抽取到复杂的随机分布,实现方式多种多样。本文将深入探讨MySQL中随机排序的各种实现方法和优化策略。

# 1. 随机排序基础概念

# 1.1 随机排序的定义

随机排序是指在查询结果集中按照随机顺序返回数据的技术。在MySQL中,这通常通过ORDER BY RAND()实现:

-- 基本随机排序
SELECT * FROM users ORDER BY RAND();

-- 随机获取指定数量的记录
SELECT * FROM users ORDER BY RAND() LIMIT 10;

-- 随机获取特定条件的记录
SELECT * FROM products WHERE category = 'electronics' ORDER BY RAND() LIMIT 5;
1
2
3
4
5
6
7
8

# 1.2 随机排序的使用场景

-- 常见的随机排序使用场景:
-- 1. 随机推荐系统
-- 2. 随机抽样调查
-- 3. 游戏中的随机元素
-- 4. 营销活动中的随机展示
-- 5. 数据测试和验证

-- 示例:随机推荐
SELECT product_id, product_name, price 
FROM products 
WHERE category = 'books' 
ORDER BY RAND() 
LIMIT 10;

-- 示例:随机抽奖
SELECT user_id, user_name 
FROM participants 
ORDER BY RAND() 
LIMIT 1;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 2. ORDER BY RAND()实现机制

# 2.1 RAND()函数工作原理

-- RAND()函数的基本用法
SELECT RAND();           -- 返回0-1之间的随机浮点数
SELECT RAND(123);        -- 使用种子值生成可重现的随机数
SELECT RAND() * 100;     -- 生成0-100之间的随机数

-- ORDER BY RAND()的内部机制:
-- 1. 为每行生成随机数
-- 2. 按随机数排序
-- 3. 返回结果

-- 查看RAND()函数的执行过程
SELECT 
    id,
    name,
    RAND() as random_value
FROM users 
ORDER BY RAND() 
LIMIT 5;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 2.2 RAND()函数的性能影响

-- RAND()函数的性能特点:
-- 1. 对于大表,性能开销较大
-- 2. 需要为每一行计算随机数
-- 3. 可能需要临时表存储中间结果

-- 性能测试示例
SET @start_time = NOW();
SELECT * FROM large_table ORDER BY RAND();
SET @end_time = NOW();
SELECT TIMEDIFF(@end_time, @start_time) as execution_time;

-- 查看临时表使用情况
SHOW STATUS LIKE 'Created_tmp%';
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3. 随机排序优化策略

# 3.1 采样优化

-- 采样优化方法:
-- 1. 先采样再随机排序
-- 2. 减少需要排序的数据量

-- 优化前:全表随机排序
SELECT * FROM users ORDER BY RAND() LIMIT 10;

-- 优化后:先采样再随机排序
SELECT * FROM (
    SELECT * FROM users 
    ORDER BY RAND() 
    LIMIT 1000  -- 先采样1000条
) sampled 
ORDER BY RAND() 
LIMIT 10;     -- 再从中随机选10条
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3.2 索引优化

-- 利用索引优化随机排序:
-- 1. 使用覆盖索引
-- 2. 创建随机索引

-- 创建随机排序优化的索引
CREATE TABLE optimized_table (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    category VARCHAR(30),
    created_date DATE,
    INDEX idx_category (category),
    INDEX idx_random (id)  -- 用于随机访问
);

-- 优化随机排序查询
-- 通过ID随机访问实现随机排序
SELECT * FROM optimized_table 
WHERE id IN (
    SELECT id FROM optimized_table 
    ORDER BY RAND() 
    LIMIT 10
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 3.3 分页随机排序优化

-- 分页随机排序优化:
-- 1. 避免使用OFFSET进行分页
-- 2. 使用游标分页

-- 优化前:传统的OFFSET分页
SELECT * FROM users ORDER BY RAND() LIMIT 10 OFFSET 100;

-- 优化后:游标分页
SELECT * FROM users 
WHERE id > (
    SELECT id FROM users ORDER BY RAND() LIMIT 100, 1
) 
ORDER BY RAND() 
LIMIT 10;

-- 更好的方法:先获取随机ID再查询
SELECT * FROM users 
WHERE id IN (
    SELECT id FROM (
        SELECT id FROM users ORDER BY RAND() LIMIT 100, 10
    ) random_ids
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 4. 高效随机排序实现

# 4.1 基于随机ID的实现

-- 基于随机ID的高效随机排序
-- 1. 先获取随机ID集合
-- 2. 再查询这些ID对应的数据

-- 方法一:使用子查询
SELECT * FROM users 
WHERE id IN (
    SELECT id FROM users ORDER BY RAND() LIMIT 10
) 
ORDER BY FIELD(id, 
    (SELECT id FROM users ORDER BY RAND() LIMIT 10)
);

-- 方法二:使用临时表
CREATE TEMPORARY TABLE temp_random_ids AS
SELECT id FROM users ORDER BY RAND() LIMIT 10;

SELECT u.* FROM users u 
JOIN temp_random_ids t ON u.id = t.id
ORDER BY t.id;

DROP TEMPORARY TABLE temp_random_ids;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 4.2 基于UUID的随机排序

-- 使用UUID实现随机排序
-- 1. 为表添加UUID字段
-- 2. 使用UUID进行随机排序

-- 创建带UUID的表
CREATE TABLE uuid_table (
    id INT AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) DEFAULT (UUID()),
    name VARCHAR(50),
    INDEX idx_uuid (uuid)
);

-- 随机排序
SELECT * FROM uuid_table ORDER BY uuid LIMIT 10;

-- 或者使用UUID的哈希值
SELECT * FROM uuid_table 
ORDER BY CRC32(uuid) 
LIMIT 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 4.3 基于时间戳的随机排序

-- 基于时间戳的随机排序
-- 1. 利用时间戳的随机性
-- 2. 结合其他随机因素

-- 方法一:时间戳+随机数
SELECT * FROM users 
ORDER BY UNIX_TIMESTAMP(created_date) + RAND() 
LIMIT 10;

-- 方法二:使用MOD函数
SELECT * FROM users 
ORDER BY MOD(id, 1000000) + RAND() 
LIMIT 10;

-- 方法三:使用自定义随机函数
SELECT * FROM users 
ORDER BY (id * 1103515245 + 12345) % 2147483647 + RAND() 
LIMIT 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 5. 随机排序的高级技巧

# 5.1 随机权重排序

-- 基于权重的随机排序
-- 1. 为不同数据分配不同权重
-- 2. 根据权重进行随机选择

-- 创建权重表
CREATE TABLE weighted_items (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    weight INT DEFAULT 1  -- 权重值
);

-- 随机权重排序
SELECT * FROM weighted_items 
ORDER BY RAND() * weight 
LIMIT 10;

-- 或者使用更复杂的权重算法
SELECT * FROM weighted_items 
ORDER BY RAND() * (weight / (SELECT SUM(weight) FROM weighted_items)) 
LIMIT 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 5.2 分层随机排序

-- 分层随机排序
-- 1. 先按类别分组
-- 2. 在每个类别内随机排序

-- 示例:按类别随机选择
SELECT * FROM (
    SELECT * FROM products WHERE category = 'electronics' ORDER BY RAND() LIMIT 5
    UNION ALL
    SELECT * FROM products WHERE category = 'books' ORDER BY RAND() LIMIT 5
    UNION ALL
    SELECT * FROM products WHERE category = 'clothing' ORDER BY RAND() LIMIT 5
) combined 
ORDER BY RAND();
1
2
3
4
5
6
7
8
9
10
11
12
13

# 5.3 多维度随机排序

-- 多维度随机排序
-- 1. 结合多个字段进行随机排序
-- 2. 实现更复杂的随机分布

-- 方法一:多字段随机
SELECT * FROM users 
ORDER BY RAND() + (age * 0.01) + (score * 0.001) 
LIMIT 10;

-- 方法二:使用复杂表达式
SELECT * FROM products 
ORDER BY RAND() * (price * 0.01) + (rating * 0.1) 
LIMIT 10;

-- 方法三:基于业务逻辑的随机
SELECT * FROM orders 
ORDER BY RAND() * (DATEDIFF(NOW(), order_date) * 0.001) + (amount * 0.0001) 
LIMIT 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 6. 随机排序性能监控

# 6.1 性能指标监控

-- 监控随机排序性能指标
SELECT 
    VARIABLE_NAME,
    VARIABLE_VALUE
FROM information_schema.GLOBAL_STATUS 
WHERE VARIABLE_NAME LIKE '%Rand%';

-- 关键性能指标:
-- Handler_read_rnd_next: 随机读取次数
-- Handler_read_rnd: 随机读取记录次数
-- Created_tmp_tables: 创建的临时表数量
-- Created_tmp_disk_tables: 创建的磁盘临时表数量
1
2
3
4
5
6
7
8
9
10
11
12

# 6.2 查询执行计划分析

-- 分析随机排序查询的执行计划
EXPLAIN SELECT * FROM users ORDER BY RAND() LIMIT 10;

-- 查看执行计划中的关键信息
-- 1. Extra字段:是否使用了临时表
-- 2. Rows字段:扫描的行数
-- 3. Extra字段:是否使用了文件排序

-- 优化后的执行计划
EXPLAIN SELECT * FROM (
    SELECT * FROM users ORDER BY RAND() LIMIT 100
) sampled 
ORDER BY RAND() 
LIMIT 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 6.3 性能测试脚本

-- 创建随机排序性能测试脚本
DELIMITER //
CREATE PROCEDURE test_random_sort_performance()
BEGIN
    DECLARE start_time TIMESTAMP;
    DECLARE end_time TIMESTAMP;
    DECLARE execution_time DECIMAL(10,4);
    
    -- 测试全表随机排序
    SET start_time = NOW();
    SELECT * FROM large_table ORDER BY RAND() LIMIT 100;
    SET end_time = NOW();
    SET execution_time = TIMEDIFF(end_time, start_time);
    
    -- 记录测试结果
    INSERT INTO random_sort_performance (
        test_type,
        execution_time,
        timestamp
    ) VALUES (
        'Full Table Random Sort',
        execution_time,
        NOW()
    );
    
    -- 测试采样随机排序
    SET start_time = NOW();
    SELECT * FROM (
        SELECT * FROM large_table ORDER BY RAND() LIMIT 1000
    ) sampled 
    ORDER BY RAND() 
    LIMIT 100;
    SET end_time = NOW();
    SET execution_time = TIMEDIFF(end_time, start_time);
    
    -- 记录采样测试结果
    INSERT INTO random_sort_performance (
        test_type,
        execution_time,
        timestamp
    ) VALUES (
        'Sampled Random Sort',
        execution_time,
        NOW()
    );
END //
DELIMITER ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

# 7. 随机排序最佳实践

# 7.1 适用场景选择

-- 根据数据量选择随机排序方法:
-- 1. 小数据量(< 10000):直接使用ORDER BY RAND()
-- 2. 中等数据量(10000-1000000):使用采样方法
-- 3. 大数据量(> 1000000):使用基于ID的随机方法

-- 小数据量优化
SELECT * FROM small_table ORDER BY RAND() LIMIT 10;

-- 中等数据量优化
SELECT * FROM (
    SELECT * FROM medium_table ORDER BY RAND() LIMIT 1000
) sampled 
ORDER BY RAND() 
LIMIT 10;

-- 大数据量优化
SELECT * FROM large_table 
WHERE id IN (
    SELECT id FROM (
        SELECT id FROM large_table ORDER BY RAND() LIMIT 10000
    ) random_ids
) 
ORDER BY FIELD(id, 
    (SELECT id FROM large_table ORDER BY RAND() LIMIT 10000)
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 7.2 随机种子管理

-- 随机种子管理
-- 1. 使用固定的种子值实现可重现的随机
-- 2. 在需要时重置随机种子

-- 使用固定种子
SELECT * FROM users ORDER BY RAND(12345) LIMIT 10;

-- 生成可重现的随机序列
SELECT 
    id,
    name,
    RAND(12345) as random_value
FROM users 
ORDER BY RAND(12345) 
LIMIT 10;

-- 重置随机种子
SELECT * FROM users ORDER BY RAND() LIMIT 10;
-- 每次执行都会生成不同的随机序列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 7.3 缓存机制

-- 随机排序缓存机制
-- 1. 对于不经常变化的数据,可以缓存随机结果
-- 2. 定期更新缓存

-- 创建随机结果缓存表
CREATE TABLE random_cache (
    cache_key VARCHAR(100) PRIMARY KEY,
    cached_data TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    expires_at TIMESTAMP
);

-- 缓存随机结果
INSERT INTO random_cache (cache_key, cached_data, expires_at) 
VALUES (
    'random_products_20240101',
    (SELECT GROUP_CONCAT(CONCAT(id, ':', name) SEPARATOR '|') 
     FROM products ORDER BY RAND() LIMIT 100),
    DATE_ADD(NOW(), INTERVAL 1 HOUR)
);

-- 使用缓存结果
SELECT * FROM products 
WHERE id IN (
    SELECT CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(cached_data, '|', numbers.n), ':', -1) AS UNSIGNED) 
    FROM (SELECT 1 n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) numbers
    JOIN random_cache ON CHAR_LENGTH(cached_data) - CHAR_LENGTH(REPLACE(cached_data, '|', '')) >= numbers.n - 1
    WHERE cache_key = 'random_products_20240101'
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 8. 随机排序的注意事项

# 8.1 内存使用考虑

-- 内存使用优化:
-- 1. 监控临时表使用情况
-- 2. 控制返回结果集大小
-- 3. 考虑分批处理

-- 监控临时表使用
SHOW STATUS LIKE 'Created_tmp%';

-- 控制结果集大小
SELECT * FROM users ORDER BY RAND() LIMIT 1000;

-- 分批处理大结果集
SELECT * FROM users ORDER BY RAND() LIMIT 1000 OFFSET 0;
SELECT * FROM users ORDER BY RAND() LIMIT 1000 OFFSET 1000;
SELECT * FROM users ORDER BY RAND() LIMIT 1000 OFFSET 2000;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 8.2 并发处理考虑

-- 并发处理中的随机排序:
-- 1. 避免在高并发下使用全表随机排序
-- 2. 使用适当的锁机制
-- 3. 考虑读写分离

-- 高并发下的优化
-- 1. 使用索引优化
-- 2. 限制查询结果数量
-- 3. 使用缓存机制

-- 示例:并发安全的随机查询
SELECT * FROM users 
WHERE id IN (
    SELECT id FROM users ORDER BY RAND() LIMIT 100
) 
ORDER BY FIELD(id, 
    (SELECT id FROM users ORDER BY RAND() LIMIT 100)
)
LIMIT 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 8.3 数据一致性考虑

-- 数据一致性考虑:
-- 1. 随机排序可能影响数据一致性
-- 2. 在事务中使用随机排序需要特别注意
-- 3. 考虑使用快照读

-- 事务中的随机排序
BEGIN;
-- 使用一致性读
SELECT * FROM users ORDER BY RAND() LIMIT 10;
COMMIT;

-- 或者使用指定事务隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT * FROM users ORDER BY RAND() LIMIT 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 9. 总结

随机排序在数据库应用中具有重要价值,但同时也带来了性能挑战。通过理解不同实现方法的特点和适用场景,可以有效优化随机排序的性能。

关键优化要点包括:

  1. 选择合适的实现方法:根据数据量和业务需求选择最适合的随机排序方式
  2. 性能监控与分析:持续监控随机排序的性能指标,及时发现问题
  3. 缓存机制应用:对不经常变化的数据使用缓存机制
  4. 内存资源管理:合理控制临时表使用和结果集大小
  5. 并发安全考虑:在高并发环境下注意随机排序的并发处理

通过系统性的优化和监控,可以实现高效、稳定的随机排序功能,为业务应用提供良好的数据随机化支持。

#MySQL#随机排序#查询优化#数据随机化
上次更新: 3/4/2026

← orderby工作原理 SQL性能差异函数与转换→

最近更新
01
表空间管理与回收
03-04
02
MySQL抖动刷脏页
03-04
03
count函数详解
03-04
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式