Это на 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 наНомер отчета при выполнении объединения, но я понятия не имею, как.Или, может быть, мне следует вообще избегать такого рода условных ограничений на объединение, и если да, то какую технику я могу использовать для достижения того, что я пытаюсь сделать?