Прежде всего, как упомянуто в комментарии Алекса, я не уверен, что ваша вторая версия на 100% гарантированно даст вам правильные строки - поскольку «средний» блок запроса не имеет явного order by
Oracle не обязана передавать строки во внешний блок запроса в каком-либо определенном порядке. Однако, похоже, нет какой-либо конкретной причины, по которой это могло бы изменить порядок передачи строк из самого внутреннего блока, поэтому на практике это, вероятно, сработает.
И именно поэтому Oracle выбирает другой план для второго запроса - логически не может применить операцию STOPKEY
к самому внутреннему блоку запроса.
Я думаю, что в первом случае оптимизатор предполагает, что значения id
хорошо распределены, и для любого заданного значения, вероятно, будут некоторые очень недавние транзакции. Поскольку он может видеть, что ему нужно только найти 5 самых последних совпадений, он рассчитывает, что, по-видимому, более эффективно сканировать строки в порядке убывания paydate
с использованием индекса, искать соответствующий идентификатор и другие данные из таблицы. и остановитесь, когда найдете первые 5 совпадений. Я подозреваю, что вы увидите очень разную производительность для этого запроса в зависимости от конкретного значения идентификатора, который вы используете - если идентификатор имеет много недавних действий, строки должны быть найдены очень быстро, но если это не так, сканирование индекса возможно, придется сделать гораздо больше работы.
Во втором случае я считаю, что он не может применить оптимизацию STOPKEY
к самому внутреннему блоку из-за дополнительного уровня вложенности. В этом случае полное сканирование индекса станет гораздо менее привлекательным, поскольку всегда нужно будет сканировать весь индекс. Поэтому он выбирает поиск индекса по id
(я предполагаю) с последующей фактической сортировкой по дате. Если данное значение id
соответствует небольшому подмножеству строк, это, вероятно, будет более эффективным, но если вы дадите id
, у которого множество строк разбросано по всей таблице, я ожидаю, что оно станет медленнее, так как ему придется обращаться и сортировать много строк.
Итак, я бы предположил, что в ваших тестах использовались значения id
, в которых относительно мало строк, которые не являются слишком свежими. Если это будет типичный вариант использования, то второй запрос, вероятно, лучше для вас (опять же, с учетом предостережения, что я не уверен, что технически гарантированно будет получен правильный набор результатов). Но если типичные значения с большей вероятностью будут иметь много совпадающих строк и / или с большей вероятностью будут иметь 5 самых последних строк, тогда первый запрос и план могут быть лучше.