我正在处理着陆页的一些查询。此页面将为用户提供各种搜索选项。查询将根据用户选择的内容和激发到DB2数据库的各个部分构建。总而言之,有超过100个独特的查询。我正在努力降低性能,而且我有一个时间太长了。因此基本结构是:
SELECT ...
FROM
TABLE A
--A few joins and a few left joins--
WHERE A.FIELD1 IS NOT NULL
AND A.FIELD2 IN (:parameter) --No more than two values in here
AND (
A.FIELD3 IN ('ONE', 'TWO')
OR (A.FIELD3 IN ('THREE','FOUR') AND A.FIELD4 BETWEEN :x AND :y)
)
AND A.FIELD5 IN (uncorrelated subquery, potentially returns over 1k values, usually less)
选择FIELD2和3,而仅过滤其他的FIELD2和3。 FIELD5用于连接,但这与使用子查询的过滤无关。问题来自(X OR Y)子句。查询大约需要3秒才能执行。如果我删除OR子句中的任何一个条件,它将在不到十分之一的时间内执行。奇怪的是,删除它们都会使它恢复大约3秒,这没有多大意义,因为它似乎没有那么多地增加数据集的大小。带有OR子句或没有两个条件的解释计划几乎相同,但它似乎不是索引问题,因为它似乎在相关表上遇到相同的索引。在这两种情况下,最大的成本来自最外面的NLJOIN。从OR子句中删除一个条件(因此它只是一个AND)并且解释计划发生了显着变化,尽管使用了相同的相关索引,但显着降低了成本并显着改变了结构。
我尝试使用子查询和联合解决这个问题,甚至在两个只区分该子句的查询之间使用UNION ALL(这确实对这个实例有所帮助,但显着减慢了其他查询),但似乎没有帮助执行时间。由于查询非常庞大,我无法发布完整的详细信息,但希望这足以让我们了解这个想法。我知道OR子句有时可以将优化器抛出一个循环,所以我猜想避免有问题的OR子句或将优化器推向更好的方向的一般建议将非常受欢迎,即使它不直接特定于这个例子。
答案 0 :(得分:1)
您可以尝试使用case
语句。
而不是
AND ( A.FIELD3 IN ('ONE', 'TWO')
OR (A.FIELD3 IN ('THREE','FOUR') AND A.FIELD4 BETWEEN :x AND :y))
使用
AND CASE WHEN A.FIELD3 IN ('ONE', 'TWO') THEN 1
WHEN A.FIELD3 IN ('THREE','FOUR') AND A.FIELD4 BETWEEN :x AND :y THEN 1 ELSE 0 END = 1
答案 1 :(得分:0)
它可能看起来很极端,但你可以将两个快速版本结合在一起......一个用这一行
AND A.FIELD3 IN ('ONE', 'TWO')
和一个
A.FIELD3 IN ('THREE','FOUR') AND A.FIELD4 BETWEEN :x AND :y)
答案 2 :(得分:0)
尝试:
SELECT ...
FROM
TABLE A
--A few joins and a few left joins--
WHERE A.FIELD1 IS NOT NULL
AND A.FIELD2 IN (:parameter)
AND A.FIELD3 IN ('ONE', 'TWO', 'THREE', 'FOUR')
AND (A.FIELD3 IN ('ONE', 'TWO') OR A.FIELD4 BETWEEN :x AND :y)
AND A.FIELD5 IN (uncorrelated subquery)