1

我有下面的 SQL,它有一个不可接受的响应时间。

这与 RPG 程序中的 DECLARE、PREPARE、OPEN 和 FETCH 一起使用,其中选定的字段放置在主变量中,填充到数组中,然后按 [降序] 排序以显示子文件。

正在使用的 2 个表根本没有键控 (PF),它们在下面连接,如 WHERE 子句所示。

Select DISTINCT B.Fld1, B.Fld2, B.Fld3, B.Fld4,
A.Fld1, A.Fld2, A.Fld3, A.Fld4, A.Fld5, A.Fld6, A.Fld7, A.Fld8, A.Fld9
From TableA A, TableB B
Where A.Fld2 = B.Fld5
And A.Fld1 = B.Fld6 || B.Fld7
And ((A.Fld7 BETWEEN <from-date> and <to-date>)
Or (A.Fld5 BETWEEN <from-date> and <to-date>))

我已将其重写为“真正的”左连接,没有任何改进。

我还使用了 2 个可用的 LF,其中 A.Fld2 和 A.Fld1 作为键,略有改进。

我觉得递归 SQL 可以解决问题,但我缺乏将其淘汰的经验。我从每个表中选择了自己创建和运行的选项。我只是不知道如何将它们组合成一只美丽的野兽以获得我想要的结果。

这个结果集大约有 10,000 行一周的时间段,我需要看到 2 周。

TableA 中有近 6,000,000 条记录,TableB 中有大约 160,000 条记录。

现在的逻辑是

  1. 在上述 SQL 之前运行一个简单的 SQL。
  2. 游标通过记录并填充数组
  3. 运行上面的 SQL。
  4. 游标通过记录并附加到同一个数组
  5. 对数组进行排序并使用它来填充子文件。

在调试中,我验证了上面的 SQL 是问题的核心。

事实是我有 3 个文件,我相信可以将它们加入 1 个结果表以构建子文件。如果我可以通过上面的查询,那么“我认为我可以”处理加入另一个文件。

我的猜测是那里有人可以“鞭打这个”!我曾经和他一起工作过!

这不是 RPG,我质疑系统。我以前在 RPG 中写过一些这样的 SQL。问题是其他人编写了 SQL。: (

4

4 回答 4

0

您在连接中遇到了 OR(或 ||)语句的性能问题,并且可能来自 BETWEEN(在 DATETIME 对我来说从来没有很好的工作)。删除“或”和“||” 语句,而是有四个单独的查询,它们之间有一个“UNION ALL”。这将大大提高你的表现,即使它看起来违反直觉。我还将该日期设置为 [date]>fromDate 和 [date]


更新 - 这是没有 OR 子句的完整查询。>/< 符号可能难以阅读,因此请先喝杯咖啡:

Select DISTINCT B.Fld1, B.Fld2, B.Fld3, B.Fld4,
A.Fld1, A.Fld2, A.Fld3, A.Fld4, A.Fld5, A.Fld6, A.Fld7, A.Fld8, A.Fld9
From TableA A, TableB B
Where A.Fld2 = B.Fld5
And A.Fld1 = B.Fld6
And A.Fld7 > <from-date> 
AND A.Fld7 < <to-date>
AND A.Fld5 < <from-date> -- Excluding these to avoid duplicates
and A.Fld5 > <to-date> -- Excluding these to avoid duplicates
UNION ALL
Select DISTINCT B.Fld1, B.Fld2, B.Fld3, B.Fld4,
A.Fld1, A.Fld2, A.Fld3, A.Fld4, A.Fld5, A.Fld6, A.Fld7, A.Fld8, A.Fld9
From TableA A, TableB B
Where A.Fld2 = B.Fld5
And A.Fld1 = B.Fld6
AND A.Fld5 > <from-date> 
and A.Fld5 < <to-date>
UNION ALL
Select DISTINCT B.Fld1, B.Fld2, B.Fld3, B.Fld4,
A.Fld1, A.Fld2, A.Fld3, A.Fld4, A.Fld5, A.Fld6, A.Fld7, A.Fld8, A.Fld9
From TableA A, TableB B
Where A.Fld2 = B.Fld5
And A.Fld1 = B.Fld7
And A.Fld7 > <from-date> 
AND A.Fld7 < <to-date>
AND A.Fld5 < <from-date> -- Excluding these to avoid duplicates
and A.Fld5 > <to-date> -- Excluding these to avoid duplicates
UNION ALL
Select DISTINCT B.Fld1, B.Fld2, B.Fld3, B.Fld4,
A.Fld1, A.Fld2, A.Fld3, A.Fld4, A.Fld5, A.Fld6, A.Fld7, A.Fld8, A.Fld9
From TableA A, TableB B
Where A.Fld2 = B.Fld5
And A.Fld1 = B.Fld7
AND A.Fld5 > <from-date> 
and A.Fld5 < <to-date>
于 2012-04-18T20:01:06.760 回答
0

根据给定的 SELECT 语句,您希望从 TableA 开始查询,因为您希望根据 Fld7 和 Fld5 中的日期/时间戳值获取条目。首先,您希望对这两列进行索引。两者都需要有自己的索引。

您应该首先检查从 TableA 获取数据的性能。您可以通过执行 SELECT 语句来做到这一点:

SELECT COUNT(*)
  FROM TableA
 WHERE 
   (A.Fld7 BETWEEN <from-date> and <to-date>) OR
   (A.Fld5 BETWEEN <from-date> and <to-date>)

如果这已经没有足够的性能,那么问题出在 TableA 索引上。您还可以考虑将其他具有 INCLUDE 定义的列添加到这些索引中。可能至少有用于加入 TableB 的字段 Fld1 和 Fld2。

一旦您对 TableA 有足够的性能,您需要使其有效地加入到 TableB。A.Fld1 = B.Fld6 || B.Fld7看起来很有问题。 我希望这B.Fld5在 TableB 中是相对独特的,在这种情况下,您在 TableB 中有 Fld5 的索引就足够了。A.Fld1 检查将在 join 中只是为了消除您通过 join 获得的少量行A.Fld2 = B.Fld5

如果 B.Fld5 不是相对唯一的,那么您遇到了问题:) 在这种情况下,您可以尝试在连接中使用类似的东西:

