随机结果分页

时间:2010-06-07 17:50:43

标签: php html

我目前有一个包含随机生成的订单列表的数据列表。现在没有分页,因此我很容易生成一个随机排序的列表。随着我的数据列表的增长,由于所有数据,它会变慢,因此明显的解决方案是分页。我的分页问题是每次页面加载时我都不能随机生成订单,所以我和我的经理得出结论,列表必须提前预先生成并重新生成每x个时间。现在的问题是我们如何存储这个生成的列表?我们提出了四种选择:

  1. 会话(占用服务器上的ram)
  2. Cookies(传输更多数据。考虑传输给用户的数千个整数值)
  3. 平面文件(实施可能需要一些时间。不是极端数量,但比其余时间稍长)
  4. 数据库(一个cron作业将运行x次,并对所有记录进行大量更新。我们担心如果数据太多,如果人们在更新期间点击服务器,可能会降低系统速度。)
  5. 如果有任何其他解决方案似乎比预先生成的基于时间的列表更好,我很乐意听到它们。

    感谢。

    更新:我真的喜欢的答案,但由于某种原因被删除,是有人提到使用SEED,然后我可以存储种子而不是id列表,这会减少我的数据存储并简化一切。我刚刚测试了解决方案,它几乎完美无缺。唯一的问题是,当我使用LIMIT时,一切都会搞砸。有没有人对此提出建议?我不想每次都生成所有数据,我只想使用LIMIT * ,.如果我将它与种子一起使用,那么数字总是会重置,就像它应该的那样。

    希望这是有道理的。当我思考它时,它更有意义,而不是它的结果。

6 个答案:

答案 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.,