使用嵌套选择进行查询优化

时间:2014-10-23 11:42:41

标签: sql

我有一个表products和一个表translations。我为每种产品提供了n个翻译,但始终至少有一个默认翻译(LangID = 0)。

我想要做的是"搜索查询"用户输入的字符串。如果用户使用的语言中有翻译(让我们说LangID = 1)我只想搜索此语言的翻译(也不是默认翻译),但是如果没有翻译我希望在默认翻译中搜索所需的语言。所以基本上默认的翻译只是一个后备。

我想出了什么:

SELECT * FROM products p JOIN translations t ON p.ID = t.ProductID 
WHERE (t.LangID = 1 OR (t.LangID = 0 AND NOT EXISTS (SELECT id FROM translations t2 WHERE t2.ProductID = p.ID AND t2.LangID = 1))
      AND t.Translation LIKE "Foo%" `

这是最好的方法还是没有嵌套选择可以做到这一点?或者是否有更好的(表现明智的)查询/方法?

2 个答案:

答案 0 :(得分:2)

你可以这样做,但不清楚执行计划是好还是不好坏。 OREXISTS的组合无法可靠地产生良好的计划。

加入两次更安全,更快:

select *
from products p
left join translations t1 on t1.langid = 1 and ...
left join translations t0 on t1.langid is null and t0.langid = 0 and ...

然后使用t1的值(如果存在)。如果不是,请使用t0的值。谓词t1.langid is null是可选的,但它允许SQL Server(希望)在第一个连接成功的情况下跳过第二个连接。我已经看到这种模式有效,但假设它总是这样做是不安全的。

这导致了一个可靠而简单的计划。

答案 1 :(得分:1)

with t as (
SELECT * FROM products p JOIN translations t ON p.ID = t.ProductID 
WHERE t.LangID = 1 AND t.Translation LIKE "Foo%")
select * from t
union all
SELECT * FROM products p, translations t 
 where (select count(*) from t) = 0
   and p.ID = t.ProductID 
   and t.LangID = 0 AND t.Translation LIKE "Foo%"';

它是Oracle语法, t 只是一个子查询(WITH允许您为子查询指定名称)

如果计算 t 的过程很复杂,此查询可能会更快

P.S。您的数据库可能不会对WHERE条件使用快捷方式评估。需要测试(实际上Oracle并不保证其使用,但Oracle优化器足够智能,所以它适用于我的情况)