mysql - 使用 GROUP BY、ORDER BY 和 GROUP_CONCAT 进行索引

标签 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 处理器上的总查询时间现在为 0.02 秒,128MB 100Hz RAM。
EXPLAIN现在给我一个 USING INDEXlookup_difficulty table 。我添加了这个来实现:
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制作完成,您就拥有了!我的查询现在看起来一团糟,但至少它是优化的。我认为没有人会在阅读这篇文章时走到这一步......

最佳答案

输入 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 处理器上的总查询时间现在为 0.02 秒,100Hz RAM 为 128MB。

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.whatever 添加到每个 JOIN 中,就可以了!我的查询现在看起来一团糟,但至少它是优化的。我认为没有人会在阅读这篇文章时走到这一步......

关于mysql - 使用 GROUP BY、ORDER BY 和 GROUP_CONCAT 进行索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7381828/

相关文章:

Mysql检查约束不起作用

python - 类型错误 : not enough arguments for format string for mysqldb

MySQL Group By - 获取与 max() 金额关联的行

python - Pandas dataframe groupby + apply + new column 很慢

mysql - 计算同一个表mysql中条目的平均值

php - CodeIgniter 中具有表关联的产品的颜色数组

mysql - 使用 MySQL 获取 n 行组的平均值

php - MySQL ORDER BY 'ENUM' 类型值

MySQL - 同时对相同类型的字段进行排序

php - MYSQL ORDER BY 子句不起作用