Это условие:
WHERE UPPER(ps.customerpostcode) like 'MK3%'
не является непрерывным, то есть вы не можете сохранить для него один заказанный диапазон.
Таким образом, есть два способа выполнить этот запрос:
- Порядок по номеру, затем фильтр по коду.
- Фильтрация по коду, затем упорядочение по номеру.
Метод 1
может использовать индекс для числа, который дает вам линейное время выполнения (верхние 100
строк будут выбраны * в 1016 * раз быстрее, чем верхние 200
, при условии, что число и код делаютне коррелирует).
Метод 2
может использовать сканирование диапазона для грубой фильтрации по коду (условие диапазона будет что-то вроде code >= 'MK3' AND code < 'MK4'
), однако, требуется сортировка, так как порядок числане может быть сохранен в составном индексе.
Время сортировки зависит также от количества выбранных вами верхних строк, но эта зависимость, в отличие от метода для 1
, не является линейной (вам всегда нужно по крайней мереодно сканирование диапазона).
Однако условие фильтрации в методе 2
достаточно избирательно для RANGE SCAN
с последующей сортировкой, чтобы быть более эффективным, чем FULL SCAN
для всей таблицы.
Это означает, что существует переломный момент: для этого условия: ROWNUM <= X
существует значение X
, поэтому метод 2
становится более эффективным при превышении этого значения.
Обновление:
Если вы всегда ищете хотя бы по 3
первым символам, вы можете создать такой индекс:
SUBSTRING(UPPER(customerpostcode), 1, 3), proposalnumber
и использовать его в этом запросе:
SELECT *
FROM (
SELECT *
FROM cr_proposalsearch ps
WHERE SUBSTRING(UPPER(customerpostcode, 1, 3)) = SUBSTRING(UPPER(:searchquery), 1, 3)
AND UPPER(ps.customerpostcode) LIKE UPPER(:searchquery) || '%'
ORDER BY
proposalNumber DESC
)
WHERE rownum <= 200
Таким образом, порядок номеров будет сохраняться отдельно для каждого набора кодов, разделяющих первые 3
букв, что даст вам более плотное сканирование индекса.