就本文而言,我已将问题简化为最纯粹的形式。 我有3个表:games,games_tags和games_tags_map
如果我想为每个游戏获得一个标签表,我会这样做:
SELECT `games_tags_map`.`game_id` as 'game_id', GROUP_CONCAT(`games_tags_map`.`tag_id`) as 'tags'
FROM `games_tags_map`
LEFT JOIN `games_tags` on `games_tags`.id = `games_tags_map`.`tag_id`
GROUP BY `games_tags_map`.game_id
需要~1ms
SELECT `games`.`id` AS 'id' from `games`
这需要< 1ms。
但是,当我尝试加入这两个时:
SELECT `games`.`id` AS 'id',
t.`tags` as `tags`
FROM `games`
LEFT JOIN (
SELECT `games_tags_map`.`game_id` as 'game_id', GROUP_CONCAT(`games_tags_map`.`tag_id`) as 'tags'
FROM `games_tags_map`
LEFT JOIN `games_tags` on `games_tags`.id = `games_tags_map`.`tag_id`
GROUP BY `games_tags_map`.game_id
) t ON t.`game_id`=`games`.`id`
需要约100毫秒
但是,当我进行等效查询时:
SELECT `games`.`id` AS 'id',
GROUP_CONCAT(DISTINCT `games_tags`.`tag`) AS 'tags'
FROM `games`
LEFT JOIN `games_tags_map` ON `games`.`id` = `games_tags_map`.`game_id`
LEFT JOIN `games_tags` ON `games_tags`.`id` = `games_tags_map`.`tag_id`
WHERE `games`.`active`=1
GROUP BY `games`.`id`
需要2ms ...... 但是,当我需要通过主列(id)之外的任何其他命令时,它需要~80ms
只是为了澄清,这是我的实际数据库的一个非常简单的版本,它经历了更长的加载时间并导致我的网站出现问题,但问题出现在这些查询中。
我的数据库设置方式存在明显的缺陷,因为加载时间非常不同。我尝试过添加更多索引,但它没有帮助。 桌上游戏'我有主要索引' id' 在桌子上#games_authors_map'主要索引包含' game_id'和' author_id'
我知道有问题,但我无法修复,而且我不明白为什么。
请帮忙。
答案 0 :(得分:2)
为什么不在主游戏桌面上添加聚合列,而不是连接所有游戏标签表(这本身就可以),所以你不需要加入。然后,您可以简单地添加一个触发器,无论何时在game_tags_map表中添加或删除标记,它都会更新主游戏表。如果这只是为了显示到基于网络的游戏网站,你就是好的。如果某人对某种类型的游戏感兴趣,那么针对game_tags_map表的查询将很好地总结该特定兴趣的列表。
您每次都在对所有游戏进行查询,因此这对您来说可能是更好的途径。
首先,查看您的第一个查询,并删除刻度, 引用并将长表名称别名分别为gtm和gt, 你的查询甚至都不使用games_tags表,因为它是一个左连接 并且不使用它的任何列...
SELECT
gtm.game_id,
GROUP_CONCAT(gtm.tag_id) as tags
FROM
games_tags_map gtm
LEFT JOIN games_tags gt
on gtm.tag_id = gt.id
GROUP BY
gtm.game_id
所以从本质上说,它只是
SELECT
gtm.game_id,
GROUP_CONCAT(gtm.tag_id) as tags
FROM
games_tags_map gtm
GROUP BY
gtm.game_id
除非您打算使用group_concat()来显示文字说明 表示ID而不是ID本身。如果是ID,那么 你的第二个查询也可以删除games_tags表的内部左连接。
SELECT
g.id AS id,
t.tags as tags
FROM
games g
LEFT JOIN ( SELECT
gtm.game_id,
GROUP_CONCAT(gtm.tag_id) as tags
FROM
games_tags_map gtm
LEFT JOIN games_tags
on gtm.tag_id = gt.id
GROUP BY gtm.game_id ) t
ON g.id = t.game_id
在您的上一次查询中,您正在加入以实际获取标记说明 而不是标签。
SELECT
g.id,
GROUP_CONCAT(DISTINCT gt.tag) AS tags
FROM
games g
LEFT JOIN games_tags_map gtm
ON g.id = gtm.game_id
LEFT JOIN games_tags gt
ON gtm.tag_id = gt.id
WHERE
g.active = 1
GROUP BY
g.id
要优化此查询,我会提供以下索引。
这将使整个查询与覆盖索引一起使用并且可以处理
索引的整个查询,永远不需要转到原始底层数据。
table index
games ( active, id )
games_tags_map ( game_id, tag_id )
games_tags ( id, tag )
最后一点,当你试图为帖子提供更多细节时,你可以 始终编辑现有帖子,添加更多详细信息,然后向用户发送评论 关于提供给审查的额外数据,并可能提供额外的数据 内容/答案/回应。
答案 1 :(得分:0)
尝试在表格中使用外键索引(games_tags_map
。tag_id
,games_tags_map
。game_id
),同时索引您尝试使用的列对查询进行排序
这将解决您的问题。