【问题标题】:Query Syntax in Oracle11GOracle11G 中的查询语法
【发布时间】:2021-10-22 22:20:54
【问题描述】:

我有一个要在 Oracle 中执行的查询,由于数据量大,这需要更多时间。 CUSTOMER_ADDRESS 表有接近 450K 的记录,而 CONTROL_REC 有接近 1.7M 的记录。 这可能是因为 GROUP BY 和子查询。 即使在使用并行线程之后,它也不起作用。

有人可以帮忙简化查询以更快地运行吗?

SELECT /*+ parallel(A,8) */ 
A.SETID, A.CUST_ID, A.ADDRESS_SEQ_NUM,
A.ALT_NAME1, A.ALT_NAME2,  
A.LANGUAGE_CD, A.COUNTRY, A.ADDRESS1,
A.ADDRESS2, A.ADDRESS3, A.ADDRESS4, 
A.CITY, A.NUM1, A.NUM2, A.ADDR_FIELD1,
A.ADDR_FIELD2, A.ADDR_FIELD3, 
A.COUNTY, A.STATE, A.POSTAL, 
A.IN_CITY_LIMIT, A.COUNTRY_CODE, 
A.PHONE, A.EXTENSION, A.FAX, 
B.SETCNTRLVALUE, MAX(A.EFFDT) AS EFFDT 
FROM CUSTOMER_ADDRESS A, 
     CONTROL_REC B 
WHERE B.RECNAME = 'CUST_ADDRESS' 
AND A.EFFDT = (
    SELECT MAX(A_ED.EFFDT) 
    FROM CUSTOMER_ADDRESS A_ED 
    WHERE A.SETID = A_ED.SETID 
    AND A.CUST_ID = A_ED.CUST_ID 
    AND A.ADDRESS_SEQ_NUM = A_ED.ADDRESS_SEQ_NUM 
    AND A_ED.EFFDT <= SYSDATE) 
AND A.SETID = B.SETID 
GROUP BY A.SETID, A.CUST_ID, 
    A.ADDRESS_SEQ_NUM, A.ALT_NAME1, 
    A.ALT_NAME2, A.LANGUAGE_CD, 
    A.COUNTRY, A.ADDRESS1, A.ADDRESS2,
    A.ADDRESS3, A.ADDRESS4, A.CITY, 
    A.NUM1, A.NUM2, A.ADDR_FIELD1, 
    A.ADDR_FIELD2, A.ADDR_FIELD3, 
    A.COUNTY, A.STATE, A.POSTAL, 
    A.IN_CITY_LIMIT, A.COUNTRY_CODE, 
    A.PHONE, A.EXTENSION, A.FAX, B.SETCNTRLVALUE;

【问题讨论】:

  • 请描述查询应该做什么。样本数据和期望的结果也会有所帮助。
  • 运行解释计划并发布结果。您可能还想格式化查询,使其可读。

标签: sql oracle oracle11g


【解决方案1】:

尝试将自联接转换为分析函数。解析函数避免了两次从同一个表中读取,简化了代码,简化了执行计划。您可能还希望将对象级并行性/*+ parallel(A,8) */ 转换为语句级并行性/*+ parallel(8) */。如果查询的一部分并行运行,通常最好让查询的所有部分并行运行。

SELECT /*+ parallel(8) */ 
A.SETID, A.CUST_ID, A.ADDRESS_SEQ_NUM,
A.ALT_NAME1, A.ALT_NAME2,  
A.LANGUAGE_CD, A.COUNTRY, A.ADDRESS1,
A.ADDRESS2, A.ADDRESS3, A.ADDRESS4, 
A.CITY, A.NUM1, A.NUM2, A.ADDR_FIELD1,
A.ADDR_FIELD2, A.ADDR_FIELD3, 
A.COUNTY, A.STATE, A.POSTAL, 
A.IN_CITY_LIMIT, A.COUNTRY_CODE, 
A.PHONE, A.EXTENSION, A.FAX, 
B.SETCNTRLVALUE, MAX(A.EFFDT) AS EFFDT 
FROM
    (
        SELECT CUSTOMER_ADDRESS.*,
            MAX(CASE WHEN EFFDT <= SYSDATE THEN EFFDT ELSE NULL END)
                OVER (PARTITION BY SETID, CUST_ID, ADDRESS_SEQ_NUM) MAX_EFFDT
        FROM CUSTOMER_ADDRESS
    ) A
JOIN CONTROL_REC B 
    ON A.SETID = B.SETID 
WHERE B.RECNAME = 'CUST_ADDRESS' 
    AND A.EFFDT = A.MAX_EFFDT
GROUP BY A.SETID, A.CUST_ID, 
    A.ADDRESS_SEQ_NUM, A.ALT_NAME1, 
    A.ALT_NAME2, A.LANGUAGE_CD, 
    A.COUNTRY, A.ADDRESS1, A.ADDRESS2,
    A.ADDRESS3, A.ADDRESS4, A.CITY, 
    A.NUM1, A.NUM2, A.ADDR_FIELD1, 
    A.ADDR_FIELD2, A.ADDR_FIELD3, 
    A.COUNTY, A.STATE, A.POSTAL, 
    A.IN_CITY_LIMIT, A.COUNTRY_CODE, 
    A.PHONE, A.EXTENSION, A.FAX, B.SETCNTRLVALUE;

如果上述方法不起作用,那么您需要generate an an execution plan with the the GATHER_PLAN_STATISTICS hint。通过执行计划,有人可能会告诉您查询的哪些部分运行缓慢,以及原因。

【讨论】:

    【解决方案2】:

    您需要提供这些表格上的索引。从给定的确定性列谓词来看,B 似乎是您的驱动表。所以 /*+ parallel(A,8) */ *可以 * 在内部表上引发 FTS,使内部子查询中的任何索引前导列都无用

    【讨论】:

      猜你喜欢
      • 2021-11-01
      • 1970-01-01
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多