SQL-запрос занимает много времени - PullRequest
0 голосов
/ 11 июля 2011

Я выполняю следующий запрос:

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)
)

Ответы [ 3 ]

2 голосов
/ 11 июля 2011

Не зная размера таблицы, существующих индексов, плана выполнения и других деталей, трудно дать какой-либо совет.

Поскольку запрос выполняется в двух диапазонах, получить все результаты, используя только индексы, нелегко.

Но я бы попробовал сначала эти 2 варианта:

  • Простой индекс для crd_effective_date и составной для (crd_expiration_date, o_crd_score) или

  • Простой индекс для o_crd_score и составной для (crd_expiration_date, crd_effective_date)

Вы можете проверить план выполнения запроса (теперь без индексов и после их добавления), используя: EXPLAIN PLAN

0 голосов
/ 11 июля 2011

Существует одна конкретная проблема и некоторые общие улучшения.

Во-первых, null значения не проиндексированы, поэтому Oracle, скорее всего, выберет вариант полного сканирования индекса или пропуска сканирования индекса для вашего запроса с построением индекса выше основногоключ.Если вам действительно необходимо включить crd_expiration_date в первичный ключ, создайте еще один индекс для этого запроса только для полей o_crd_score и crd_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. Суррогатные первичные ключи предпочтительнее.

Обновление

Оооо ... Я пропустил фразу "Над таблицей нет индексов" при чтении вопроса раньше.

Поэтому только одна рекомендация: просто создать индекс.

0 голосов
/ 11 июля 2011

Вы можете сделать это быстрее,

  • ВЫБЕРИТЕ конкретный элемент, для которого вы хотите уменьшить вес результата.
  • В предложении WHERE используйте o_crd_score >650 на первом месте, crd_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 

Что я здесь делаю, так это короткое замыкание записей до минимума, чтобы проверка даты была применена к отфильтрованной записи.

Также вы можете сделать это быстро, применив ИНДЕКС на столе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...