我有一个包含很多行的MySQL表。该表有一个受欢迎的列。如果我按人气排序,我可以得到每个项目的排名。是否可以在不对整个表进行排序的情况下检索特定项目的等级?我不这么认为。这是对的吗?
另一种方法是创建一个用于存储排名的新列,对整个表进行排序,然后遍历所有行并更新排名。这是非常低效的。有没有办法在单个查询中执行此操作?
答案 0 :(得分:9)
如果没有先排序表或存储排名,就无法计算某些东西的顺序(你称之为排名)。
如果你的表被正确编入索引(流行度指数),数据库对此进行排序是微不足道的,这样你就可以得到你的排名。我建议如下:
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;
答案 1 :(得分:0)
如果在读取的每个表上更新rank列,那么第二种方法是无效的,你是对的。但是,根据数据库的更新次数,您可以计算每次更新的排名,并存储它 - 它是一种缓存形式。然后,您将计算字段转换为固定值字段。
This video涵盖了mysql中的缓存,虽然它是特定于rails的,并且是一种稍微不同的缓存形式,但它是一种非常类似的缓存策略。
答案 2 :(得分:0)
如果您使用的是InnoDb表,则可以考虑在热门列上构建聚簇索引。 (仅当按受欢迎程度的顺序是频繁查询时)。决定还取决于受欢迎列的变化程度(0 - 3不太好)。
您可以在聚集索引上查看此信息,看看这是否适用于您的案例:http://msdn.microsoft.com/en-us/library/ms190639.aspx
这指的是SQL服务器但概念是一样的,也就这个查找mysql文档。
答案 3 :(得分:0)
如果您使用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;
答案 4 :(得分:-1)
hobodave的解决方案非常好。或者,您可以添加单独的排名列,然后,每当行的受欢迎程度为UPDATE
d时,查询以确定该受欢迎程度更新是否相对于其上方和下方的行更改了其排名,然后UPDATE
3行受影响。您必须剖析以确定哪种方法更有效。