mysql优化取随机数据慢的方法

前天因为工作需要我把从一个5W记录的数据库中随机抽取几条记录了,这里我是直接使用mysql rand by函数来直接,几千条记录没关系,但如果到了几万条感觉要几秒,这个就很慢了,下面小编与大家一起来看看mysql 取随机数据慢优化过程。
MySQL很多时候需要获取随机数据,举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:


代码如下:

SELECT * FROM tablename ORDER BY RAND() LIMIT 1

但是,后来我查了一下MYSQL的官方手册,里面针对RAND()的提示大概意思就是,在ORDER BY从句里面不能使用RAND()函数,因为这样会导致数据列被多次扫描。但是在MYSQL 3.23版本中,仍然可以通过ORDER BY RAND()来实现随机。
 测试一下才发现这样效率非常低。一个15万余条的库,查询5条数据,居然要8秒以上。查看官方手册,也说rand()放在ORDER BY 子句中会被执行多次,自然效率及很低。
You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times.
搜索Google,网上基本上都是查询max(id) * rand()来随机获取数据。


代码如下:

SELECT *
FROM 'table' AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM 'table')) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id ASC LIMIT 5;

但是这样会产生连续的5条记录。解决办法只能是每次查询一条,查询5次。即便如此也值得,因为15万条的表,查询只需要0.01秒不到。
下面的语句采用的是JOIN,mysql的论坛上有人使用:


代码如下:

SELECT *
FROM 'table'
WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM 'table' )
ORDER BY id LIMIT 1;

我测试了一下,需要0.5秒,速度也不错,但是跟上面的语句还是有很大差距。总觉有什么地方不正常。
于是把语句改写了一下。


代码如下:

SELECT * FROM 'table'
WHERE id >= (SELECT floor(RAND() * (SELECT MAX(id) FROM 'table'))) 
ORDER BY id LIMIT 1;

这下,效率又提高了,查询时间只有0.01秒。
 最后,再把语句完善一下,加上MIN(id)的判断。我在最开始测试的时候,就是因为没有加上MIN(id)的判断,结果有一半的时间总是查询到表中的前面几行。
 完整查询语句是:
 

代码如下:

SELECT * FROM 'table' WHERE id >= (
SELECT floor(
RAND() * ((SELECT MAX(id) FROM 'table')-(SELECT MIN(id) FROM 'table'))
+ (SELECT MIN(id) FROM 'table')
)
) 
ORDER BY id LIMIT 1;

SELECT * FROM 'table' AS t1 JOIN (
SELECT ROUND(
# 最小值 + (1 至 最小与最大值差)
RAND() * (
(SELECT MAX(id) FROM 'table')-(SELECT MIN(id) FROM 'table')
)
+(SELECT MIN(id) FROM 'table')
) AS id
) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 1;

最后在php中对这两个语句进行分别查询10次,前者花费时间 0.147433 秒,后者花费时间 0.015130 秒。看来采用JOIN的语法比直接在WHERE中使用函数效率还要高很多。


代码如下:

SELECT *
FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `table`) – (SELECT MIN(id) FROM `table`)) + (SELECT MIN(id) FROM `table`)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 10;

这个就是我自己选用了,从以前5秒到现面0.0003秒时间都不用就查出10条记录了。

(0)

