Похоже, вы уже достаточно близки к объяснению. Это из-за этого:
Представление состоит из нескольких довольно больших таблиц, и его поле id представляет собой строку строк их соответствующих идентификаторов ...
Это создает условие предиката необязательного соединения и не позволяет SQL-серверу использовать какие-либо индексы в базовых таблицах. Таким образом, движок должен выполнить полное сканирование всех базовых таблиц для каждого объединения (в вашем случае две).
Возможно, чтобы избежать нескольких полных сканирований таблиц (по одному для каждой таблицы, умноженных на количество объединений), SQL Server решил, что быстрее будет просто использовать декартово произведение и фильтровать впоследствии (отсюда и «нет». предикат присоединения «предупреждение». Когда вы FORCE ORDER
, он покорно выполняет все полные сканирования и вложенные циклы, которые вы изначально запрашивали.
Я согласен с некоторыми комментариями о том, что это представление лежит в основе проблемной модели данных, но краткосрочный обходной путь, как вы обнаружили, заключается в индексации столбца вычисленного идентификатора в представлении, что (очевидно) делает он снова может быть sargable, потому что он содержит хеши сгенерированного идентификатора.
Редактировать: я также пропустил это при первом прочтении:
WHERE dbo.fnDatesAreOverlapping(N.dtmValidStartDate,N.dtmValidEndDate,A.dtmValidStartDate,A.dtmValidEndDate) = 1
Опять же, это предикат без аргументов, который приведет к снижению производительности. Обтекание любых столбцов в UDF вызовет такое поведение. Индексирование представления также материализует его, что также может влиять на скорость запроса; без индекса этот предикат должен оцениваться каждый раз и вызывать полное сканирование базовых таблиц, даже без составного идентификатора.