#oracle #primary-key #oracle12c #query-performance
#Oracle #первичный ключ #oracle12c #запрос-производительность
Вопрос:
Я использую Oracle 12C, и у меня есть следующий код
SELECT
d.id,
'Status' "ImportStatus",
p.importid "ImportID",
macid,
p.daterequire "CreateDate",
p.dateimport "DateImPort",
TRANSLATE(p.accrequire USING NCHAR_CS) "CreateBy",
TRANSLATE(p.accimport USING NCHAR_CS) "AccImPort",
0 "isEdit",
employee,
deptid partner,
equipmentid
FROM
(
SELECT
id,
importid,
daterequire,
dateimport,
accrequire,
accimport,
subdeptid employee,
deptid
FROM
tableA
WHERE
estatus = 2
AND createdate BETWEEN to_timestamp('01/01/2019','dd/mm/yyyy') AND to_timestamp('12/02/2019','dd/mm/yyyy')
) p
INNER JOIN tableB d ON d.importid = p.id
Таблица A имела значения 5m, а таблица B — значения 3m.
Importid — это уникальный столбец с типом данных varchar2. Идентификатор равен PK с типом данных number.
Вот план выполнения:
https://i.stack.imgur.com/tR2Q9.png
Как можно видеть, в PK нет индекса, и это приводит к высокой стоимости. Есть ли какой-нибудь способ помочь мне решить эту проблему?
Спасибо!
Ответ №1:
Прежде всего, вы должны учитывать, что индексы не всегда являются хорошей идеей.
Если Oracle необходимо прочитать большую часть данных из таблицы, он будет использовать ПОЛНОЕ СКАНИРОВАНИЕ ТАБЛИЦЫ, поскольку это быстрее, чем сначала считывать блоки индекса, а затем блоки данных во вторую очередь. Задействовано слишком много операций ввода-вывода.
Теперь вернемся к вашему вопросу.
Вы можете заставить Oracle использовать индекс, если хотите, предоставив подсказку:
/* INDEX(table_name index_name) */
Вы можете добавить его в свой запрос и проверить, что происходит с планом запроса и сколько будет стоить новый план:
SELECT /* INDEX(tableA index_name) */ --replace 'index_name' with the name of your index
d.id,
'Status' "ImportStatus",
p.importid "ImportID",
macid,
p.daterequire "CreateDate",
p.dateimport "DateImPort",
TRANSLATE(p.accrequire USING NCHAR_CS) "CreateBy",
TRANSLATE(p.accimport USING NCHAR_CS) "AccImPort",
0 "isEdit",
employee,
deptid partner,
equipmentid
FROM
(
SELECT
id,
importid,
daterequire,
dateimport,
accrequire,
accimport,
subdeptid employee,
deptid
FROM
tableA
WHERE
estatus = 2
AND createdate BETWEEN to_timestamp('01/01/2019','dd/mm/yyyy') AND to_timestamp('12/02/2019','dd/mm/yyyy')
) p
INNER JOIN tableB d ON d.importid = p.id
Комментарии:
1. Я пытался использовать подсказку для принудительного использования, но бесполезно. Из-за этого стоимость и затраченное время были выше, чем из-за отсутствия силы
2. Это означает только, что Oracle выбирает лучший план выполнения для выполнения вашего запроса, который не использует индекс innvole (как я уже говорил ранее, индексы не всегда являются хорошей идеей). Чтобы ускорить производительность, вы могли бы попробовать разбить вашу таблицу на
createdate
(и, возможноestatus
) столбцы и посмотреть, поможет ли это.