如何在联合中避免两次 运行 昂贵的子查询
How to avoid running an expensive sub-query twice in a union
我想合并两个查询。这两个查询都使用内部连接进入数据集,计算量非常大,但是两个查询的数据集查询是相同的。例如:
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
其中 [...] 对应于需要一秒钟计算的子查询,并且 returns 行至少 carrot_id 和 potato_id.
我想避免在我的整体查询中两次查询 massive_market [...]。
最好的方法是什么?
如果那个子查询花费超过一秒到 运行,我会说这是一个索引问题而不是查询本身(当然,没有看到那个查询,这有点猜想,我也建议发布该查询)。根据我的经验,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
发生在临时 table 上(将被删除自动 但直到连接关闭后才会 ,因此您可能需要手动删除 table)。
您可以在 CREATE TEMPORARY TABLE
和 SELECT
语句中添加您需要的任何其他列
目标是从需要重复查询字符串的查询字符串列表中提取所有重复的查询字符串。所以我将土豆和胡萝卜放在一个联合子查询中,然后将 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
我想合并两个查询。这两个查询都使用内部连接进入数据集,计算量非常大,但是两个查询的数据集查询是相同的。例如:
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
其中 [...] 对应于需要一秒钟计算的子查询,并且 returns 行至少 carrot_id 和 potato_id.
我想避免在我的整体查询中两次查询 massive_market [...]。
最好的方法是什么?
如果那个子查询花费超过一秒到 运行,我会说这是一个索引问题而不是查询本身(当然,没有看到那个查询,这有点猜想,我也建议发布该查询)。根据我的经验,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
发生在临时 table 上(将被删除自动 但直到连接关闭后才会 ,因此您可能需要手动删除 table)。
您可以在 CREATE TEMPORARY TABLE
和 SELECT
语句中添加您需要的任何其他列
目标是从需要重复查询字符串的查询字符串列表中提取所有重复的查询字符串。所以我将土豆和胡萝卜放在一个联合子查询中,然后将 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