Условный предикат в левом внешнем соединении оценивается поздно, что вызывает проблемы с производительностью. Oracle 8i

Это на Oracle 8i (извините, нет контроля над этим) и PHP 7.

Я строю инструмент поиска. Это простая форма с 3 полями, использующая метод HTTP Post. Затем PHP выполняет некоторые проверки значений 3 полей, определяет, действительны ли они, а затем отправляет значения в запрос SQL. Запрос выглядит примерно так; помните его 8i, так что нет ANSI присоединиться здесь:

SELECT
reports_table.*, documents_table.*, cases_table.*

FROM
reports_table, documents_table, cases_table

WHERE
reports_table.report_id = documents_table.report_id
AND reports_table.report_id = cases_table.report_id(+)

-- Report Number filtering

AND reports_table.report_no =
CASE
WHEN $report_no_isvalid = 1
THEN '$report_no'       -- Oracle expects datatype varchar2
ELSE reports_table.report_no
END

-- Document Number filtering

AND documents_table.document_no =
CASE
WHEN $doc_no_isvalid = 1
THEN $doc_no        -- Oracle expects datatype number
ELSE documents_table.document_no
END

-- Case Number filtering

AND cases_table.case_no =
CASE
WHEN $case_no_isvalid = 1
THEN '$case_no'     -- Oracle expects datatype varchar2
ELSE cases_table.case_no
END

Пользователь должен ввести хотя бы номер отчета или номер дела. Требуются полные номера, то есть поиск по шаблону не допускается.
reports_table очень большой
При поиске по номеру отчета база данных занимает очень много времени, как будто оценка CASE, которая влияет на достоверность номера отчета, то есть этот раздел кода здесь

AND reports_table.report_no =
CASE
WHEN $report_no_isvalid = 1
THEN '$report_no'       -- Oracle expects datatype varchar2
ELSE reports_table.report_no
END

оценивается после операции соединения. Это, кажется, действительно оценивается, потому что, если я добавлю еще один простой предикат в предложении WHERE, чтобы ограничить область действия для номера отчета, база данных ответит очень быстро, с ожидаемым результатом. например скажем, номер отчета, который я ищу, это «R123456», если я добавлю AND reports_table.report_no LIKE 'R1234%'как предикат вне оператора CASE, производительность хорошая. В противном случае это очень медленно, как будто Oracle сканирует весь reports_table в попытке сделать соединение.

Я хотел бы найти способ сообщить Oracle, чтобы он смотрел на условный фильтр CASE по номеру отчета при выполнении объединения, но я не знаю, как это сделать.
Или, может быть, мне следует вообще избегать такого рода условных ограничений на объединение, и если да, то какую технику я могу использовать для достижения того, что я пытаюсь сделать?

0

Решение

Прошло некоторое время с тех пор, как мне пришлось поработать с этим: и полный выстрел в темноте … Перераспределяет ли ограничения так, чтобы они налагались до внешнего соединения?

WHERE
(reports_table.report_id = documents_table.report_id
-- Report Number filtering

AND reports_table.report_no =
CASE
WHEN $report_no_isvalid = 1
THEN '$report_no'       -- Oracle expects datatype varchar2
ELSE reports_table.report_no
END
-- Document Number filtering
AND documents_table.document_no =
CASE
WHEN $doc_no_isvalid = 1
THEN $doc_no        -- Oracle expects datatype number
ELSE documents_table.document_no
END)
AND
(reports_table.report_id = cases_table.report_id(+)
-- Case Number filtering
AND cases_table.case_no =
CASE
WHEN $case_no_isvalid = 1
THEN '$case_no'     -- Oracle expects datatype varchar2
ELSE cases_table.case_no
END)

В ANSI я знаю, что если я использую AND в таблице where с помощью внешнего соединения, то мое внешнее соединение ведет себя как внутреннее. Я задаюсь вопросом, переставляя ли двигатель лучше оптимизировать; или если понадобится реальная подсказка SQL.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]