ZBlogger技术交流中心

 找回密码
 注册

QQ登录

只需一步,快速开始

Z-BlogPHP 最新开发动态 下载最新版:Z-BlogPHP 1.5 Zero Wordpress转换 - Emlog转换 - 找回密码

Z-BlogASP 最新开发动态 下载最新版:Z-Blog 2.2 Prism Build 140101 转换到Z-BlogPHP - 1.8升级指南 - 找回密码

DBS官方主机/域名/VPS 推荐:Z-BlogPHP主机-Z-BlogASP主机 联系值班客服(每天9:00-21:30)

搜索
【聚划算】宅男最新神器!你懂的!环球外贸论坛
查看: 2370|回复: 8

关于全面禁止直接在数据库内使用rand()进行随机读取的公告

[复制链接]
发表于 2015-10-6 21:21:35 | 显示全部楼层 |阅读模式
很多开发者喜欢用类似以下的代码来取得随机文章:
  1. $array = $zbp->GetArticleList(array('*'),$where,array('rand()'=>' '),array($numm),'');
复制代码
这样做有以下问题:
1. 不支持MySQL之外的数据库;
2. 数据量上万即奇慢无比。

所以,除非特殊情况,我们今后不再允许代码含直接在数据库内rand()的应用通过审核。当然,不包含在PHP里用rand()或mt_rand()函数,也不包含Math.random()。

为什么会慢?
我这里尝试用非计算机专业术语来解释。
我们把一本书比作数据库。一般的数据库查询,比如查一条ID为1的记录,一般会直接根据索引来得到结果。索引的用途,相当于一本书的目录。直接查目录得到结果,自然会比一页一页翻来得快。
然而,ORDER BY RAND()呢?它会先给你这本书的每一页都随机写一个数字,这就要翻过每一页了。接着,再排序比大小,把每一页的数字都排序排一遍,这就又要把书翻一遍。再取出数字最小的那几条记录。所以,这就是慢的原因。(当然,MySQL的内部实现我没看过,这两个任务不一定是互相独立的。)
如果要比较专业解释的话,请参看MySQL的官方文档:

https://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand
You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times. However, you can retrieve rows in random order like this:

mysql> SELECT * FROM tbl_name ORDER BY RAND();
ORDER BY RAND() combined with LIMIT is useful for selecting a random sample from a set of rows:

mysql> SELECT * FROM table1, table2 WHERE a=b AND c<d -> ORDER BY RAND() LIMIT 1000;
RAND() is not meant to be a perfect random generator. It is a fast way to generate random numbers on demand that is portable between platforms for the same MySQL version.

如何解决?
非对数据库有一定研究的开发者,请直接去除随机文章功能。
否则,请参考以下链接对你的程序进行优化。另外,请务必确保你的代码对SQLite等数据库有效,或干脆对这些数据库不提供相关功能。
在 MySQL 中,从 10 万条主键不连续的数据里随机取 3000 条,如何做到高效?

MySQL select 10 random rows from 600K rows fast


其它:我的测试数据库是六十万,大小3.1GB。



回复

使用道具 举报

发表于 2015-10-6 21:24:12 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2015-10-6 21:30:04 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2015-10-7 19:05:23 | 显示全部楼层
支持楼主,好贴!
回复 支持 反对

使用道具 举报

发表于 2015-10-8 15:36:02 | 显示全部楼层
支持!!!!
回复 支持 反对

使用道具 举报

发表于 2015-10-14 19:42:58 | 显示全部楼层
本帖最后由 peakhour 于 2015-10-15 15:53 编辑

微软有篇技术文章有写:
https://msdn.microsoft.com/zh-tw/library/cc441928.aspx用BINARY_CHECKSUM的方法,如下例子。
  1.   SELECT * FROM Table1
  2.   WHERE (ABS(CAST(
  3.   (BINARY_CHECKSUM(*) *
  4.   RAND()) as int)) % 100) < 10
复制代码

我把它改写成适合我们zBlog的例子,如下:

  1. SELECT top 10 * FROM blog_Article
  2. WHERE [log_Level]=4 AND [log_Type]=0
  3. AND   (ABS(CAST(
  4.   (BINARY_CHECKSUM
  5.   ([log_ID], NEWID())) as int))
  6.   % 2) =1
复制代码

效能差别甚钜。


2015/10/15更正:以上算法还是分配不均匀,还不如用这个:

  1. SELECT  TOP 10 * FROM [blog_Article]  TABLESAMPLE (0.1 percent)
  2. WHERE [log_Level]=4 AND [log_Type]=0
  3. ORDER BY NEWID()
复制代码



回复 支持 反对

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies |上传

本版积分规则

Archiver|手机版|ZBlogger技术交流中心 ( 鄂ICP备11007414号 鄂公网安备 42060602000101号 )

GMT+8, 2019-1-18 05:29 , Processed in 0.034799 second(s), 5 queries , APCu On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表