【问题标题】:sql query takes a lot of timesql查询需要很多时间
【发布时间】:2011-10-02 15:38:42
【问题描述】:

我正在运行以下查询:

SELECT * 
  FROM dblappc.credit_history 
 WHERE crd_effective_date > TO_DATE('20100801','YYYYMMDD') 
   AND o_crd_score > 650 
   AND crd_expiration_date IS NULL
  • 上面的表没有索引
  • crd_expiration_date 是主键的一部分

如何加快查询速度?
我可以在这里使用并行提示,以便一次至少提供 500 行吗?

下面是表结构:

CREATE TABLE DFQAPP13.CREDIT_HISTORY
(
  BAN                  NUMBER(9) CONSTRAINT CRHST_BAN_NN NOT NULL,
  CRD_SEQ_NO           NUMBER(9) CONSTRAINT CRDHST_CRD_SEQ_NO_NN NOT NULL,
  SYS_CREATION_DATE    DATE                     NOT NULL,
  SYS_UPDATE_DATE      DATE,
  OPERATOR_ID          NUMBER(9),
  APPLICATION_ID       CHAR(6 BYTE),
  DL_SERVICE_CODE      CHAR(5 BYTE),
  DL_UPDATE_STAMP      NUMBER(4),
  CRD_EFFECTIVE_DATE   DATE CONSTRAINT CRDHST_CRD_EFFECTIVE_DATE_NN NOT NULL,
  CRD_EXPIRATION_DATE  DATE,
  CRD_VET_TYPE         CHAR(4 BYTE),
  O_CRD_APPLIC_NUM     NUMBER(9),
  O_CRD_DECISION       CHAR(2 BYTE),
  O_CRD_SCORE          NUMBER(7),
  O_CRD_POLICY_RULE1   VARCHAR2(40 BYTE),
  O_CRD_POLICY_RULE2   VARCHAR2(40 BYTE),
  O_CRD_POLICY_RULE3   VARCHAR2(40 BYTE),
  O_CRD_POLICY_RULE4   VARCHAR2(40 BYTE),
  O_CRD_POLICY_RULE5   VARCHAR2(40 BYTE),
  O_CRD_POLICY_RULE6   VARCHAR2(40 BYTE),
  CRD_CLASS            CHAR(1 BYTE),
  CRD_CLASS_CHG_TYPE   CHAR(1 BYTE),
  CRD_CHG_RSN_TEXT     CHAR(100 BYTE),
  I_CRD_REQ_CTN_QTY    NUMBER(7),
  CRD_APR_CTN_QTY      NUMBER(7),
  I_CRD_BANK_BRANCH    VARCHAR2(100 BYTE),
  I_CRD_TACT_BANK_CD   CHAR(1 BYTE),
  I_CRD_BANK_DATE      DATE,
  I_ESAT_CUST_IND      CHAR(1 BYTE),
  O_DUNS_RET_CODE1     CHAR(4 BYTE),
  O_DUNS_RET_CODE2     CHAR(4 BYTE),
  O_DUNS_RET_NUM       VARCHAR2(18 BYTE),
  O_DUNS_NUM           NUMBER(9),
  O_DUNS_FIN_STRENGTH  CHAR(3 BYTE),
  O_DUNS_COMP_COND     CHAR(1 BYTE),
  O_DUNS_PAYM_SCORE    NUMBER(4),
  O_DUNS_CCJ1_EIRE     NUMBER(6),
  O_DUNS_CCJ2_EIRE     NUMBER(6),
  O_DUNS_CCJ3_EIRE     NUMBER(6),
  O_DUNS_CCJ4_EIRE     NUMBER(6),
  O_DUNS_CCJ5_EIRE     NUMBER(6),
  O_DUNS_CCJ1_UK       NUMBER(4),
  O_DUNS_CCJ2_UK       NUMBER(4),
  O_DUNS_CCJ3_UK       NUMBER(4),
  O_DUNS_CCJ4_UK       NUMBER(4),
  O_DUNS_CCJ5_UK       NUMBER(4),
  I_PHONE_TYPE         CHAR(3 BYTE),
  I_PAID_ENHANCE_NUM   NUMBER(1),
  I_CHURN_CUST_IND     CHAR(1 BYTE),
  I_EX_DIRECTORY_IND   CHAR(1 BYTE),
  I_ITEMISED_BIL_IND   CHAR(1 BYTE),
  CONV_RUN_NO          NUMBER(3)
)

