【问题标题】:Why does separate table perform significantly better than subquery?为什么单独的表执行得比子查询好得多?
【发布时间】:2017-03-15 02:30:43
【问题描述】:

我试图提高 SQL 查询的性能并尝试了几种组合。

原始查询

SELECT ALIAS_A.id1, 
       ALIAS_A.id2, 
       ALIAS_B.columnA, 
       ALIAS_C.columnB, 
       ALIAS_B.columnC 
FROM   db_A.table_A ALIAS_A 
       LEFT OUTER JOIN db_A.table_B ALIAS_B 
                    ON ALIAS_A.id2 = ALIAS_B.id2 
       LEFT OUTER JOIN db_B.table_C ALIAS_C 
                    ON ALIAS_B.columnA = ALIAS_C.item_num 
       LEFT OUTER JOIN db_A.table_D ALIAS_D 
                    ON ALIAS_A.id2 = ALIAS_D.id2 
       INNER JOIN db_C.table_E ALIAS_E 
               ON Cast(ALIAS_A.column_date AS DATE) BETWEEN 
                  ALIAS_E.column_startdate AND ALIAS_E.column_enddate 
WHERE  ALIAS_E.fiscalyear >= 2016 
       AND Cast(ALIAS_A.columnD AS DATE) BETWEEN 
           CURRENT_DATE - 5 AND CURRENT_DATE 

以上查询消耗近400k ImpactCPU

优化查询 1

SELECT New_sub_table.id1, 
       New_sub_table.id2, 
       ALIAS_B.columnA, 
       ALIAS_C.columnB, 
       ALIAS_B.columnC 
--changed part start--
FROM   ( sel * from db_A.table_A ALIAS_A WHERE Cast(ALIAS_A.columnD AS DATE) BETWEEN 
           CURRENT_DATE - 5 AND CURRENT_DATE ) New_sub_table -- created a subquery 
--changed part end--
       LEFT OUTER JOIN db_A.table_B ALIAS_B 
                    ON New_sub_table.id2 = ALIAS_B.id2 
       LEFT OUTER JOIN db_B.table_C ALIAS_C 
                    ON ALIAS_B.columnA = ALIAS_C.item_num 
       LEFT OUTER JOIN db_A.table_D ALIAS_D 
                    ON New_sub_table.id2 = ALIAS_D.id2 
       INNER JOIN db_C.table_E ALIAS_E 
               ON Cast(New_sub_table.column_date AS DATE) BETWEEN 
                  ALIAS_E.column_startdate AND ALIAS_E.column_enddate 
WHERE  ALIAS_E.fiscalyear >= 2016 

我想先过滤数据,然后再进行连接。在我检查了性能统计数据之后。它消耗了近 390k CPU。差别不大。

优化查询 2

SELECT ALIAS_A.id1, 
       ALIAS_A.id2, 
       ALIAS_B.columnA, 
       ALIAS_C.columnB, 
       ALIAS_B.columnC 
--changed part start--
FROM   INTERMEDIATE_DB.INTERMEDIATE_TABLE ALIAS_A --CREATED AN INTERMEDIATE TABLE
--changed part end--
       LEFT OUTER JOIN db_A.table_B ALIAS_B 
                    ON ALIAS_A.id2 = ALIAS_B.id2 
       LEFT OUTER JOIN db_B.table_C ALIAS_C 
                    ON ALIAS_B.columnA = ALIAS_C.item_num 
       LEFT OUTER JOIN db_A.table_D ALIAS_D 
                    ON ALIAS_A.id2 = ALIAS_D.id2 
       INNER JOIN db_C.table_E ALIAS_E 
               ON Cast(ALIAS_A.column_date AS DATE) BETWEEN 
                  ALIAS_E.column_startdate AND ALIAS_E.column_enddate 
WHERE  ALIAS_E.fiscalyear >= 2016 

将数据加载到中间表的宏

INSERT INTO INTERMEDIATE_DB.INTERMEDIATE_TABLE
sel * from db_A.table_A ALIAS_A WHERE Cast(ALIAS_A.columnD AS DATE) BETWEEN 
           CURRENT_DATE - 5 AND CURRENT_DATE

所以我在这里所做的是。我使用了中间表而不是子查询。中间表首先通过宏加载,然后选择查询运行。它现在只消耗 50k ImpactCPU(对于 Macro 和 Select 查询的组合)。

我的问题 - 即使两个查询背后的逻辑相同(或者我认为是),我也无法解释为什么会发生这种情况。如果这是不正确的方式,最佳做法是什么?

【问题讨论】:

  • 添加执行计划,我们有话要说。同时,一个疯狂的猜测 - 请在原始查询中添加option(hash) 并检查性能。

标签: sql performance teradata


【解决方案1】:

您的主要问题是Cast(ALIAS_A.columnD AS DATE)。当您检查 Explains 时,您会注意到优化器对这一步没有信心,可能大大高估了返回的行数。

但是当您实现 Select 时,行数会更清楚,并且连接的顺序会发生变化。

当您在 Cast(ALIAS_A.columnD AS DATE) 上收集统计信息、运行 DIAGNOSTIC HELPSTATS ON FOR SESSION; 时,您可能会得到相同的计划,并且 Explain 应该将其显示为 推荐的统计信息

【讨论】:

  • 谢谢dnoeth,我会检查解释计划并恢复。此外,CAST(ALIAS_A.TIMESTAMP as DATE)的任何替换。这是一种日期时间格式。
  • @PirateX:实际的数据类型是什么?如果它是时间戳,您可以使用ALIAS_A.columnD BETWEEN Cast(CURRENT_DATE - 5 AS TIMESTAMP) AND Cast(CURRENT_DATE+1 AS TIESTAMP) 避免强制转换。如果它是 Char/Int,则没有解决方法。第二个不好的部分是使用之间的连接,我不知道你的表,但看起来你加入日历以每天返回一行在范围内。这可以使用 Teradata 专有的EXPAND ON 语法来解决。
  • 是的,它是TIMESTAMP(6)。你能详细说明EXPAND ON吗?
  • 我检查了双方的信心,他们都没有信心,但表一估计的行数与子查询完全不同。
  • @PirateX:那一栏有统计数据吗?您是否运行了诊断程序?由于数字不同,连接顺序应该不同。
猜你喜欢
  • 2010-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-17
  • 2018-12-10
  • 2017-06-17
相关资源
最近更新 更多