通过唯一键优化多个内部自连接

时间:2017-02-01 12:29:25

标签: sql query-optimization

假设我有一些包含交易的表X,其中CUSTOMER_ID是主键。

此外,我有数百个“功能”(就机器学习而言),即此表X上的查询文本。 所有这些查询都是:

查询1:

SELECT
X.CUSTOMER_ID,
WHEN(X.GENDER = "F" AND X.IS_PREGNANT = TRUE) THEN 1 OTHERWISE 0 AS WILL_BUY_FOR_KIDS
FROM X

查询xxx:

SELECT
X.CUSTOMER_ID,
WHEN(X.GENDER = "M" AND X.AVG_AMOUNT > 1000) THEN 1 OTHERWISE 0 AS RICH_DUDE
FROM X


任务是生成包含从X表计算的所有“特征”的表。 所以我需要使用“特征”查询的文本创建输出查询文本(以编程方式)。 类似的东西:

SELECT
*
FROM SOME_QUERY_1
INNER JOIN SOME_QUERY_X
ON SOME_QUERY_1.CUSTOMER_ID = SOME_QUERY_X.CUSTOMER_ID
...

当内部自连接数百个子查询时,上面的输出查询可能会非常慢。 显然,如果SQL引擎将这个查询“重写”为类似(避免连接),那将会很酷:

SELECT
CUSTOMER_ID,
WHEN(X.GENDER = "F" AND X.IS_PREGNANT = TRUE) THEN 1 OTHERWISE 0 AS WILL_BUY_FOR_KIDS,
WHEN(X.GENDER = "M" AND X.AVG_AMOUNT > 1000) THEN 1 OTHERWISE 0 AS RICH_DUDE,
.....
FROM X


几个问题:

  1. 是否有任何可以进行上述优化的SQL引擎(MySQL,PostgreSQL等)?
  2. 使用通用的数值代数,我们已经证明了简化表达式的规则(例如:(a + b) * a = a^2 + b*a)。关系algrebra是否有这样的规则?

2 个答案:

答案 0 :(得分:1)

似乎Oracle的优化器可以完成这项工作。

req.user

请注意执行计划中的9 ELIMINATE_JOIN

drop table x;
create table x (a int primary key,b int);

select  x0.b,x1.b,x2.b,x3.b,x4.b,x5.b,x6.b,x7.b,x8.b,x9.b

from         (select x.a,x.b from x) x0
        join (select x.a,x.b from x) x1 on x1.a = x0.a
        join (select x.a,x.b from x) x2 on x2.a = x0.a
        join (select x.a,x.b from x) x3 on x3.a = x0.a
        join (select x.a,x.b from x) x4 on x4.a = x0.a
        join (select x.a,x.b from x) x5 on x5.a = x0.a
        join (select x.a,x.b from x) x6 on x6.a = x0.a
        join (select x.a,x.b from x) x7 on x7.a = x0.a
        join (select x.a,x.b from x) x8 on x8.a = x0.a
        join (select x.a,x.b from x) x9 on x9.a = x0.a
;        

答案 1 :(得分:0)

首先,您应该将查询编写为:

SELECT X1.A * 2, // Some operation on X1.A
       X2.B / 2 // Some operation on X2.B
FROM X X1 JOIN
     X X2
     ON X1.C = X2.C;

子查询没有提供任何价值(但我稍后会回复)。

如果C被声明为unique(或primary key),那么该字段就有一个索引。我很确定每个数据库仍然会执行JOIN,但它会非常快:

  • 处理记录(X1)并找到C
  • 在索引中查找C
  • 返回已在内存中的记录以获取X2

与首先阅读数据相比,通过索引的额外开销并不是一个很大的负担。

使用您编写的查询,大多数数据库都足够智能,仍然可以执行此优化 - 它们只是忽略子查询。 MySQL是个例外。它实际上实现了子查询,因此您编写的版本可能很慢 - 实现也失去了使用索引的能力。但是,重写应该没问题。

您可能会问为什么数据库没有针对此进行优化。好吧,数据库开发人员更专注于优化编写良好的查询而不是优化写得不好的查询。如果不需要JOIN,那么查询写入应该知道这一点。 (实际上,JOIN只有一次使用,它会过滤掉NULL个值。)