mysql order by rand优化
今天来讲讲这个mysql常用的order by rand用法。我们经常会遇见一个需求,那就是随机从数据库中抽取几条数据显示在右边栏,或则显示在其它地方,那么常用的方法就是:
SELECT * FROM tablename ORDER BY RAND() LIMIT 1; 但是随着数据量的增加,这个语句会变得越来越慢。
举例:我这里有一个news的表,如下:
mysql> select count(*) from news;
+———-+
| count(*) |
+———-+
| 16338 |
+———-+
1 row in set (0.00 sec)
执行SQL: select from ·`news` order by rand() limit 1; 结果:1 row in set (13.97 sec) ,执行时间长达14秒左右,这对于一个网站来说是无法接受的。
这时候网上百度,google一搜就能搜到替代方案,如:
执行sql: SELECT *
FROM `news` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `news`)-(SELECT MIN(id) FROM `news`))+(SELECT MIN(id) FROM `news`)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 1;
结果: 1 row in set (0.02 sec),这个差距实在是太大了。很多时候到这里我们以为就结束了,其实并不然,这只是简单的抽取表中的随机数据,并没有任何的过滤条件,有人说,很简单嘛,我们就在where后面加条件就行了,例如:
SELECT *
FROM `news` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `news`)-(SELECT MIN(id) FROM `news`))+(SELECT MIN(id) FROM `news`)) AS id) AS t2
WHERE t1.id >= t2.id AND category_id = 2
ORDER BY t1.id LIMIT 1;
其实这里是有一个误区的,如果我们只在最后的where里面加过滤条件有可能是查询不到足够的数据的(对于多条数据抽取),因为这个最大值和最小值中间的差并不是满足条件的数据总和,因为这会导致t2.id的值比较大,就算我们在子查询select minx和select max后面加上where的新条件也是一样的,例如
SELECT *
FROM `news` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `news` WHERE category_id = 2)-(SELECT MIN(id) FROM `news` WHERE category_id = 2))+(SELECT MIN(id) FROM `news` WHERE category_id = 2)) AS id) AS t2
WHERE t1.id >= t2.id AND category_id = 2
ORDER BY t1.id LIMIT 1; 执行时间: 1 row in set (0.04 sec)
当limit的值比较大时,很容易就取不到数据,这时候我们就需要考虑新的办法了。既然最大值与最小值之的差不是满足条件的数据总和,那我们是不是可以考虑直接用这个数据总和值来作为这个条件了,答案是肯定的,而且更能取得足够合适的数据,sql如下:
SELECT *
FROM `news` AS t1 JOIN (SELECT ROUND(RAND() * (SELECT COUNT(*) FROM `news` WHERE category_id = 2)+(SELECT MIN(id) FROM `news` WHERE category_id = 2)) AS id) AS t2
WHERE t1.id >= t2.id AND category_id = 2
ORDER BY t1.id LIMIT 1; 执行时间: 1 row in set (0.02 sec),
由此可见,新的方法不仅速度快,而且数据更真实, 不信你可以试试看。
- 高性能网络编程7--tcp连接的内存使用
- Android 平台 Native 代码的崩溃捕获机制及实现
- go语言变参,匿名函数的多种用法
- 问题帖子--Concurrent Read/Write Map
- Android 混淆那些事儿
- H5 直播避坑指南
- H5 和移动端 WebView 缓存机制解析与实战
- 根据IE版本加载不同CSS样式的方法小结,解决低版本IE兼容问题
- Linux下用dd命令测试硬盘的读写速度
- 教你 Debug 的正确姿势——记一次 CoreMotion 的 Crash
- Linux系统yum命令安装软件时保留(下载)rpm包
- Go语言读写数据库
- 《Android 创建线程源码与OOM分析》
- 微信 Android 视频编码爬过的那些坑
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- 旷视科技|商用端侧Raw图像降噪方案
- Python | 时间戳转换
- Stata | 2020年国家社科基金立项名单分析
- 还在用Guava Cache?它才是Java本地缓存之王
- 死信队列的消息处理方案
- 【Ceph】Rook 中使用 External Cluster 的方式管理外部集群
- Redis排行榜的设计与实现
- 血的教训 | 一次订单号重复的事故差点被开除
- 60分钟看懂HMM的基本原理
- R语言确实会蛮耗费磁盘空间哦
- 很多时候你就是不知道如何提问
- seurat标准流程实例之2个10x样本的项目(GSE135927数据集)
- 使用 Jenkins 和 Ansible 实现 CI/CD
- 太刺激了,面试官让我手写跳表,而我用两种实现方式吊打了TA!
- 被 Google 选择的下一代数据面 Cilium 是什么 - 上手实践