一般的来说,开发者获取随机文章最简单的方式就是使用 order by RAND(),然而这种方式在数据量稍大的时候可能产生数百毫秒的延迟。关于 mysql RAND() 的性能分析,网上已经很有多的文章了,本文不再赘述。大概意思就是,在ORDER BY从句里面不建议使用RAND()函数,因为这样会导致数据列被多次扫描。
以下直接给出优化后的获取随机文章的代码,能够极大的减少数据库查询时间。
typecho 版本:
$db = Typecho_Db::get();
$prefix = $db->getPrefix();
$adapterName = $db->getAdapterName();//兼容非MySQL数据库
if ($adapterName == 'pgsql' || $adapterName == 'Pdo_Pgsql' || $adapterName == 'Pdo_SQLite' || $adapterName == 'SQLite') {
$order_by = 'RANDOM()';
$user_former = false;
} else {
$order_by = 'RAND()';
$user_former = true;
}
// 使用原生sql
if($user_former){
$sql = "SELECT * FROM `{$prefix}contents` WHERE cid >= (SELECT floor( RAND() * ((SELECT MAX(cid) FROM `{$prefix}contents`)-(SELECT MIN(cid) FROM `{$prefix}contents`)) + (SELECT MIN(cid) FROM `{$prefix}contents`))) and type='post'
and status='publish' and (password is NULL or password='') ORDER BY cid LIMIT {$random};";
$result = $db->query($sql);
}else{
$sql = $db->select()->from('table.contents')
->where('status = ?', 'publish')
->where('table.contents.created <= ?', time())
->where('type = ?', 'post')
->limit($random)
->order($order_by);
$result = $db->fetchAll($sql);
}
假设数据库的主键为 cid。 比如最小的文章cid是1,最大的文章cid是10,那就从1到10之间选一个随机数,比如5,然后假设我们要取一篇文章,那么就是从 1 + 5 到 10 之间取。一定程度上降低了数据量。
但是怎么看都是薛定谔的处理方法,但总归比原来性能好了。 ::(超赞)