Estoy construyendo una vista en SQL Server 2000 (y 2005) y me he dado cuenta de que el orden de las instrucciones de combinación afecta en gran medida el plan de ejecución y la velocidad de la consulta.¿Por qué el orden de las cláusulas de unión afecta el plan de consulta en SQL Server?
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
En SQL Server 2000, la consulta anterior genera constantemente un plan de costo 946. Si elimine el comentario MO_Stream unirse en el medio de la consulta y comente la otra en la inferior, el costo se reduce a 263. La velocidad de ejecución cae en consecuencia. Siempre pensé que el optimizador de consultas interpretaría la consulta de manera apropiada sin considerar el orden de unión, pero parece que el orden es importante.
Por lo tanto, dado que la orden hace parece importar, ¿hay alguna estrategia de unión que deba seguir para escribir consultas más rápidas?
(Por cierto, en SQL Server 2005, con datos casi idénticos, los costos del plan de consulta fueron 0,675 y 0,631, respectivamente.)
Editar: En SQL Server 2000, aquí están las estadísticas perfiladas:
946-cost query: 9094ms CPU, 5121 reads, 0 writes, 10123ms duration
263-cost query: 172ms CPU, 7477 reads, 0 writes, 170ms duration
Edit: Aquí está la estructura lógica de las tablas.
SessionRange ---+--- SessionRangeTutor
|--- SessionRangeClass
|--- SessionRangeStream --- MO_Stream
|--- SessionRangeEnrolmentPeriod
|--- SessionRangeStudent
+----SessionSubrange --- SessionSubrangeRoom
Editar: Gracias a Alex y GBN para mí apuntando en la dirección correcta. También encontré this question.
Aquí está la nueva consulta:
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
costo SQLServer2000: 24.9
Depende de la estructura de las tablas. Estás en lo correcto para el caso T1-T2, T2-T3. En mi situación, es T1-T2, T1-T3. – geofftnz
@geofftnz: ver mi respuesta. Usted * no * T1-T2, T1-T3 – gbn