Es una selección simple de una tabla temporal, uniendo a la izquierda una tabla existente en su clave primaria, con dos sub-selecciones usando el top 1 que hace referencia a la tabla unida.
En codigo:
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
JoinedTable.Col1,
JoinedTable.Col2,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,
FROM
#TempTable as TempTable
LEFT JOIN
JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn1 AND
TempTable.PKColumn2 = JoinedTable.PKColumn2)
WHERE
JoinedTable.WhereColumn IN (1, 3)
Esta es una réplica exacta de mi consulta.
Si elimino las dos subelecciones, se ejecuta muy bien y rápidamente. Con las dos sub-selecciones, obtengo alrededor de 100 registros por segundo, lo cual es extremadamente lento para esta consulta porque debería devolver casi un millón de registros.
Verifiqué si cada tabla tiene una Clave primaria, todas las tienen. Todos tienen índices Y estadísticas para sus columnas importantes, como las de las cláusulas WHERE y las de la cláusula JOIN. La única tabla sin clave primaria definida ni índice es la tabla temporal, pero tampoco es el problema porque no está relacionada con las subselecciones lentas y, como mencioné, sin subselecciones, funciona bien.
Sin ellos TOP 1
, devuelve más de un resultado y genera un error.
Ayuda, alguien?
EDITAR :
Entonces el plan de ejecución me dijo que me faltaba un índice. Lo creé y recreé algunos de los otros índices. Después de un tiempo, el plan de ejecución los estaba usando, y la consulta ahora se ejecuta rápidamente. El único problema es que no logro volver a hacerlo en otro servidor, para la misma consulta. Entonces, mi solución será SUGERIR qué índice utilizará SQL Server.
Respuestas:
Creo que en una consulta de un millón de registros, debes evitar cosas como
OUTER JOINS
. Te sugiero que uses enUNION ALL
lugar deLEFT JOIN
. Siempre que piense queCROSS APPLY
es más eficiente que la subconsulta en la cláusula select, modificaré la consulta escrita por Conard Frix, que creo que es correcta.Ahora: cuando empecé a modificar la consulta me di cuenta de que tiene una cláusula WHERE diciendo:
JoinedTable.WhereColumn IN (1, 3)
. en este caso, si el campo es nulo, la condición se convertirá en falsa. entonces, ¿por qué está utilizando LEFT JOIN mientras filtra filas con valores nulos? simplemente reemplaceLEFT JOIN
conINNER JOIN
, le garantizo que será más rápido.sobre ÍNDICE:
tenga en cuenta que cuando tenga un índice en una tabla, diga
y tu índice es:
y quieres hacer algo como esto:
en su índice no ha incluido la columna,
b
¿qué sucede?si sql-server usa su índice, tendrá que buscar en el índice, llamado "Búsqueda de índice" y luego consultar la tabla principal para obtener la columna
b
, llamada "Buscar" . Este procedimiento puede llevar mucho más tiempo que escanear la tabla en sí: "Escaneo de tabla" .pero en base a las estadísticas que tiene sql-server, en tales situaciones, es posible que no use su índice en absoluto.
así que antes que nada, verifique
Execution Plan
si el índice se usa en absoluto.en caso afirmativo o no ambos, modifique su índice para incluir todas las columnas que está seleccionando. decir como:
en este caso, Look Up no será necesario y su consulta se ejecutará mucho más rápido.
fuente
Es la sub selección en su selección de columna que está causando el lento retorno. Debería intentar usar sus sub-selecciones en combinaciones izquierdas, o usar una tabla derivada como la que he definido a continuación.
Usar combinaciones izquierdas en dos instancias de la tercera tabla
Usando una tabla derivada
fuente
Intente una aplicación cruzada en su lugar
También puede usar CTE y row_number o una consulta en línea usando MIN
fuente
Mueva los bits JOIN fuera de la parte principal de la cláusula y póngalo como una subselección. Moverlo a la sección DONDE y UNIR le garantiza que no tiene que SELECCIONAR TOP 1 una y otra vez, lo cual creo que es la razón de la lentitud. Si desea verificar esto, examine el plan de ejecución.
fuente
Las
ThirdTable
referencias (subselecciones en su ejemplo) necesitan la misma atención de índice que cualquier otra parte de una consulta.Independientemente de si usa sub selecciones:
IZQUIERDA SE UNE (según lo propuesto por John Hartsock):
APLICACIÓN CRUZADA (según lo propuesto por Conrad Frix):
Usted necesita asegurarse
covering indexes
están definidos paraThirdTable.SomeColumn
yThirdTable.SomeOtherColumn
y los índices es único. Esto significa que deberá calificar aún más lasThirdTable
referencias para eliminar la selección de varias filas y mejorar el rendimiento. La elección desub selects
,LEFT JOIN
oCROSS APPLY
no importará realmente hasta que mejore la selectividad paraThirdTable.SomeColumn
eThirdTable.SomeOtherColumn
incluyendo más columnas para garantizar una selectividad única. Hasta entonces, espero que su desempeño continúe sufriendo.El
covering index
tema es muy bien presentado por Maziar Taheri; Si bien no repito su trabajo, hago hincapié en la necesidad de tomar en serio el uso de índices de cobertura.En resumen: mejore la selectividad para las consultas
ThirdTable.SomeColumn
yThirdTable.SomeOtherColumn
(o combinaciones) agregando columnas relacionadas en la tabla para garantizar una coincidencia de fila única. Si esto no es posible, continuará sufriendo problemas de rendimiento ya que el motor está ocupado tirando en filas que posteriormente se tiran. Esto afecta su E / S, CPU y, en última instancia, el plan de ejecución.fuente