【问题标题】:the below select statement takes a long in running下面的 select 语句需要很长时间才能运行
【发布时间】:2019-05-27 10:28:52
【问题描述】:

这个select的语句运行了很长时间,经过我的调查我发现问题是子查询,存储过程,谢谢你的帮助。

SELECT DISTINCT
    COKE_CHQ_NUMBER,
    COKE_PAY_SUPPLIER
FROM
    apps.Q_COKE_AP_CHECKS_SIGN_STATUS_V
WHERE 
    plan_id = 40192
    AND COKE_SIGNATURE__A = 'YES'
    AND COKE_SIGNATURE__B = 'YES'
    AND COKE_AUDIT = 'YES'
    AND COKE_CHQ_NUMBER NOT IN (SELECT DISTINCT COKE_CHQ_NUMBER_DELIVER
                                FROM apps.Q_COKE_AP_CHECKS_DELIVERY_ST_V
                                WHERE UPPER(COKE_CHQ_NUMBER_DELIVER_STATUS) <> 'DELIVERED')
    AND COKE_CHQ_NUMBER NOT IN (SELECT COKE_CHQ_NUMBER_DELIVER
                                FROM apps.Q_COKE_AP_CHECKS_DELIVERY_ST_V)

【问题讨论】:

  • 这是一个相当大胆的问题,没有双关语的意思。您能否为您的问题添加一个执行计划,或者一些数据?
  • @mohamedbarakat。 . .据推测,_v 意味着引用的“表”实际上是视图。在不知道视图定义的情况下,外部无法帮助查询。我要补充一点,我强烈建议避免使用带有子查询的not in,而是使用not exists
  • 请参阅here 启发您应该提供哪些信息
  • @MarmiteBomber 关于应该提供的额外信息是正确的。
  • q_coke_ap_checks_delivery_st_v.coke_chq_number_deliver 是否定义为NOT NULL?可空列不倾向于与not in 子查询混合。这是一个疯狂的猜测。此外,第一个子查询似乎被第二个子查询变得多余。

标签: sql oracle performance oracle11g query-optimization


【解决方案1】:

您的 SELECT 语句有一些问题需要解决:

首先让我们看看这个条件:

COKE_CHQ_NUMBER NOT IN (SELECT DISTINCT COKE_CHQ_NUMBER_DELIVER
                         FROM apps.Q_COKE_AP_CHECKS_DELIVERY_ST_V
                        WHERE UPPER(COKE_CHQ_NUMBER_DELIVER_STATUS) <> 'DELIVERED')

首先您选择DISTINCT 未交付状态的支票号码,然后您说您不想要这个。与其说我不希望未交付,不如说我要交付更易读。然而,这并不是一个真正的问题,而是它会让您的 SELECT 更易于阅读和理解。

接下来我们看看你的第二个检查条件:

COKE_CHQ_NUMBER NOT IN (SELECT COKE_CHQ_NUMBER_DELIVER
                         FROM apps.Q_COKE_AP_CHECKS_DELIVERY_ST_V)

您要在此处排除在Q_COKE_AP_CHECKS_DELIVERY_ST_V 中有条目的所有检查。这使您的第一个 DISTINCT 条件变得多余,因为任何支票号码将带回将被您的第二个条件拒绝。我不知道 Oracle SQL 引擎是否足够聪明来解决这种冗余,但这可能会导致你的速度变慢,因为 SELECT distinct 可能需要更长的时间来运行

除此之外,如果您还没有这些索引,我建议您添加以下索引:

CREATE INDEX index_1 ON q_coke_ap_checks_sign_status_v(coke_chq_number, coke_pay_supplier);
CREATE INDEX index_2 ON q_coke_ap_checks_sign_status_v(plan_id, coke_signature__a, coke_signature__b, coke_audit);
CREATE INDEX index_3 ON q_coke_ap_checks_delivery_st_v(coke_chq_number_deliver);

为了便于阅读,我将 index_1,2,3 称为显然不是一个好的命名约定。

有了这个,您的选择应该被优化,以便以可接受的性能检索您的数据。当然,这完全取决于数据的大小和分布,如果不进行特定的数据分析,就很难控制。

【讨论】:

    【解决方案2】:

    看着你的代码.. 似乎你有多余的条件,第二个 NOT IN 意味着第一个,所以你可以避免

    你也可以在一个 MINUS 子句中转换你的 NOT IN 子句 .. 用你不在子查询中的 INNER 连接加入同一个查询

    最后要小心你在表上有适当的复合索引

    Q_COKE_AP_CHECKS_SIGN_STATUS_V 
    cols (plan_id,COKE_SIGNATURE__A , COKE_SIGNATURE__B, COKE_AUDIT, COKE_CHQ_NUMBER, COKE_PAY_SUPPLIER)
    
    
    SELECT DISTINCT
        COKE_CHQ_NUMBER,
        COKE_PAY_SUPPLIER
    FROM
        apps.Q_COKE_AP_CHECKS_SIGN_STATUS_V
    WHERE 
        plan_id = 40192
        AND COKE_SIGNATURE__A = 'YES'
        AND COKE_SIGNATURE__B = 'YES'
        AND COKE_AUDIT = 'YES'
    
    MINUS 
    
    
    SELECT DISTINCT
        COKE_CHQ_NUMBER,
        COKE_PAY_SUPPLIER
    FROM  apps.Q_COKE_AP_CHECKS_SIGN_STATUS_V
    INNER JOIN (
        SELECT COKE_CHQ_NUMBER_DELIVER
        FROM apps.Q_COKE_AP_CHECKS_DELIVERY_ST_V
    ) T ON T.COKE_CHQ_NUMBER_DELIVER = apps.Q_COKE_AP_CHECKS_SIGN_STATUS_V
    WHERE 
        plan_id = 40192
        AND COKE_SIGNATURE__A = 'YES'
        AND COKE_SIGNATURE__B = 'YES'
        AND COKE_AUDIT = 'YES'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 2021-04-08
      • 2021-06-15
      相关资源
      最近更新 更多