【问题标题】:DB2 Inner Query slow but fast with hardcoded valuesDB2 内部查询速度慢但使用硬编码值快速
【发布时间】:2013-06-03 13:53:00
【问题描述】:

我在 DB2 sql 中遇到了一个奇怪的行为。 (DB2 9.7) 以下是获取员工工资、状态和乐队的示例查询。

SELECT
                EMP.STATUS,
                COUNT(*)               AS EMP_COUNT,
                GRP.GROUP_NAME
FROM
                EMPLOYEE EMP,
                EMPLOYEE_SALARY ES,
                GROUP_TABLE GRP
WHERE
                EMP.SALARY > 
                             (select max(EMP1.SALARY) from  
                             EMPLOYEE EMP1, FINANCIAL_YEAR FY where 
                              date(EMP1.JOIN_DT) = '2013-01-01' 
                              and date(EMP1.DATE_TS) = date(FY.CURRENT_DT) - 2 days)
                AND EMP.SALARY = E.EMPID
                AND E.SALARY_GRP = GRP.BAND_GROUP
                AND GRP.RANGE_SALARY = 'BAND-10'
                GROUP BY
                        EMP.STATUS,
                        GRP.GROUP_NAME

EMP(员工)表包含大约 100 万行。其余的桌子都很小。 执行查询大约需要 10 秒

但是当我对内部查询进行硬编码时

来自

select max(EMP1.SALARY) from  EMPLOYEE EMP1, FINANCIAL_YEAR FY where 
        date(EMP1.JOIN_DT) = '2013-01-01' 
        and date(EMP1.DATE_TS) = date(FY.CURRENT_DT) - 2 days

到

select max(EMP1.SALARY) from  EMPLOYEE EMP1, FINANCIAL_YEAR FY where 
       date(EMP1.JOIN_DT) = '2013-01-01' 
       and date(EMP1.DATE_TS) = '2013-06-01' 

结果在一秒钟内出现!!

“FINANCIAL_YEAR FY”表是一个非常小的表,大约有 50 行,因此我不知道为什么内部查询在动态时需要时间,但在我硬编码时非常快

一些附加信息

  • EMPID 是整数
  • DATE_TS 是时间戳
  • CURRENT_DT,JOIN_DT 是日期
  • 其余都是 VARCHAR
  • EMPID 已编入索引

【问题讨论】:

  • EMP1.JOIN_DT、EMP1.DATE_TS 和FY.CURRENT_DT 的数据类型是什么?什么是示例值? (问题的原因是在要加入的字段上调用函数 DATE,这样做会破坏使用索引的能力。)
  • @Dems 我最初也想过。但是当我硬编码时它完全一样吗? FY.CURRENT_DT 如果单独查询将在毫秒内到达。
  • 您看过访问计划吗?它说什么?
  • 将执行计划粘贴到您的问题中。我认为内部 SELECT 语句必须每行执行一次。这无疑是性能杀手。
  • DB2 优化器可能能够在您进行硬编码时“作弊”,通过替换范围查询(现在,看,我不知道它是否实际上可以)。

标签: sql performance db2


【解决方案1】:

你可以试试这个版本(我假设 E 引用应该是 ES 别名,否则语句不应该运行)。除此之外,您应该放弃“隐式连接”(逗号分隔的FROM 子句),尤其是当您开始处理LEFT JOINs 时。

WITH Maximum_Salary (max) as (SELECT MAX(EMP.SALARY) 
                              FROM EMPLOYEE EMP
                              JOIN FINANCIAL_YEAR FY
                                ON (FY.CURRENT_DT - 2 DAYS) >= EMP.DATE_TS
                                   AND (FY.CURRENT_DT - 1 DAYS) < EMP.DATE_TS
                              WHERE EMP.JOIN_DT = DATE('2013-01-01')

SELECT EMP.STATUS, COUNT(*) AS EMP_COUNT, GRP.GROUP_NAME
FROM EMPLOYEE EMP
JOIN GROUP_TABLE GRP
  ON GRP.RANGE_SALARY = 'BAND-10'
JOIN EMPLOYEE_SALARY ES
  ON ES.EMPID = EMP.SALARY
     AND ES.SALARY_GRP = GRP.BAND_GROUP
JOIN Maximum_Salary 
  ON Maximum_Salary <= EMP.SALARY
GROUP BY EMP.STATUS, GRP.GROUP_NAME

如果您还不习惯它们,WITH 语法是一个公用表表达式(或 CTE)——实际上,它是一个内联视图。在某些情况下,这些可以导致创建临时表,但否则可以为您节省大量输入(它们也是执行递归查询的方式)。我已经设法将EMP.DATE_TS 的引用转换为可以使用索引的表单(FY.CURRENT_DT 上的日期数学没有帮助,尽管作为一个不重要的小表)。

请注意,您可能仍需要执行额外的调整,尤其是取决于您可能(没有)拥有的索引。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多