SELECT ... 
FROM TableA A, TableB B
WHERE
   A.Fld2 = B.Fld5 AND
   SUBSTR(A.Fld1, 1, N) = B.Fld6 AND
   A.Fld1 = B.Fld6 || B.Fld7
...

想法是,您不要从 TableB 行中查找在连接时与 A.Fld1 匹配的行,而是从 A.Fld1 中获取一个子字符串,以便它与 B.Fld6 匹配。之后,您需要确保 B.Fld6 具有正确的索引,并且在 TableB 中也是真正唯一的。您显然可以将其扩展为对 B.Fld7 应用相同的模式,即:

SELECT ... 
FROM TableA A, TableB B
WHERE
   A.Fld2 = B.Fld5 AND
   SUBSTR(A.Fld1, 1, N) = B.Fld6 AND
   SUBSTR(A.Fld1, N, LENGTH(A.Fld1)) = B.Fld7
...

在上面的 JOIN 中,为 TableB 设置以 B.Fld5、B.Fld6 和 B.Fld7 中最具选择性的值开头的索引可能就足够了。

HTH。

于 2012-04-18T20:06:03.160 回答
0

尝试这个

Select DISTINCT B.Fld1, B.Fld2, B.Fld3, B.Fld4,
A.Fld1, A.Fld2, A.Fld3, A.Fld4, A.Fld5, A.Fld6, A.Fld7, A.Fld8, A.Fld9
From 
(
select * from TableA where ((Fld7 BETWEEN <from-date> and <to-date>)
Or (Fld5 BETWEEN <from-date> and <to-date>))
) A, 
TableB B
Where A.Fld2 = B.Fld5
And A.Fld1 = B.Fld6 || B.Fld7

和这个

Select DISTINCT c.Fld1, c.Fld2, c.Fld3, c.Fld4,
c.Fld1, c.Fld2, c.Fld3, c.Fld4, c.Fld5, c.Fld6, c.Fld7, c.Fld8, c.Fld9
From 
(
select * from TableA A, TableB B
Where A.Fld2 = B.Fld5
And A.Fld1 = B.Fld6 || B.Fld7
)c
where ((c.Fld7 BETWEEN <from-date> and <to-date>)
Or (c.Fld5 BETWEEN <from-date> and <to-date>))

希望至少其中一个会更快。

编辑

在这里,连接是瓶颈或由于日期比较而导致的表扫描是问题所在。所以想法是首先提取所需的行,然后通过连接或日期比较进一步处理它们。这将限制没有。需要处理的总行数,而不是处理整个行表。

于 2012-04-18T20:19:55.860 回答
0

您可能会尝试的一件事是在 where 子句中的每个子句周围加上括号。代替:

Where A.Fld2 = B.Fld5 And A.Fld1 = B.Fld6 || B.Fld7 And ((A.Fld7 BETWEEN <from-date> and <to-date>) Or (A.Fld5 BETWEEN <from-date> and <to-date>)) 

Where (A.Fld2 = B.Fld5) And ((A.Fld1 = B.Fld6) || B.Fld7) And ((A.Fld7 BETWEEN <from-date> and <to-date>) Or (A.Fld5 BETWEEN <from-date> and <to-date>))

问题是 || 的优先级 操作员。如果它与 AND 相同,那么您实际上是在执行以下操作:

WHERE (A.Fld2 = B.fld5) or B.fld7

“或”的优先级在 AND 之后,这会导致交叉连接。. . 那会有非常糟糕的表现。

于 2012-04-18T20:41:03.613 回答