按标签过滤的项目排序

时间:2010-11-28 11:31:26

标签: mysql join tags query-optimization sql-order-by

我想实现一个非常常见的功能 - 按标签过滤一些项目。互联网上有许多教程,并附有如何操作的示例。查询非常简单快速(假设存在适当的索引) 但通常过滤的项目需要按某个字段进行排序。例如,当您在SO上按标记过滤问题时,您可以对结果进行排序。

要完成此任务(假设我们需要按评级排序),可以写一下:

SELECT item.id FROM item
    INNER JOIN taggeditem ON taggeditem.item_id = item.id
WHERE
    taggeditem.tag_id = 1234
ORDER BY item.rating DESC

我们有索引(taggeditem.tag_id)(item.id)(item.rating) 这个查询的问题是mysql不能在item.rating上使用索引,因为用于获取行的键与ORDER BY(MySQL: ORDER BY Optimization)中使用的键不同。这导致使用临时表和filesort,这反过来导致执行时间变慢。

我提出的解决方案是将排序字段反规范化到taggeditem表,以便我可以在(tag_id, item_rating)上创建索引taggeditem

我在SO搜索了类似的问题,发现只有这一个:Mysql slow query: INNER JOIN + ORDER BY causes filesort。解决方案是一样的。

所以,我想问一下,这是解决这个问题的常见方法吗?将一堆排序字段反规范化为taggeditem是一种好的做法,例如创建,评级?在SO,您可以使用4个不同的参数(最新,热门,投票,活动)进行排序 - 它是否意味着它们用于对结果进行排序的非规范化字段? 这个解决方案有其他替代方案吗?

2 个答案:

答案 0 :(得分:1)

有一个标准替代方案 - 更改服务器系统变量。 例如,您可以尝试使用sort_buffer_size值(默认为2MB)。 More关于它。

答案 1 :(得分:0)

一旦你使用了JOIN,并在连接的表上过滤掉,你就会遇到糟糕的表现。

正如你所说,避免这种情况的唯一方法是创建一个非规范化表。

对于SO的种类,我认为他们没有这样的问题:他们只需要通过答案表的一列来排序答案(类似于SELECT * FROM answers WHERE question_id = 1234 SORT BY answer_date,索引为question_id, answer_date

我也在寻找具有多值列的解决方案,这非常困难(非规范化数据会非常庞大​​,因为它需要跨越多值列中的所有值)