【问题标题】:ranking entries in mysql tablemysql表中的排名条目
【发布时间】:2011-01-12 19:23:39
【问题描述】:

我有一个包含很多行的 MySQL 表。该表有一个流行度列。如果我按人气排序,我可以得到每个项目的排名。是否可以在不对整个表进行排序的情况下检索特定项目的排名?我不这么认为。对吗?

另一种方法是创建一个新列来存储排名,对整个表进行排序,然后遍历所有行并更新排名。这是极其低效的。有没有办法在单个查询中做到这一点?

【问题讨论】:

    标签: mysql sorting ranking


    【解决方案1】:

    如果不先对表格进行排序或存储排名,就无法计算某项的顺序(您称之为排名)。

    但是,如果您的表被正确索引(流行度索引),那么数据库对其进行排序是微不足道的,因此您可以获得您的排名。我建议如下:

    全选,包括排名

    SET @rank := 0;
    SELECT t.*, @rank := @rank + 1
    FROM table t
    ORDER BY t.popularity;
    

    要获取具有特定“id”的项目,您可以简单地使用子查询,如下所示:

    选择一项,包括排名

    SET @rank := 0;
    SELECT * FROM (
      SELECT t.*, @rank := @rank + 1
      FROM table t
      ORDER BY t.popularity
    ) t2
    WHERE t2.id = 1;
    

    【讨论】:

    • 我认为对于一条记录的排名计算更好的是基于 WHERE t.popularity > t1.popularity + COUNT(*) 的相关子查询
    • 应该通常避免相关子查询。派生表在 MySQL 中几乎总是性能更高。
    • 这是一个很好的解决方案。我不知道您可以像这样按行递增变量。这是一个不错的技巧。
    【解决方案2】:

    如果在每次读取的表上更新排名列,则第二种方法效率低下是对的。但是,根据数据库的更新次数,您可以计算每次更新的排名,并将其存储 - 这是一种缓存形式。然后,您将计算字段转换为固定值字段。

    This video 涵盖了 mysql 中的缓存,虽然它是特定于 rails 的,并且是一种略有不同的缓存形式,但它是一种非常相似的缓存策略。

    【讨论】:

      【解决方案3】:

      如果您使用 InnoDb 表,那么您可以考虑在流行度列上构建聚集索引。 (仅当按流行度排序是频繁查询时)。该决定还取决于受欢迎程度列的变化程度(0 - 3 不太好)。

      您可以查看有关聚集索引的信息,看看这是否适用于您的情况:http://msdn.microsoft.com/en-us/library/ms190639.aspx

      这是指SQL server,但概念是一样的,也可以查看mysql文档。

      【讨论】:

        【解决方案4】:

        如果您使用 PDO 执行此操作,则需要将查询修改为全部包含在单个语句中,以使其正常工作。见PHP/PDO/MySQL: Convert Multiple Queries Into Single Query

        所以 hobodave 的回答变成了这样:

        SELECT t.*, (@count := @count + 1) as rank
        FROM table t 
        CROSS JOIN (SELECT @count := 0) CONST
        ORDER BY t.popularity;
        

        【讨论】:

          【解决方案5】:

          hobodave 的解决方案非常好。或者,您可以添加一个单独的排名列,然后,只要一行的受欢迎程度为UPDATEd,查询以确定该受欢迎程度更新是否改变了其相对于其上方和下方行的排名,然后UPDATE 受影响的 3 行。您必须进行剖析以查看哪种方法更有效。

          【讨论】:

          • 这并不像你描述的那么简单。经常会有许多个受影响的行。您似乎在假设一件物品的受欢迎程度只会增加 +/- 1 个单位,并且没有考虑到更大的增加。事实上,最坏的情况是将某些内容移到列表顶部,您必须更新表中的每一行。
          • 另一件事,UPDATE 将总是比 SELECT 花费更长的时间。
          • 全部为真;我的操作是假设受欢迎程度只会逐渐改变。
          猜你喜欢
          • 2019-08-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多