Объединения выполняются не в порядке, основанном на внутреннем и внешнем, а скорее на том, что, по мнению оптимизатора, приведет к тому, что запрос будет выполнен быстрее всего. Детали будут варьироваться в зависимости от базы данных. Но в основном оптимизатор запросов пытается оптимизировать использование индексов.
Предположим, у вас был этот запрос:
select a.foo, b.bar
from a
join b on b.b_id=a.b_id
where a.some_number=42;
Теперь предположим, что у вас есть уникальный индекс для b.b_id, но нет индекса для a.some_number.
Тогда у оптимизатора запросов есть два варианта: он может выполнить последовательное чтение полного файла на b, а затем для каждого b выполнить последовательное чтение полного файла при поиске совпадения по b_id и some_number = 42. То есть читать записи ^ b. Или он мог бы выполнить последовательное чтение всего файла при поиске some_number = 42, затем для каждого a он мог бы использовать индекс для быстрого поиска записи из b с совпадающим b_id. То есть прочитайте * 2 записи. Ну, очевидно, второй план намного лучше, так что это то, что он выберет.
Когда вы добавляете больше таблиц, расчет становится более сложным, но принцип тот же. Соединения, которые приводят к быстрому считыванию индекса с использованием значений, найденных в других таблицах, будут выполнены позже, после прочтения других таблиц. Таблицы, которые должны читаться последовательно, независимо от того, что или где чтение основано на константах, а не на значениях из других записей, обычно читаются первыми.