Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何使用条件联接优化查询?_Mysql_Sql_Join_Query Optimization - Fatal编程技术网

Mysql 如何使用条件联接优化查询?

Mysql 如何使用条件联接优化查询?,mysql,sql,join,query-optimization,Mysql,Sql,Join,Query Optimization,我需要优化一个连接依赖于条件的查询 我有两张桌子 表1有两列,我们称之为A列和B列,它们可以与表2的C列相关 如果列B为null,我必须将t1.A与t2.C匹配 如果列B不为null,则必须将t1.B与t2.C匹配 最后,我需要知道t1上的哪些条目与t2上的条目不匹配 更详细地说,t1是一个客户机表,a和B都是客户机代码。 A代码与B代码不同,在有B的情况下,B具有优先权(B是新客户机代码,但旧客户机没有。在B为空的情况下,A是要使用的代码)(所有这些都是因为B列是新的,而旧客户机的B值为空)

我需要优化一个连接依赖于条件的查询

我有两张桌子

表1有两列,我们称之为A列和B列,它们可以与表2的C列相关

如果列B为null,我必须将t1.A与t2.C匹配 如果列B不为null,则必须将t1.B与t2.C匹配

最后,我需要知道t1上的哪些条目与t2上的条目不匹配

更详细地说,t1是一个客户机表,a和B都是客户机代码。 A代码与B代码不同,在有B的情况下,B具有优先权(B是新客户机代码,但旧客户机没有。在B为空的情况下,A是要使用的代码)(所有这些都是因为B列是新的,而旧客户机的B值为空)

t2是一个采购表。t2.C是客户机代码,但在本例中是一列,它为旧客户机存储a代码,为新客户机存储B代码

我只想知道哪些客户还没有购买,并尽可能高效地查询

我提出了几个问题,但它们的速度非常慢,我想这是因为条件是如何处理的:

第一次尝试:

select * 
from t1
left join t2 on (t1.A = t2.C or t1.B = t2.C)
where t2.D is null;
请注意,我可以使用OR条件,因为我知道t1.A永远不会与任何t1.B相同,所以在t2.C中,它只能与A或B匹配,但不能同时与两者匹配(假设条件得到保证)。查询速度太慢,以至于在我的sql客户端中超时

第二次尝试

select * 
from t1
left join t2 on (if(t1.B is null, t1.A = t2.C, t1.B = t2.C))
where t2.D is null;
在这种情况下,比较条件取决于t1.B,如果为null,则与A进行比较,如果不是,则与B进行比较。 同样,查询速度非常慢

我想我可以只使用两个连接,并对每个连接使用每个条件(A或B),但我不知道如何实现它,特别是因为我只需要得到A和B在t2上都不匹配的情况。(也就是说,t1客户没有t2购买)

对于这种情况,我可以选择什么来构建更高效的查询


多亏了

唉,执行条件联接往往会导致非常差的查询性能。在本例中,您正在测试两个值,并可能希望查看两个值是否都不存在。尝试将其拆分为两个联接:

select * 
from t1 left join
     t2
     on t1.A = t2.C left join
     t2 t2a
     on t1.B = t2a.C
where t2.D is null and t2a.D is null;

这将允许查询使用A、B和C上的索引。

如果您在
t1.A
t1.B
上没有索引,那么我怀疑这将是您的最佳选择:

select * 
from t1
left join t2 on ifnull(t1.B, t1.A) = t2.C
where t2.D is null;
但是,如果对任一列进行了索引,我怀疑您将通过使用
UNION-ALL
获得最佳性能:

select * 
from t1
left join t2 on t1.A = t2.C
where t2.D is null
and t1.B is null
union all
select * 
from t1
left join t2 on t1.B = t2.C
where t2.D is null
and t1.B is not null;
原因是,在编译过程中,优化程序不知道是否要对联接使用
t1.A
t1.B
,因此无法选择索引并选择表扫描,但如果将其分为两个查询,它知道要在联接上使用哪一列,并且可以使用适当的索引


谢谢!第一个版本(使用
ifnull
)运行得非常好,我看到的与我的第二次尝试非常相似,我在其中使用
(如果(t1.B为null,t1.A=t2.C,t1.B=t2.C))
而不是ifnull(t1.B,t1.A)=t2.C上的
。是什么让它们如此不同,以至于你的版本比我的版本更有效?我觉得这很有趣。事实上,尽管我为所有涉及的列(A、B和C)建立了索引,但您的ifnull版本的运行速度比union all快(.2秒vs.6秒)。原因是
ifnull
比您的if语句运行得更好,因为其中不包含列
t2.C
,它是静态的,所以MySQL知道它可以在这个列上使用索引,而在您的if语句中,它无法计算出
t2.C
在true和false表达式中都使用,所以它不使用索引。哦,现在我明白了!因此,这不是因为简单地使用
ifnull(x,y)
而不是
if(x为null,y,x)
,而是因为比较列位于
if
之外。因此使用
(如果(t1.B为null,t1.A,t1.B)=t2.C)
与ifnull()完全相同。谢谢我接受了这个答案,但Gordon Linoff的答案也是正确的,事实上,如果有索引,它会运行得更快。工会的所有提示都为我敲定了它!