【问题标题】:Need help tuning query - left join using concatenated fields not efficient需要帮助调整查询 - 使用连接字段的左连接效率不高
【发布时间】:2014-06-15 19:29:31
【问题描述】:

我编写了一个查询,在该查询中从总体中过滤掉记录,其中嵌套查询中的 2 个字段的值等于表中的 2 个对应字段。我正在尝试使用 2 个关键字段的串联作为查找。

虽然这确实让我得到了我正在寻找的结果,但这种方法似乎效率很低,因为查询需要大约 60 秒才能返回结果(CRM.ASSET_PLUS 表有超过 10M 的记录)。假设我无法过滤掉任何内容,并且没有在 CRM.ASSET_PLUS 中创建自定义字段,并且这两个字段已经连接。

有没有更好的方法可以做到这一点?

SELECT DISTINCT A.ACCOUNT_NUMBER
  FROM (SELECT C.ACCOUNT_NUMBER,
               A.LOCATION_ACCOUNT_ID || A.PRODUCT_ID AS LOOKUP
          FROM CRM.ASSET_PLUS A,
               CRM.PROD_INT B,
               CRM.ACCOUNT C,
               CRM.ACCOUNT D
         WHERE A.PRODUCT_ID = B.ROW_ID
           AND A.LOCATION_ACCOUNT_ID = C.ACCOUNT_ID
           AND C.PARENT_ID = D.ACCOUNT_ID
           AND D.ACCOUNT_NUMBER = '00750333'
       ) A
   LEFT JOIN (SELECT A.LOCATION_ACCT_ID || A.PRODUCT_ID AS LOOKUP
                FROM ORDER_FORM_PRODUCTS A
               WHERE A.AGREEMENT_NUM = '00750333_JUN2014'
             ) B
     ON A.LOOKUP = B.LOOKUP
  WHERE B.LOOKUP IS NULL;

【问题讨论】:

  • LEFT JOIN(SELECT ...) B WHERE B.xxx IS NULL 等同于 NOT EXISTS(...)

标签: sql oracle query-optimization


【解决方案1】:

尝试连接多个字段,而不是连接

SELECT DISTINCT
    A.ACCOUNT_NUMBER
FROM 
    CRM.ASSET_PLUS A,
    CRM.PROD_INT B,
    CRM.ACCOUNT C,
    CRM.ACCOUNT D
LEFT JOIN ORDER_FORM_PRODUCTS E 
    ON (E.LOCATION_ACCOUNT_ID = A.LOCATION_ACCOUNT_ID
       OR (E.LOCATION_ACCOUNT_ID IS NULL AND A.LOCATION_ACCOUNT_ID IS NULL))
    AND (E.PRODUCT_ID = A.PRODUCT_ID 
        OR (E.PRODUCT_ID IS NULL AND A.PRODUCT_ID IS NULL))
    AND E.AGREEMENT_NUM = '00750333_JUN2014'
WHERE 
    A.PRODUCT_ID = B.ROW_ID 
    AND A.LOCATION_ACCOUNT_ID = C.ACCOUNT_ID
    AND C.PARENT_ID = D.ACCOUNT_ID
    AND D.ACCOUNT_NUMBER = '00750333'
    AND E.LOCATION_ACCOUNT_ID IS NULL
    AND E.PRODUCT_ID IS NULL

为了清楚起见,我建议您明确加入

SELECT DISTINCT
    A.ACCOUNT_NUMBER
FROM 
    CRM.ASSET_PLUS A
    JOIN CRM.PROD_INT B ON A.PRODUCT_ID = B.ROW_ID
    JOIN CRM.ACCOUNT C ON A.LOCATION_ACCOUNT_ID = C.ACCOUNT_ID
    JOIN CRM.ACCOUNT D ON C.PARENT_ID = D.ACCOUNT_ID
        AND D.ACCOUNT_NUMBER = '00750333'
    LEFT JOIN ORDER_FORM_PRODUCTS E 
       ON (E.LOCATION_ACCOUNT_ID = A.LOCATION_ACCOUNT_ID
         OR (E.LOCATION_ACCOUNT_ID IS NULL AND A.LOCATION_ACCOUNT_ID IS NULL))
       AND (E.PRODUCT_ID = A.PRODUCT_ID 
         OR (E.PRODUCT_ID IS NULL AND A.PRODUCT_ID IS NULL))
       AND E.AGREEMENT_NUM = '00750333_JUN2014'
WHERE 
    E.LOCATION_ACCOUNT_ID IS NULL
    AND E.PRODUCT_ID IS NULL

【讨论】:

  • 这不会产生相同的结果。 E.LOCATION_ACCOUNT_ID 不为空且 E.PRODUCT_ID 为空的记录会被过滤掉(反之亦然)。我只需要过滤 E.PRODUCT_ID 和 E.LOCATION_ACCOUNT_ID 均为空的记录。
  • @StephenT 更新为使用IS NOT DISTINCT FROM加入
  • @StephenT 我实际上不确定oracle是否允许IS NOT DISTINCT FROM,所以我将其替换为在OR中加入NULL
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 2012-04-09
  • 2012-02-28
  • 1970-01-01
  • 2011-07-02
  • 1970-01-01
相关资源
最近更新 更多