使用GROUP BY,ORDER BY和GROUP_CONCAT进行索引

时间:2011-09-11 22:51:01

标签: mysql group-by sql-order-by

已解决见下文

我在我的查询中尝试使用GROUP BYORDER BY,我检索按难度排序的数据。我必须使用GROUP BY,因为GROUP CONCAT因为某些表(例如'lookup_peripheral')将多个值链接到同一个键(content_id)。我理解为什么MYSQL在执行此任务时不能使用索引,因为GROUP BY和ORDER BY语句不共享相同的字段。但是,我正在寻找替代解决方案,不需要一天的时间来检索结果。

如果省略GROUP BYORDER BY子句,则数据库使用索引,但结果缺少所有外围设备或者没有按难度排序。

我在FROM中使用'lookup_difficulty'表,所以我可以使用该索引来排序结果。 lookup_xxxxx表存储每个允许的值,然后其他表(例如peripheral)通过content_id将提交链接到值。所有内容都以提交content_id为参考。 content表包含成员ID,名称等基本信息。

如果我的帖子不够明确,我道歉。

mysql> describe peripheral;
+------------------+----------+------+-----+---------+-------+
| Field            | Type     | Null | Key | Default | Extra |
+------------------+----------+------+-----+---------+-------+
| peripheral_id    | int(2)   | NO   | PRI | NULL    |       |
| peripheral       | char(30) | NO   |     | NULL    |       |
| peripheral_total | int(5)   | NO   |     | NULL    |       |
+------------------+----------+------+-----+---------+-------+

mysql> select * from peripheral;
+---------------+-----------------+------------------+
| peripheral_id | peripheral      | peripheral_total |
+---------------+-----------------+------------------+
|             1 | periph 1        |                0 |
|             2 | periph 2        |                1 |
|             3 | periph 3        |                3 |
+---------------+-----------------+------------------+

mysql> describe lookup_peripheral;
+---------------+---------+------+------+---------+-------+
| Field         | Type    | Null | Key  | Default | Extra |
+---------------+---------+------+------+---------+-------+
| content_id    | int(10) | NO   | INDEX| NULL    |       |
| peripheral_id | int(2)  | NO   |      | NULL    |       |
+---------------+---------+------+------+---------+-------+  


mysql> mysql> select * from lookup_peripheral;
+------------+---------------+
| content_id | peripheral_id |
+------------+---------------+
|         74 |             2 |
|         74 |             5 |
|         75 |             2 |
|         75 |             5 |
|         76 |             3 |
|         76 |             4 |
+------------+---------------+

以下不是在lookup_difficulty上使用索引,而是使用表排序和临时表。

SELECT group_concat(DISTINCT peripheral.peripheral) as peripheral, content.member, .....
FROM (lookup_difficulty)
LEFT OUTER JOIN lookup_peripheral ON lookup_difficulty.content_id = lookup_peripheral.content_id
LEFT OUTER JOIN peripheral ON peripheral.peripheral_id = lookup_peripheral.peripheral_id
.....
LEFT OUTER JOIN programmer ON programmer.programmer_id = lookup_programmer.programmer_id
LEFT OUTER JOIN lookup_programming_language ON lookup_difficulty.content_id = lookup_programming_language.content_id

GROUP BY lookup_difficulty.content_id
ORDER BY lookup_dfficulty.difficulty_id
LIMIT 30    

最终目标是通过附加的正确外围设备检索按难度排序的结果。我想我需要一个子查询来实现这个目标。


编辑:下面回答:

想出来。我做了我怀疑我必须做的事情,那就是添加一个子查询。由于MYSQL每个表只能使用一个索引,因此我无法将GROUP BYSORT BY一起用于我的特定设置。相反,我添加了另一个查询,该查询将使用另一个表上的另一个索引将外围设备组合在一起。这是我在上面SELECT语句中添加的内容:

(SELECT group_concat(DISTINCT peripheral.peripheral) as peripheral
FROM lookup_peripheral
LEFT OUTER JOIN peripheral ON peripheral.peripheral_id = lookup_peripheral.peripheral_id
WHERE lookup_difficulty.content_id = lookup_peripheral.content_id
GROUP BY lookup_peripheral.content_id
LIMIT 1) as peripheral

我使用了LEFT OUTER,因为有些条目没有任何外围设备。对于大多数表,对于40k行数据库,400MHz处理器上的总查询时间现在为.02s,具有128MB的100Hz RAM。

EXPLAIN现在为USING INDEX表格提供lookup_difficulty。我添加了这个来实现:

ALTER TABLE `pictuts`.`lookup_difficulty` DROP PRIMARY KEY ,
ADD PRIMARY KEY ( `difficulty_id` , `content_id` ) 

编辑2 我注意到,通过使用分页进行大偏移,页面加载速度会慢得多。您可能也体验过其他网站。幸运的是,正如Peter Zaitsev所指出的那样,有一种方法可以避免这种情况。这是我更新的片段,用于实现30K或0的偏移的相同时间:

FROM 
SELECT lookup_difficulty.content_id, lookup_difficulty.difficulty_id
FROM lookup_difficulty
LIMIT '.$offset.', '.$per_page.'
) ld

现在只需将ld.whatever添加到每个JOIN制作中,就可以了!我的查询现在看起来像一团糟,但至少它已经过优化。我认为没有人会在阅读这篇文章时做到这一点......

1 个答案:

答案 0 :(得分:2)

输入Justin的答案,所以这个问题没有得到答案:

想出来。我做了我怀疑我必须做的事情,那就是添加一个子查询。由于MYSQL每个表只能使用一个索引,因此我无法将GROUP BY和SORT BY一起用于我的特定设置。相反,我添加了另一个查询,该查询将使用另一个表上的另一个索引将外围设备组合在一起。这是我在上面的SELECT语句中添加的内容:

(SELECT group_concat(DISTINCT p.peripheral) as peripheral
FROM lookup_peripheral lp
LEFT JOIN peripheral p ON p.peripheral_id = lp.peripheral_id
WHERE ld.content_id = lp.content_id
GROUP BY lp.content_id
LIMIT 1) as peripheral

我使用LEFT OUTER,因为有些条目没有任何外围设备。对于大多数表,40k行数据库的400MHz处理器上的总查询时间现在为.02s,带有128MB的100Hz RAM。

EXPLAIN现在为lookup_difficulty表提供了一个USING INDEX。我添加了这个来实现:

ALTER TABLE pictuts.lookup_difficulty DROP PRIMARY KEY ,
ADD PRIMARY KEY ( difficulty_id , content_id ) 

编辑2我注意到使用分页的大偏移量,页面加载速度会相当慢。您可能也体验过其他网站。幸运的是,Peter Zaitsev指出,有一种方法可以避免这种情况。这是我更新的片段,用于实现30K或0的偏移的相同时间:

FROM 
SELECT ld.content_id, ld.difficulty_id
FROM lookup_difficulty ld
LIMIT '.$per_page.' OFFSET '.$offset.' 
) ld

现在只需添加ld.w到每个JOIN,你就拥有它!我的查询现在看起来像一团糟,但至少它已经过优化。我认为没有人会在阅读这篇文章时做到这一点......