0

问题

我正在查看 MySQL 中的排名用例,但我还没有确定一个明确的“最佳解决方案”。我有一张这样的桌子:

CREATE TABLE mytable (
  item_id int unsigned NOT NULL,
  # some other data fields,
  item_score int unsigned NOT NULL,
  PRIMARY KEY (item_id),
  KEY item_score (item_score)
) ENGINE=MyISAM;

其中包含数百万条记录,最常见的写入操作是使用新值更新 item_score。给定一个 item_id 和/或它的分数,我需要得到它的排名,我目前知道两种方法来完成它。

COUNT() 个得分较高的项目

SELECT COUNT(*) FROM mytable WHERE item_score > $foo;

分配行号

SET @rownum := 0;
SELECT rank FROM (
    SELECT @rownum := @rownum + 1 AS rank, item_id
    FROM mytable ORDER BY item_score DESC ) AS result
WHERE item_id = $foo;

哪一个?

它们的表现相同还是表现不同?如果是这样,为什么它们不同,我应该选择哪一个?

有更好的主意吗?

有没有更好/更快的方法?我唯一能想到的就是一个单独的表/memcache/NoSQL/whatever 来存储预先计算的排名,但是我mytable每次更新它时仍然需要排序和读出。这让我认为,只有当“读取等级”查询的数量(很多?)大于更新数量时,这才是一个好方法,另一方面,当“读取等级”查询接近更新查询的数量。

4

1 回答 1

0

由于您的表上有索引,因此唯一有意义的查询是

-- findByScore    
SELECT COUNT(*) FROM mytable WHERE item_score > :item_score; 
-- findById
SELECT COUNT(*) FROM mytable WHERE item_score > (select item_score from mytable where item_id = :item_id); 

在 findById 上,因为您只需要 1 个项目 id 的排名,因此在性能方面与加入对应项没有太大区别。

如果您需要许多项目的排名,那么使用连接会更好。

Usign“分配行号”不能在这里竞争,因为它不会使用索引(在你的查询中根本没有,如果我们甚至改进它仍然不是那么好)

使用分配索引也可能存在一些隐藏的陷阱:如果有多个项目具有相同的分数,那么它会给你最后一个的排名。

无关:如果可能,请使用 PDO 以防止 sql 注入。

于 2012-11-20T12:51:31.720 回答