Как оптимизировать SQL-запрос (Oracle Database) - PullRequest
0 голосов
/ 01 октября 2018

Я хочу оптимизировать свой SQL-запрос.Это выглядит действительно просто, но компилируется слишком долго для меня.Моя база данных - Oracle 12.1.0.3.Когда таблица AB_MESSAGE содержит около 1К записей (тестовая среда), время компиляции запроса составляет более 6 секунд.

Мой запрос SQL:

SELECT * from AB_MESSAGE m 
left join AB_MESSAGE_TYPE mt ON m.MESSAGE_TYPE_ID=m.ID
where to_char(m.CREATION_DATE,'YY/MM/DD') >= '18/09/30'  
and m.MESSAGE_ID is null 
and m.id in (select max(m2.ID) 
             from AB_MESSAGE m2
             where m2.MESSAGE_ID is null 
             group by m2.AB_MESSAGE_ID, m2.SEND_DATE)  
order by m.SEND_DATE desc;

Таблица AB_MESSAGE:

CREATE TABLE "AB"."AB_MESSAGE" 
(   "ID" NUMBER(*,0) NOT NULL ENABLE, 
"MESSAGE_ID" NUMBER(*,0), 
"AB_MESSAGE_ID" NUMBER(*,0), 
"SNDR_MSG_REF" VARCHAR2(20 BYTE), 
"SENDER_ID" VARCHAR2(20 BYTE), 
"RECEIVER_ID" VARCHAR2(20 BYTE), 
"ESDK_MESSAGE_TYPE_ID" NUMBER, 
"MESSAGE_TYPE_ID" NUMBER NOT NULL ENABLE, 
"MT_FIELD_DEF_VARIANT_ID" NUMBER, 
"ISSUE_ID" NUMBER, 
"PARENT_ID" NUMBER, 
"PARENT_MESSAGE_ID" NUMBER, 
"CREATION_DATE" TIMESTAMP (6) DEFAULT CURRENT_TIMESTAMP NOT NULL ENABLE, 
"CHANGE_DATE" TIMESTAMP (6), 
"SEND_DATE" TIMESTAMP (6), 
"MESSAGE_FILE_NAME" VARCHAR2(100 BYTE), 
"MESSAGE_TYPE" VARCHAR2(24 BYTE), 
"RAW_ESDK_MESSAGE" BLOB, 
"XML_MESSAGE_CLOB" CLOB, 
"MESSAGE_STATUS" VARCHAR2(50 BYTE), 
 CONSTRAINT "AB_MESSAGE_PK" PRIMARY KEY ("ID")
 USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS 
 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
 TABLESPACE "ABA"  ENABLE, 
 CONSTRAINT "AB_MESSAGE_FK5" FOREIGN KEY ("PARENT_ID")
  REFERENCES "AB"."AB_MESSAGE" ("ID") ENABLE, 
 CONSTRAINT "AB_MESSAGE_FK1" FOREIGN KEY ("MESSAGE_TYPE_ID")
  REFERENCES "AB"."AB_MESSAGE_TYPE" ("ID") ON DELETE CASCADE ENABLE)

Таблица AB_MESSAGE:

CREATE TABLE "AB"."AB_MESSAGE_TYPE" 
("ID" NUMBER(*,0) NOT NULL ENABLE, 
"NAME" VARCHAR2(20 BYTE) NOT NULL ENABLE, 
"DESCRIPTION" VARCHAR2(150 BYTE), 
"CREATION_DATE" TIMESTAMP (6) DEFAULT CURRENT_TIMESTAMP NOT NULL ENABLE, 
 CONSTRAINT "AB_MESSAGE_TYPE_PK" PRIMARY KEY ("ID")
 USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS 
 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
 TABLESPACE "ABA" ENABLE)

Вопрос: Есть ли способ оптимизировать этот запрос?

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

Я бы начал с улучшения двух простых вещей:

  1. Улучшение вашего SQL: измените to_char(m.CREATION_DATE,'YY/MM/DD') >= '18/09/30' на m.CREATION_DATE >= date '2018-09-30'.Это изменение поможет с использованием индекса.

  2. Добавьте следующие индексы:

    create index ix1 on AB_MESSAGE (AB_MESSAGE_ID, SEND_DATE, MESSAGE_ID, ID);
    
    create index ix2 on AB_MESSAGE (CREATION_DATE, MESSAGE_ID);
    

Если запрос все еще медленный,Я хотел бы получить план выполнения запроса, чтобы убедиться, что он использует правильные индексы.

0 голосов
/ 01 октября 2018

Ваш запрос не использует индекс (если он есть), определенный для ab_message(creation_date).Измените левую часть сравнения >=, чтобы не использовать функции, так как они являются черными ящиками для оптимизатора.

Кроме того, ваши JOIN столбцы, вероятно, неверны, поскольку должны принимать столбец из m иеще один из mt.Вместо этого попробуйте m.message_type_id = mt.id.

SELECT * 
from AB_MESSAGE m 
left join AB_MESSAGE_TYPE mt ON m.MESSAGE_TYPE_ID = mt.ID -- change here
where 
      m.CREATION_DATE >= '2018-09-30' -- change here
  and m.MESSAGE_ID is null 
  and m.id in (
    select max(m2.ID) 
    from AB_MESSAGE m2 
    where m2.MESSAGE_ID is null 
    group by m2.AB_MESSAGE_ID, m2.SEND_DATE)  
order by m.SEND_DATE desc;

Кроме этого, есть возможность переписать подзапрос, но нам нужно увидеть индексы, которые вы создали для своих таблиц.

Прочитайтеглава о EXPLAIN PLAN в документации Oracle.Это может быть хорошим дополнением к вашему вопросу, чтобы мы знали, какой план выберет ваш движок базы данных для выполнения запроса.

Я бы предложил для начинающих определить индексы, как показано ниже, и посмотреть, как / если план изменится

  • ab_message(ab_message_id, send_date)
  • ab_message(message_type_id, creation_date)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...