【问题讨论】:

  • 可以添加表结构和索引吗?
  • 你的意思是crd_effective_date是PK的一部分(不是crd_expiration_date)?如果后者是声明的主键的一部分,则它永远不能为 NULL,因此您的查询应该运行得非常快:)
  • " ... 上表没有索引 ..." 如何为WHERE 子句中的列添加一些索引,特别是crd_effective_dateo_crd_score

标签: sql oracle parallel-processing hint


【解决方案1】:

你可以让它更快

  • 选择您要减少结果权重的特定项目。
  • 在 WHERE 子句中首先使用o_crd_score >650crd_expiration_date is null 在第二位和 crd_effective_date>to_date('20100801','YYYYMMDD')在最后

所以查询会是这样的。

SELECT a,b,d... 
FROM dblappc.credit_history
WHERE 
  o_crd_score >650 and 
  crd_expiration_date is null
  crd_effective_date>to_date('20100801','YYYYMMDD') and 

我在这里所做的是将记录短路到最低限度,以便将日期检查应用于过滤掉的记录。

您还可以通过在表格上应用 INDEX 来加快速度。

【讨论】:

  • 只选择需要的字段是好的。但是没有理由改变WHERE 子句中条件的顺序。任何设计良好的查询优化器都会尝试找到最佳执行计划,而不管该顺序如何。
【解决方案2】:

在不知道表大小、现有索引、执行计划等细节的情况下,很难给出任何建议。

由于查询在两个范围内进行搜索,因此仅使用索引获取所有结果并不容易。

但我会先尝试这两个选项:

  • crd_effective_date 上的简单索引和(crd_expiration_date, o_crd_score) 上的复合索引或

  • o_crd_score 上的简单索引和(crd_expiration_date, crd_effective_date) 上的复合索引

您可以使用:EXPLAIN PLAN

检查查询的执行计划(现在,没有索引和添加索引之后)

【讨论】:

    【解决方案3】:

    有一个具体问题和一些一般性改进。

    首先,null 值未编入索引,因此 Oracle 很可能会为您的查询选择全索引扫描或索引跳过扫描变体,并在主键之上建立索引。 如果您确实需要将crd_expiration_date 包含到主键中,请仅在o_crd_scorecrd_effective_date 字段上为此查询创建另一个索引。

    create index X_CREDIT_HISTORY_DATE_SCORE 
      on CREDIT_HISTORY (o_crd_score, crd_effective_date)
    

    如果之后 Oracle 不会在查询文本中强制使用新索引:

    select /*+ index(hist_data X_CREDIT_HISTORY_DATE_SCORE) */ 
      * 
    from 
      dblappc.credit_history hist_data
    where 
      crd_effective_date>to_date('20100801','YYYYMMDD') 
      and 
      o_crd_score >650 
      and 
      crd_expiration_date is null
    

    一般问题很常见,在之前的答案中提到过:

    1. 只选择您真正需要的特定字段;
    2. 避免在主键中使用空值;
    3. 首选代理主键。

    更新

    哎呀... 我之前在阅读问题时错过了“Above table has no indexs”这句话。

    因此只有一个建议:只需创建一个索引。

    【讨论】:

    • 你说得对,NULL 没有被索引——但它们也不能出现在主键字段中。如果crd_expiration_date 确实是主键的一部分,则它不能为NULL,并且查询应该总是运行得非常快并立即返回行。我怀疑 OP 说错了——可能生效日期是 PK 的一部分,而不是到期日期。
    • @Dave Costa:你是对的。对于特定领域的正确答案,我们需要明确条件。第一个选项是它是在 Oracle 中创建的主键并且字段名称说明不正确。第二个选项是有一个逻辑条件和字段crd_expiration_date 是简单唯一索引的一部分。
    猜你喜欢
    • 2016-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多