【问题标题】:SQL Statement Performance Issue on InformixInformix 上的 SQL 语句性能问题
【发布时间】:2011-07-01 22:12:17
【问题描述】:

我有这个需要很长时间才能运行的 Informix SQL 语句。有没有人看到任何优化它的方法,所以它不会花这么长时间?

SELECT * FROM OriginalTable WHERE type = 'S' AND flag <> 'S' INTO TEMP TempTableA;

SELECT * FROM OriginalTable WHERE type = 'Z' AND flag <> 'S' INTO TEMP TempTableB;

UPDATE OriginalTable SET flag = 'D' WHERE Serialnumber in
(
select Serialnumber from TempTableA
WHERE NOT EXISTS(SELECT * FROM TempTableB
               WHERE TempTableB.Col1 = TempTableA.Col1
                 AND TempTableB.Col2 = TempTableA.Col2)
) 

我的 OriginalTable 中有大约 3 亿行,TempTableA 有 93K 行,TempTableB 有 58K 行。

【问题讨论】:

  • 你应该解释你的查询意图
  • 我需要将 OriginalTable 中所有集合的标志更改为 TemptableB 中不存在具有相等 Col1 和 Col2 的条目

标签: sql optimization query-optimization informix


【解决方案1】:
Update OriginalTable 
Set flag = 'D' 
Where Type = 'S'
    And Flag <> 'S'
    And Not Exists  (
                    Select 1
                    From OriginalTable As T1
                    Where T1.Type = 'Z'
                        And T1.flag <> 'S'
                        And T1.Col1 = OriginalTable.Col1
                        And T1.Col2 = OriginalTable.Col2
                    )

【讨论】:

  • 我承认在阅读您的答案后感到失望,因为它非常简单,我确信我会面临与现在相同的性能问题!但我没有。它工作得很好,真的比我预期的要好得多。非常感谢。
  • 就像 Info 一样无法修改子查询中使用的表/视图,所以我不得不再次将结果保存到 TempTable 并在单独的步骤中进行更改。
【解决方案2】:

我懒得用测试数据进行测试,但也许这可以做到?

SELECT col1, col2, 
CASE WHEN type = 'S' THEN 1 
ELSE WHEN type = 'Z' THEN 2 END AS filteredType 
FROM OriginalTable WHERE (type = 'S' OR type = 'Z') AND flag <> 'S' INTO TempTable;

UPDATE OriginalTable SET flag = 'D' WHERE Serialnumber IN
(
SELECT t1.Serialnumber FROM TempTable t1
LEFT JOIN TempTable t2 ON (t1.col1 = t2.col2 AND t1.col2 = t2.col2)
WHERE t1.filteredType = 1
AND t2.filteredType = 2 
AND t2.Serialnumber IS NULL
)

这样你可以省略一个加载到临时表中。另一方面,新列filteredType上将没有索引。

我也不知道informix。无论如何,希望它有所帮助。

【讨论】:

    【解决方案3】:

    采用与@tombom 所述类似的方法。仅预查询您关心的列以保持临时表更小。如果您正在处理一个有 60 列的表,那么您填写的不仅仅是 3-4 列,您的主要考虑因素是有效的序列号。预先测试查询以确保它为您提供了您期望的正确集合,然后将其应用于您的 SQL 更新。

    因此,在这里,内部查询是您不想要的查询...由于您仅与该表中的第 1 列和第 2 列进行比较,这就是我要预先查询的全部内容。然后我在 COL1 和 COL2 上对这个内部结果集进行 LEFT JOIN。我知道,你想排除在这个结果集中找到的那些......这就是为什么在 OUTER WHERE 子句中,我添加了“AND ExcludeThese.Col1 IS NULL”。因此,OT1 中从未存在于子查询中的任何实例都可以使用(通过左连接),并且那些已找到的实例将在 col1 和 col2 上匹配,但这些将通过“and”子句排除已经描述过了。

    SELECT OT1.SerialNumber
        FROM OriginalTable OT1
            LEFT JOIN ( select OT2.Col1,
                               OT2.Col2
                           FROM OriginalTable OT2
                           where OT2.type = 'Z' 
                             AND OT2.flag <> 'S' ) ExcludeThese
               ON OT1.Col1 = ExcludeThese.Col1
              AND OT1.Col2 = ExcludeThese.Col2
        WHERE  OT1.type = 'S' 
           AND OT1.flag <> 'S'
           AND ExcludeThese.Col1 IS NULL
        ORDER BY
           OT1.SerialNumber
        INTO 
           TEMP TempTableA;  
    

    同样,请自行测试此查询,以确保您获得了预期的记录。为了帮助澄清返回的记录,请更改上述选择以包含更多用于心理/健全性检查的列,例如

    SELECT OT1.SerialNumber,
           OT1.Col1,
           OT1.Col2,
           ExcludeThese.Col1 JoinedCol1,
           ExcludeThese.Col2 JoinedCol2
      from  <keep rest of query intact>
    

    现在,您将能够看到那些将或不会加入“excludeThese”结果集的列的序列号和实例...再试一次,但只删除 “AND ExcludeThese.Col1 IS NULL”子句,您会看到其他行以及它们被排除在外的原因——也就是说,如果您对内容有任何疑问。

    一旦您对预查询感到满意...它只会返回 SerialNumber 的单列,因为您要拉入临时表,构建索引,然后应用更新,所以可以对其进行索引/优化。

    UPDATE OriginalTable 
       SET flag = 'D' 
       WHERE Serialnumber in ( select Serialnumber from TempTableA  );
    

    【讨论】:

    • 您好,谢谢您的回答,我不确定语法是否与informix 兼容,我面临着严重的语法问题。例如,当您有“where”部分时,表别名在 informix 中不起作用。与加入相同,这迫使我使用临时表。因此,当我将 Excludethese 作为一个 temptable 提取时,我仍然无法运行具有 OUTER WHERE 部分的连接。我会尝试为表别名打开一个新线程,尽管我想这不会有帮助。
    猜你喜欢
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2011-04-23
    • 1970-01-01
    • 2010-09-25
    相关资源
    最近更新 更多