相关推荐

  • mysql 某字段插入随机数(插入随机数到MySQL数据库)

    常用的代码 UPDATE `表名` SET `字段名`=ceiling(rand()*500000+500000) WHERE (条件); update `表名` set click=click*0.01 where classid='2' and click>2000 我们经常会遇到使用随机的问题,下面就是一种解决随机数的方法. 在构造测试数据时,我们需要对测试表插入随机数据.构造测试数据的方法如下,仅以update为例说明 步骤1:随机数的SQL函数为rand() ,而rand()生成的是0

  • MySQL查询随机数据的4种方法和性能对比

    下面从以下四种方案分析各自的优缺点.方案一: 复制代码 代码如下: SELECT * FROM `table` ORDER BY RAND() LIMIT 0,1; 这种方法的问题就是非常慢.原因是因为MySQL会创建一张零时表来保存所有的结果集,然后给每个结果一个随机索引,然后再排序并返回.有几个方法可以让它快起来.基本思想就是先获取一个随机数,然后使用这个随机数来获取指定的行.由于所有的行都有一个唯一的id,我们将只取最小和最大id之间的随机数,然后获取id为这个数行.为了让这个方法当id不

  • MySQL的指定范围随机数函数rand()的使用技巧

    公式如下: rand() * (y-x) + x 咱们学php的都知道,随机函数rand或mt_rand,可以传入一个参数,产生0到参数之间的随机整数,也可以传入两个参数,产生这两个参数之间的随机整数. 而在mysql里,随机数函数rand不能传参,产生的0到1之间的浮点数,要是我们需要在mysql产生大于1的随机整数,该怎么办呢? 这样的需求并不陌生,例如,咱做的文章系统,需要作弊,给文章的浏览量随机加上某个范围内的整数. 现在,假设需要产生234到5678之间的随机整数,mysql下怎么实现

  • sqlserver、mysql获取连接字符串步骤

    步骤: 一.新建文本文档xxx.txt,修改文件类型为.udl 二.打开该文件,在<提供数据>中找到对应的服务. 三.在连接中选择需要的数据库,并填写相关信息. 四.测试连接,若成功则跳至下一步,失败则是用户信息有误,重新修改. 五.把xxx.udl后缀名改为txt,打开就可以找到连接字符串. 注:这里找到的连接字符串中有provider,可能不支持,如不支持,请改为server

  • 详解MySQL中concat函数的用法(连接字符串)

    MySQL中concat函数 使用方法: CONCAT(str1,str2,-) 返回结果为连接参数产生的字符串.如有任何一个参数为NULL ,则返回值为 NULL. 注意: 如果所有参数均为非二进制字符串,则结果为非二进制字符串. 如果自变量中含有任一二进制字符串,则结果为一个二进制字符串. 一个数字参数被转化为与之相等的二进制字符串格式:若要避免这种情况,可使用显式类型 cast, 例如: SELECT CONCAT(CAST(int_col AS CHAR), char_col) MySQ

  • MySQL产生随机数并连接字符串的方法示例

    本文实例讲述了MySQL产生随机数并连接字符串的方法.分享给大家供大家参考,具体如下: 用到的方法: concat('a','b','c'); 连接字符串 rand(); 产生随机数 floor(); 取整数 SQL语句示例: 复制代码 代码如下: UPDATE user set reg_ip= concat(floor(RAND() * 250),'.',floor(RAND() * 250),'.',floor(RAND() * 250),'.',floor(RAND() * 250)) w

  • mysql获取随机数据的方法

    1.order by rand()数据多了极慢,随机性非常好,适合非常小数据量的情况. 复制代码 代码如下: SELECT * FROM table_name AS r1 JOIN (SELECT (ROUND(RAND() * (SELECT ABS(MAX(id)-MIN(id)-$limit) FROM table_name))+(SELECT MIN(id) from table_name)) AS id) AS r2 WHERE r1.id >= r2.id ORDER BY r1.i

  • PHP 设置MySQL连接字符集的方法

    mysql_set_charset(). 这个函数是这样用的: mysql_set_charset('utf8', $link); 成功返回 TRUE,失败返回 FALSE. 就这么简单. 下面是PHP手册原文 This is the preferred way to change the charset. Using mysql_query() to execute SET NAMES .. is not recommended.

  • Python连接MySQL并使用fetchall()方法过滤特殊字符

    来一个简单的例子,看Python如何操作数据库,相比Java的JDBC来说,确实非常简单,省去了很多复杂的重复工作,只关心数据的获取与操作. 准备工作 需要有相应的环境和模块: Ubuntu 14.04 64bit Python 2.7.6 MySQLdb 注意:Ubuntu 自带安装了Python,但是要使用Python连接数据库,还需要安装MySQLdb模块,安装方法也很简单: sudo apt-get install MySQLdb 然后进入Python环境,import这个包,如果没有报

  • 从MySQL数据库表中取出随机数据的代码

    MySQL 如何从表中取出随机数据  以前在群里讨论过这个问题,比较的有意思.mysql的语法真好玩. 他们原来都想用PHP的实现随机,但取出多条好像要进行两次以上查询. 翻了手册,找到了下面这个语句,可以完成任务了 SELECT * FROM table_name ORDER BY rand() LIMIT 5; rand在手册里是这么说的: RAND()  RAND(N)  返回在范围0到1.0内的随机浮点值.如果一个整数参数N被指定,它被用作种子值.  mysql> select RAND

随机推荐