Первое, что нужно отметить, это то, что план «после» стоил дешевле, чем план «до».
Это говорит нам о том, что план, выбранный для второго запроса, не был рассмотрен для первого запроса, поскольку Oracle выбрала бы план с более низкой стоимостью.
Добавление подсказки USE_NL_WITH_INDEX не повлияло бы на стоимость любого плана. Что он делает, если доступен план с вложенным циклом с индексом, то любой другой план будет исключен из рассмотрения, даже если Oracle будет более эффективным планом.
Во-вторых, предикат "t1.id = t2.id" позволяет нам начинать с t1 и связываться с t2 или начинать с t2 и связываться с t1. Изменение этого предиката на «t1.id = t2.id + 0» означает, что он может перейти только от t2 (добавить 0 к идентификатору) для ссылки на t1. Oracle не достаточно умна, чтобы понять, что она может начинаться с t1 (минус 0 от идентификатора) и присоединяться к t2 (или что добавление / минус 0 в любом случае не имеет значения).
Оба этих трюка не позволяют использовать определенные пути доступа. Ни один из них не может объяснить очевидное снижение стоимости выбранного плана.
Учитывая "И t1.version_id = t2.version_id" и "И t1.version_id = t3.version_id", то
«t3.version_id = t2.version_id» является заданным (при условии преобразования типов данных). Однако добавление его в явном виде подсказало бы Oracle, что, поскольку применяется дополнительное условие, будет возвращено меньше строк, и это может отразиться на более низкой стоимости.
Если t2 и t3 version_id не были числовыми, это могло бы объяснить изменение стоимости. «+ 0» приведет к преобразованию типа данных, что может позволить использовать индекс. Я думаю, что это вряд ли.
Я подозреваю, что первоначальный план двигался с t1 (с t1.id = 123 и version_name <> 'AA'). Дополнительные предикаты (вероятно) заставят его начинать с t2.
лично, мне не нравятся другие оптимизации. Ни один адрес, почему изначально был выбран неправильный план.