如何避免在联合中运行两次昂贵的子查询

时间:2018-06-11 16:40:02

标签: mysql subquery union database-performance

我想结合两个查询。两个查询都使用内部联接到数据集中,这对于计算来说非常密集,但两个查询的数据集查询都是相同的。例如:

SELECT veggie_id
FROM potatoes
INNER JOIN ( [...] ) massive_market
    ON massive_market.potato_id=potatoes.potato_id
UNION
SELECT veggie_id
FROM carrots
INNER JOIN ( [...] ) massive_market
    ON massive_market.carrot_id=carrots.carrot_id

其中 [...] 对应于需要一秒钟计算的子查询,并返回至少为carrot_id和potato_id的行。

我想在我的总体查询中避免两次查询large_market [...]

最好的办法是什么?

2 个答案:

答案 0 :(得分:1)

如果该子查询运行时间超过一秒,我会说这是一个索引问题,而不是查询本身(当然,没有看到该查询,这有点猜想,我建议发布查询也)。根据我的经验,9/10慢查询问题归咎于数据库的索引不正确。

确保将veggie_id,potato_id和carrot_id编入索引

此外,如果您在massive_market子查询中使用任何联接,请确保您正在执行联接的列也已编入索引。

修改

如果索引已经正确完成,我能想到的唯一其他解决方案就是:

CREATE TEMPORARY TABLE tmp_veggies (potato_id [datatype], carrot_id [datatype]);

INSERT IGNORE INTO tmp_veggies (potato_id, carrot_id) select potatoes.veggie_id, carrots.veggie_id from [...] massive_market 
    RIGHT OUTER JOIN potatoes on massive_market.potato_id = potatoes.potato_id 
    RIGHT OUTER JOIN carrots on massive_market.carrot_id = carrots.carrot_id;
SELECT carrot_id FROM tmp_veggies
UNION
SELECT potato_id FROM tmp_veggies;

这样,你就颠倒了查询,所以它只运行一次大量的子查询,UNION正在临时表上发生(自动删除但直到连接关闭,因此您可能希望手动删除表格。
您可以在CREATE TEMPORARY TABLESELECT声明

中添加所需的任何其他列

答案 1 :(得分:1)

目标是将所有重复的查询字符串从需要重复查询字符串的查询字符串列表中拉出。因此,我将土豆和胡萝卜放在一个联合子查询中,然后将Massive_market放在此统一之外。

这似乎很明显,但是我的问题来自一个更复杂的查询,而实施此策略所需的工作在我的案例中涉及更多。对于上述问题中的简单示例,这可以通过以下方式解决:

SELECT veggie_id 
FROM (
  SELECT veggie_id, potato_id, NULL AS carrot_id FROM potatoes
  UNION
  SELECT veggie_id, NULL AS potato_id, carrot_id FROM carrots
) unionized
INNER JOIN ( [...] ) massive_market
  ON massive_market.potato_id=unionized.potato_id 
    OR massive_market.carrot_id=unionized.carrot_id