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

sirbozc5  于 2021-06-21  发布在  Mysql
关注(0)|答案(2)|浏览(390)

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

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\u id和potato\u id的行。
我想避免在我的总体查询中有两次对大规模市场的查询[…]。
最好的方法是什么?

mu0hgdu0

mu0hgdu01#

目标是从需要重复查询字符串的查询字符串列表中拉出所有重复查询字符串。所以我把土豆和胡萝卜放在一个联合子查询中,然后在这个联合子查询之外放置了大量的联合市场。
这看起来很令人讨厌,但我的问题源自一个更复杂的查询,而实现此策略所需的工作在我的案例中更为复杂。对于我上面问题中的简单示例,这将解决如下问题:

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
r55awzrz

r55awzrz2#

如果子查询的运行时间超过一秒钟,我会说这是一个索引问题,而不是查询本身(当然,如果没有看到该查询,这是一种推测,我建议也发布该查询)。根据我的经验,9/10查询速度慢的问题归结为数据库的索引不正确。
确保蔬菜id、土豆id和胡萝卜id已编入索引
另外,如果您在massive\u 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 TABLE 以及 SELECT 陈述

相关问题