我目前有一个包含随机生成的订单列表的数据列表。现在没有分页,因此我很容易生成一个随机排序的列表。随着我的数据列表的增长,由于所有数据,它会变慢,因此明显的解决方案是分页。我的分页问题是每次页面加载时我都不能随机生成订单,所以我和我的经理得出结论,列表必须提前预先生成并重新生成每x个时间。现在的问题是我们如何存储这个生成的列表?我们提出了四种选择:
如果有任何其他解决方案似乎比预先生成的基于时间的列表更好,我很乐意听到它们。
感谢。
更新:我真的喜欢的答案,但由于某种原因被删除,是有人提到使用SEED,然后我可以存储种子而不是id列表,这会减少我的数据存储并简化一切。我刚刚测试了解决方案,它几乎完美无缺。唯一的问题是,当我使用LIMIT时,一切都会搞砸。有没有人对此提出建议?我不想每次都生成所有数据,我只想使用LIMIT * ,.如果我将它与种子一起使用,那么数字总是会重置,就像它应该的那样。
希望这是有道理的。当我思考它时,它更有意义,而不是它的结果。
答案 0 :(得分:4)
Mysql RAND()接受种子作为可选参数。使用种子,每次都会返回相同的随机化结果集。
您可以做的是在第一页请求中使用PHP生成随机种子,并使用查询字符串将其传递给每个页面。
编辑:对不起,我没有意识到该解决方案已经发布但已被删除。
答案 1 :(得分:0)
使用#4,可能只按应检索的顺序存储要检索的数据的ID。
更好的是,如果可能(因为这类似于缩放问题)是预先生成每个页面的数据。例如,如果仅通过浏览器查看,则只需预先生成x个静态页面HTML(或仅表格/列表部分)。
我知道如果没有进一步的解释,这可能听起来很荒谬,但想想其中一个选项。
此外,如果服务器在生成结果期间受到重创,则需要将其与Web服务器分开,并且可能在原始数据库的克隆/复制从属服务器上运行报告/生成。
答案 2 :(得分:0)
使用子选择。这样你仍然可以使用RAND()
- 技巧,但是OFFSET不会搞砸你。
select * from (select * from items order by rand(3) asc) as b limit 5 offset @x;
备用提示:升级MySQL。这是一个老虫。
示例:
mysql> select * from (select id from items order by rand(3) asc) as b limit 5 offset 1;
+-------+
| id |
+-------+
| 24621 |
| 25214 |
| 27119 |
| 24672 |
| 25585 |
+-------+
5 rows in set (0.01 sec)
mysql> select * from (select id from items order by rand(3) asc) as b limit 5 offset 2;
+-------+
| id |
+-------+
| 25214 |
| 27119 |
| 24672 |
| 25585 |
| 27718 |
+-------+
5 rows in set (0.01 sec)
mysql> select * from (select id from items order by rand(3) asc) as b limit 5 offset 3;
+-------+
| id |
+-------+
| 27119 |
| 24672 |
| 25585 |
| 27718 |
| 25457 |
+-------+
5 rows in set (0.00 sec)
mysql> select * from (select id from items order by rand(3) asc) as b limit 5 offset 4;
+-------+
| id |
+-------+
| 24672 |
| 25585 |
| 27718 |
| 25457 |
| 27112 |
+-------+
5 rows in set (0.01 sec)
mysql> select * from (select id from items order by rand(3) asc) as b limit 5 offset 5;
+-------+
| id |
+-------+
| 25585 |
| 27718 |
| 25457 |
| 27112 |
| 24779 |
+-------+
5 rows in set (0.02 sec)
答案 3 :(得分:0)
我更喜欢随机文件,看看这类缓存来自opencart:
<?php
final class Cache {
private $expire = 3600;
public function __construct() {
$files = glob(DIR_CACHE . 'cache.*');
if ($files) {
foreach ($files as $file) {
$time = substr(strrchr($file, '.'), 1);
if ($time < time()) { unlink($file); }
}
}
}
public function get($key) {
$files = glob(DIR_CACHE . 'cache.' . $key . '.*');
if ($files) {
foreach ($files as $file) {
$handle = fopen($file, 'r');
$cache = fread($handle, filesize($file));
fclose($handle);
return unserialize($cache);
}
}
}
public function set($key, $value) {
$this->delete($key);
$file = DIR_CACHE . 'cache.' . $key . '.' . (time() + $this->expire);
$handle = fopen($file, 'w');
fwrite($handle, serialize($value));
fclose($handle);
}
public function delete($key) {
$files = glob(DIR_CACHE . 'cache.' . $key . '.*');
if ($files) {
foreach ($files as $file) {
unlink($file);
}
}
}
}
?>
使用非常简单,效果很好,您使用随机查询并将数据保存到文件中,我发布了一个示例。
$cache = new cache();
$data = $cache->get('my_query_key');
if (!$data) {
// I do my query and I put it into an array (because I can use shuffle :P)
$result = mysql_query('SELECT * FROM items');
$data = array();
while($row = mysql_fetch_assoc($result)) { $data[] = $row; }
$cache->set('my_query_key', $data);
}
shuffle($data);
保存超过100kb的文件时唯一存在问题,但作为谣言,我使用它并且工作得很好从来没有让我没问题。啊......在这种情况下,不需要在查询中使用RAND()。 :P
我写这篇文章时没有检查sintax,是洁具^^
答案 4 :(得分:0)
通过使用以下逻辑,您可以为每个单独的访问者(使用他/她的IP)“弄乱”您的数据,并保持您的分页结果以获得大量的导航时间......
//generate individual seed...
$ip=$_SERVER['REMOTE_ADDR'];
$hour=date("H");
$day=date("j");
$month=date("n");
$ip=str_replace(".","",$ip);
$seed=($ip+$hour+$day+$month);
//query
$query="SELECT * FROM my_table ORDER BY RAND($seed) LIMIT $amount OFFSET $offset";
专业人士:快速简便,无需额外负载,无需cron,每位访客具有独特的随机性。
缺点:如果在导航过程中小时(更多),日期或月份发生变化,数据会重新消失。
答案 5 :(得分:0)
Here's my working solution based on Kevin's answer:
public function galleries(){
if (!Input::has('page')){ //it means we are on the first page
$seed = rand(1, 10); //generate a random number between 1 and 10
Session::put('seed', $seed); //then pass it to session named 'seed'
}else{
if (Input::get('page') == 1){ //this also indicate the first page, because page = 1
$seed = rand(1, 10);
Session::put('seed', $seed);
}
}
$orgs = Organization::orderByRaw("RAND(".Session::get('seed').")")->paginate(4); //put the seed value to RAND(), this way, the second page will generate random row with same seed as the first page
return redirect('galleries')->with('orgs', $orgs);
}
}
Cheers.
Edit : this is a laravel project based, but you get the idea.,