Кажется, вы думаете, что ваш основной запрос подразумевает следующие шаги:
(1) Run the subquery
(2) Check each row in table1 against the result set from the subquery.
Таким образом, вы считаете, что отдельный подзапрос должен занимать меньше времени, чем весь запрос.
Но SQL не является процедурным языком, и структура запроса не обязательно подразумевает шаги, которые будут выполнены для выполнения запроса.
Как ответил Гуффа, оптимизатор придумает (как он считает) оптимальный план для выполнения каждого запроса. Эти планы выполнения не всегда очевидны при взгляде на запрос, и в некоторых случаях они могут быть довольно нелогичными.
Я думаю, что в этом случае наиболее вероятно, что оптимизатор придумал более быстрый метод проверки существования значения в таблице2, чем простой запрос всех таблиц2 одновременно. Это может быть преобразование, показанное Гуффой (хотя это все еще не говорит вам точный используемый план выполнения).
Я бы предположил, что table1 имеет значительно меньше строк, чем table2, и индекс существует для table2.columnB. Поэтому все, что нужно сделать, - это извлечь строки из таблицы table1, а затем проверить индекс для каждого из этих значений, чтобы проверить их существование. Но это только одна возможность.
Кроме того, как отметил Майкл Буэн, различия в размере возвращаемого результирующего набора также могут повлиять на вашу воспринимаемую производительность. Моя интуиция заключается в том, что это вторично по отношению к различиям в плане выполнения, но может быть значительным.