Рассмотрим следующий запрос:
SELECT *
FROM (
SELECT ARRM.*, ROWNUM
FROM CRS_ARRANGEMENTS ARRM
WHERE
CONCAT(ARRM.NBR_ARRANGEMENT, ARRM.TYP_PRODUCT_ARRANGEMENT) >
CONCAT('0000000000000000', '0000')
ORDER BY
ARRM.NBR_ARRANGEMENT,
ARRM.TYP_PRODUCT_ARRANGEMENT,
ARRM.COD_CURRENCY)
WHERE ROWNUM < 1000;
Этот запрос выполняется в таблице, содержащей 10 000 000 записей. При выполнении запроса от Oracle SQL Developer или моего приложения требуется 4 минуты ! К сожалению, это также поведение внутри приложения, которое я пишу. Изменение значения от 1000 до 10 не оказывает никакого влияния, предполагая, что оно выполняет полное сканирование таблицы.
Однако при запуске из SQuirreL запрос возвращается в течение нескольких миллисекунд. Как это возможно? Объяснение плана, сгенерированного в SQuirreL, дает:
Но в Oracle SQL Developer создается другой план объяснений для того же запроса:
Любая идея, как это различие в поведении возможно? Я не могу понять это. Я пробовал с JPA и сырой JDBC. В приложении мне нужно проанализировать все 10 000 000 записей, и этот запрос используется для поискового вызова, поэтому ожидание 4 минуты не является вариантом (это займет 27 дней).
Примечание. Я использую тот же драйвер Oracle jdbc в SQuirreL и моем приложении, что не является источником проблемы.
По-видимому, это связано с поддержкой национальных языков или NLS. Разработчик Oracle SQL Developer установил значение "голландский" по умолчанию на основе вашего локали, а SQuirreL - BINARY. Это различие заставило оптимизатор использовать разные пути для решения запроса. Чтобы использовать правильный параметр NLS_SORT в сеансе jdbc, необходимо использовать следующую команду:
ALTER SESSION SET NLS_SORT=BINARY
Затем в запросе будут использоваться правильные индексы.
explain plan for select ...
и затем select * from table(dbms_xplan.display);
покажет разницу в разделе Notes
. По какой-то причине каждая IDE, которую я когда-либо использовал, пыталась сделать планы объяснения «красивыми», но не включала важную информацию.