SQL-有问题或破坏子句的查询时间

SQL-有问题或破坏子句的查询时间,sql,db2,clause,Sql,Db2,Clause,我正在为登录页做一些查询。此页面将为用户提供多种搜索选项。查询将根据用户选择的内容从不同的部分构造,并发送到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 v

我正在为登录页做一些查询。此页面将为用户提供多种搜索选项。查询将根据用户选择的内容从不同的部分构造,并发送到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)
字段2和3被选中,而其他字段仅被过滤。字段5用于联接,但与子查询的筛选无关。问题来自(X或Y)条款。按照现在的状态执行查询大约需要3秒钟。如果我删除OR子句中的任一条件,它将在不到十分之一的时间内执行。奇怪的是,删除它们都会使其返回3秒左右,这没有多大意义,因为它似乎不会使数据集的大小增加那么多。带OR子句或不带这两个条件的explain计划几乎是相同的,但它似乎不是索引问题,因为它似乎在相关表上碰到了相同的索引。在这两种情况下,最大的成本都来自最外层的NLJOIN。从OR子句中删除一个条件(因此它只是一个AND),解释计划将发生显著变化,从而降低了bigtime的成本,并显著改变了结构,尽管使用了相同的相关索引


我曾经尝试过使用子查询和联合来解决这个问题,甚至在两个查询之间使用一个仅在该子句上区分的联合(这确实对这个实例有一点帮助,但显著地降低了其他查询的速度),但似乎对执行时间没有任何帮助。我真的不能发布完整的细节,因为查询量相当大,但希望这足以让人理解这个想法。我知道OR子句有时会使优化器陷入循环,因此我想关于避免出现问题的OR子句或将优化器推向更好的方向的一般建议会非常有用,即使它不是直接针对本例的。

您可以尝试使用
case
语句

而不是

AND ( A.FIELD3 IN ('ONE', 'TWO') 
 OR (A.FIELD3 IN ('THREE','FOUR') AND A.FIELD4 BETWEEN :x AND :y))
使用


这可能看起来很极端,但你可以将两个快速版本结合在一起。。。有这条线的

AND A.FIELD3 IN ('ONE', 'TWO') 
还有一个

A.FIELD3 IN ('THREE','FOUR') AND A.FIELD4 BETWEEN :x AND :y)
尝试:


我试过这一个和工会所有。在这种情况下,它确实有所帮助,但其他查询的性能受到了影响。不幸的是,其结果是性能净下降。这是一个很好的简化(这使得第一个FIELD3筛选器没有意义,因为in子句将包含列中的所有值),但不幸的是,它似乎没有改变解释计划或执行时间。成功!这大大缩短了几个查询的执行时间,而其他查询基本上不受影响。它可能稍微增加了一些其他的执行时间,但它在一位数的百分比范围内(这并不假设它在误差范围内),所以它肯定是一个整体收益。谢谢你,先生,你是一位绅士和学者!
A.FIELD3 IN ('THREE','FOUR') AND A.FIELD4 BETWEEN :x AND :y)
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)