【问题标题】:Extremely large query giving performance issues非常大的查询会导致性能问题
【发布时间】:2014-12-04 13:33:32
【问题描述】:
SELECT COUNT(*)
FROM TABLE1
WHERE COLUMN1='x1'
AND COLUMN2  ='Y1'
AND COLUMN3  = 'Z1'
AND COLUMN4  ='N1'
UNION ALL
SELECT COUNT(*)
FROM TABLE1
WHERE COLUMN1='x1'
AND COLUMN2  ='Y1'
AND COLUMN3  = 'Z1'
AND COLUMN4  ='N2' 
UNION ALL...

数值如下:

X1 Y1 Z1 N1 : X1 Y1 Z1 N2 : ....

那么,

X1 Y1 Z2 N1 : X1 Y1 Z2 N2 : ....

然后

X1 Y2 Z1 N1 : X1 Y2 Z2 N2 : ....

然后

X2 Y1 Z1 N1 :.... 整个过程不断重复。

形成 100 到 200 的 UNION ALLS。 我需要做的就是检查表中是否存在组合(COL1,COL2,COL3,COL4)(如果不存在,Count 将返回 0)。

我知道这是编写查询的一种非常糟糕的方式,但我是新手。所以请帮忙。 谢谢

【问题讨论】:

    标签: sql performance oracle10g


    【解决方案1】:

    您可以使用WHERE 子句来处理公共部分。然后使用 CASE 语句隐藏在 SUM 语句中的 column4 部分:

    SELECT 
      SUM(CASE WHEN COLUMN4 = 'N1' THEN 1 ELSE 0 END) AS N1Count,
      SUM(CASE WHEN COLUMN4 = 'N2' THEN 1 ELSE 0 END) AS N2Count
    FROM TABLE1
    WHERE COLUMN1 = 'x1'
      AND COLUMN2 = 'Y1'
      AND COLUMN3 = 'Z1'
    

    这将阻止所有这些单独的 SELECT 语句的运行。

    确保您在 COLUMN1COLUMN2COLUMN3COLUMN4 上有索引也会有所帮助。

    编辑 1:

    SELECT
      SUM(CASE WHEN
        COLUMN1 = 'X1' AND COLUMN2 = 'Y1' AND COLUMN3 = 'Z1' AND COLUMN4 = 'N1'
        THEN 1 ELSE 0 END) AS Count1,
      SUM(CASE WHEN
        COLUMN1 = 'X1' AND COLUMN2 = 'Y1' AND COLUMN3 = 'Z1' AND COLUMN4 = 'N2'
        THEN 1 ELSE 0 END) AS Count2,
      SUM(CASE WHEN
        COLUMN1 = 'X1' AND COLUMN2 = 'Y2' AND COLUMN3 = 'Z1' AND COLUMN4 = 'N1'
        THEN 1 ELSE 0 END) AS Count3,
      SUM(CASE WHEN
        COLUMN1 = 'X1' AND COLUMN2 = 'Y2' AND COLUMN3 = 'Z2' AND COLUMN4 = 'N2'
        THEN 1 ELSE 0 END) AS Count4,
      SUM(CASE WHEN
        COLUMN1 = 'X2' AND COLUMN2 = 'Y1' AND COLUMN3 = 'Z1' AND COLUMN4 = 'N1'
        THEN 1 ELSE 0 END) AS Count5,
      AND ETC.....
    FROM TABLE1
    

    编辑 2:

    您可以创建另一个表来保存 COLUMN1COLUMN2COLUMN3COLUMN4 的所有不同变体。然后 JOIN 到该表并使用 GROUP BY 像这样:

    SELECT tt.COLUMN1, tt.COLUMN2, tt.COLUMN3, tt.COLUMN4, 
      CASE WHEN t1.COLUMN1 IS NULL THEN 0 ELSE COUNT(1) END AS RecCount
    FROM TABLE1 t1
      RIGHT JOIN TempTable tt ON tt.COLUMN1 = t1.COLUMN1, tt.COLUMN2 = t1.COLUMN2, 
                                 tt.COLUMN3 = t1.COLUMN3, tt.COLUMN4 = t1.COLUMN4
    GROUP BY tt.COLUMN1, tt.COLUMN2, tt.COLUMN3, tt.COLUMN4
    

    【讨论】:

    • @Leocode,您已经完全改变了查询的复杂性。我已经编辑了我的答案,展示了如何完成你想要的。
    • 您提供的查询将返回数千列,因为表中的记录非常高。谢谢。
    • @Leocode,这不是你想要的吗?它也应该跑得更快,对吧?
    • 如果它们是行,我可以使用它。如果可以在 ORACLE 中使用的列数是有限的(我认为是 1000)。 :)
    • @Leocode,我再次编辑我的答案给你另一个选择。
    【解决方案2】:

    为什么会有这么多UNION ALL 声明?我只看到谓词中的 column4 值发生了变化。

    尝试WHERE EXISTS 用于第 4 列。并确保您对where 子句中列出的列具有所需的索引。注意索引中的leading column

    通常,开发人员会为所有要比较的值编写IN list。但是,它效率不高,因为将针对 IN 列表中的每个值扫描table

    此外,如果前三列的 DML 没有频繁更改,则创建一个 PARTITION 以将这些值存储在该分区中。

    并且,对于任何性能调优问题,请始终提供执行计划和元数据信息。这有助于我们更好地了解您的问题。

    【讨论】:

    • 好的,我看到了你修改后的问题。现在您有两列具有不同的值,这意味着查询谓词中的两列具有不同值的多个条件。因此,正如我在回答中建议的那样,现在也包括另一列。
    • 实际上所有 4 列都不同。
    • 那又怎样?对所有列使用相同的建议。是什么阻止了你至少尝试?如果您发现任何困难,我很乐意为您提供帮助。但是,请先尝试让我知道。
    猜你喜欢
    • 2022-11-18
    • 2018-10-29
    • 1970-01-01
    • 2017-12-10
    • 2011-10-27
    • 1970-01-01
    • 2011-02-04
    • 2013-04-01
    • 1970-01-01
    相关资源
    最近更新 更多