Я создаю представление в SQL Server 2000 (и 2005), и я заметил, что порядок операторов соединения сильно влияет на план выполнения и скорость запроса.
select sr.WTSASessionRangeID,
-- bunch of other columns
from WTSAVW_UserSessionRange us
inner join WTSA_SessionRange sr on sr.WTSASessionRangeID = us.WTSASessionRangeID
left outer join WTSA_SessionRangeTutor srt on srt.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeClass src on src.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeStream srs on srs.WTSASessionRangeID = sr.WTSASessionRangeID
--left outer join MO_Stream ms on ms.MOStreamID = srs.MOStreamID
left outer join WTSA_SessionRangeEnrolmentPeriod srep on srep.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeStudent stsd on stsd.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionSubrange ssr on ssr.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionSubrangeRoom ssrr on ssrr.WTSASessionSubrangeID = ssr.WTSASessionSubrangeID
left outer join MO_Stream ms on ms.MOStreamID = srs.MOStreamID
В SQL Server 2000 запрос выше последовательно генерирует план стоимости 946. Если я раскомментирую соединение MO_Stream в середине запроса и закомментирую его внизу, стоимость снижается до 263. Скорость выполнения падает соответственно. Я всегда думал, что оптимизатор запросов будет интерпретировать запрос соответствующим образом, не учитывая порядок объединения, но кажется, что порядок имеет значение.
Итак, поскольку порядок действительно имеет значение, существует ли стратегия объединения, которую я должен выполнять для написания более быстрых запросов?
(Кстати, на SQL Server 2005 с почти идентичными данными стоимость плана запроса составляла 0,675 и 0,631 соответственно.)
Изменить: В SQL Server 2000, вот профилированная статистика:
-
946-cost query: 9094ms CPU, 5121 reads, 0 writes, 10123ms duration
-
263-cost query: 172ms CPU, 7477 reads, 0 writes, 170ms duration
Изменить: Вот логическая структура таблиц.
SessionRange ---+--- SessionRangeTutor
|--- SessionRangeClass
|--- SessionRangeStream --- MO_Stream
|--- SessionRangeEnrolmentPeriod
|--- SessionRangeStudent
+----SessionSubrange --- SessionSubrangeRoom
Изменить: Спасибо Alex и gbn за то, что указали мне в правильном направлении. Я также нашел этот вопрос.
Здесь новый запрос:
select sr.WTSASessionRangeID // + lots of columns
from WTSAVW_UserSessionRange us
inner join WTSA_SessionRange sr on sr.WTSASessionRangeID = us.WTSASessionRangeID
left outer join WTSA_SessionRangeTutor srt on srt.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeClass src on src.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeEnrolmentPeriod srep on srep.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeStudent stsd on stsd.WTSASessionRangeID = sr.WTSASessionRangeID
// SessionRangeStream is a many-to-many mapping table between SessionRange and MO_Stream
left outer join (
WTSA_SessionRangeStream srs
inner join MO_Stream ms on ms.MOStreamID = srs.MOStreamID
) on srs.WTSASessionRangeID = sr.WTSASessionRangeID
// SessionRanges MAY have Subranges and Subranges MAY have Rooms
left outer join (
WTSA_SessionSubrange ssr
left outer join WTSA_SessionSubrangeRoom ssrr on ssrr.WTSASessionSubrangeID = ssr.WTSASessionSubrangeID
) on ssr.WTSASessionRangeID = sr.WTSASessionRangeID
Стоимость SQLServer2000: 24,9