【问题标题】:Yii: Select 20 last entries order by id ASCYii:选择 20 个最后的条目 order by id ASC
【发布时间】:2012-10-08 03:55:01
【问题描述】:

我想获取表格的最后 20 个条目,但按 id 升序排列。

在 Sql 中不是很复杂:

SELECT * 
FROM (SELECT * FROM comments
      WHERE postID='$id' 
      ORDER BY id DESC 
      LIMIT 20) t
ORDER BY id ASC;

但我想用我的 yii 模型来做:

Comment::model()->findAll($criteria)

但我真的不知道我应该在 CDbCriteria 中添加什么内容!

【问题讨论】:

  • 是的,我很了解 Yii,但我不知道如何以 cactiverecord 的方式制定 sql 请求。我无法制定的主要问题是 frome 子句是一个请求,我真的不知道如何将它放在 CActiveRecord 样式中。我不是唯一一个遇到这个问题的人,直到现在没有人成功回答:yiiframework.com/forum/index.php/topic/…
  • 我再次阅读了文档,但没有找到对我有帮助的东西!我现在看到的唯一东西是:$criteria = new CDbCriteria(); $标准->限制= 20; $criteria->order = 'id DESC'; $models = array_reverse(评论::model()->finAll($criteria));但我想避免使用 array_reverse()
  • $criteria->order = 'id ASC' 有什么问题; ?
  • 使用 $criteria->order = 'id ASC';我将获得 cmets 表中的前 20 个条目。我想要最后 20 个,但按升序排列!

标签: php mysql sql activerecord yii


【解决方案1】:
$models = Comment::model()->findAll(array(
    "condition" => "WHERE postID = '".$id."'",
    "order" => "id DESC",
    "limit" => 20,
));

将获得最后 20 个。现在您想订购由 id ASC 设置的记录,对吗?是否没有其他字段可以为类似结果排序(可能是日期或创建字段?)例如:

"order" => "id DESC, created ASC"

放弃二级排序,但为什么不直接使用数组反转呢?

$models = array_reverse($models);

【讨论】:

  • 我认为在“id DESC,created ASC”中,“created ASC”将仅用于具有相同 id 的条目。我们应该将其解读为:我们按 id DESC 排序,然后如果它们具有相同的按创建的 ASC
  • id 属性不是你的主键吗?为什么 2 条记录的 id 相同?
  • 对不起,我的错,误读了您的回复。是的,你是对的。为什么你不想使用 array_reverse?
  • 我想我最终会这样做!因为表演没被发现,不过只有20篇应该没那么差吧!
  • 是的,我认为 array_reverse 是要走的路,除非表结构有负载和列负载,否则 20 条记录绝对不是问题
【解决方案2】:

有一种方法不用array_reverse,如果你想用这个sql:

SELECT * FROM `comments` `t` 
WHERE id 
in (SELECT id 
     FROM (SELECT id FROM comments Where postID = xyz ORDER BY id DESC LIMIT 20) 
    as q) 
ORDER BY id ASC

其中的条件将变为:

$criteria=new CDbCriteria();
$criteria->condition='id in (SELECT id FROM (SELECT id FROM comments Where postID='.$id.' ORDER BY id DESC LIMIT 20) as q)';
$criteria->order='id ASC';

更新

对于您的原始查询,您还可以使用 findBySql

$sql='SELECT * FROM (SELECT * FROM comments  WHERE postID= :postid  ORDER BY id DESC LIMIT 20) q ORDER BY id ASC';
$params=array('postid'=>$id);
$comments=Comment::model()->findAllBySql($sql,$params);

这个查询的性能比我之前的查询要好。

【讨论】:

  • 它似乎解决了问题,但你知道它在性能方面的表现吗?有3个sql请求,会不会有点长?
  • 我可以推测:如果您的表很大,最里面的查询是可能需要时间的地方。第二层肯定会非常快,第三层(最外层)可能需要时间,具体取决于桌子的大小。但是,由于这是一个 id 字段,我认为不会花很长时间。您必须对其进行测试,并与您最初的 array_reverse 方法进行比较,我认为这也是一个不错的选择,但既然您问的是另一种方法,那就是它。同时,我也会尝试用测试结果回复您。
  • 我不断增加种子表(达到 10,000 条记录),并检查结果: 1. 在 1000 条记录时 - 多选 = 0.0031068325042725,array_reverse i> = 0.00077199935913086, 2. 在 10,000 条记录时 - 多选 = 0.020848989486694, arrayreverse = 0.00089120864868164。这些是微时间差异,因为您可以看到多选降级,而 array_reverse 仅因为 db 查询花费更长的时间而改变。因此,您当然应该使用旧方法。想不出一个不受数据库大小影响的替​​代查询。
  • 感谢基准测试!我会坚持使用 array_reverse,但你的回答仍然是对我的问题的回应,因为它显示了如何使用 CActiveRecord 执行请求!
  • 是的,你说得对,我没想到!所以今晚我要去试试 findBySql 和 array_reverse 看看哪个更好!
【解决方案3】:

UPD:

请注意,总的来说,其他一些解决方案比我的要好。

使用offset 会降低查询的性能。 请参阅:http://www.slideshare.net/Eweaver/efficient-pagination-using-mysqlWhy does MYSQL higher LIMIT offset slow the query down?

因此,当Comments 的数量增加时,您会得到性能下降。


使用offset 功能怎么样?

    $model = Comment::model();

    $condition = 'postID =' . $id;
    $limit = 20;
    $totalItems = $model->count($condition);

    $criteria = new CDbCriteria(array(
        'condition' => $condition,
        'order' => 'id ASC',
        'limit' => $limit,
        'offset' => $totalItems - $limit // if offset less, thah 0 - it starts from the beginning
    ));

    $result = $model->findAll($criteria);

【讨论】:

  • 偏移量是个好主意,但它可能不适用于所有情况(不确定)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-26
  • 2011-04-22
  • 1970-01-01
  • 2012-05-24
  • 2017-01-20
  • 2020-03-09
  • 2020-02-19
相关资源
最近更新 更多