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

时间:2014-01-17 17:38:13

标签: mysql sql join query-optimization

我需要优化连接取决于条件的查询

我有两张桌子

Table1有两列,我们称之为A和B列,可以与table2列C相关,

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

匹配

最后我需要知道t1上的哪些条目在t2上没有匹配...

为了提供更多细节,t1是一个客户表,A和B都是客户端代码。 代码永远不会与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的情况o B在t2上匹配。 (即没有购买t2的t1客户)

我可以选择为这种情况构建更有效的查询吗?

由于

2 个答案:

答案 0 :(得分:2)

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

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.At1.B进行连接,因此无法选择索引并选择进行表扫描,但如果分开它分为两个查询,它知道在连接上使用哪个列,并且可以使用适当的索引。

<强> Example on SQL Fiddle

答案 1 :(得分:1)

唉,进行条件连接往往会导致查询性能非常差。在这种情况下,您正在测试两个值,并且可能想要查看是否存在两个值。尝试将其分为两个连接:

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上的索引。