En mi oficina, tenemos una consulta que es bastante fea, pero que funciona bastante bien en la producción y en el entorno de desarrollo (20 segundos y 4 segundos respectivamente). Sin embargo, en nuestro entorno de prueba, lleva más de 4 horas. SQL2005 (+ parches más recientes) se está ejecutando en producción y desarrollo. SQL2008R2 se está ejecutando en las pruebas.
Eché un vistazo al Plan de consulta, y muestra que SQL2008R2 está utilizando TempDB, a través de un Spool de tabla (spool perezoso) para almacenar las filas devueltas desde el servidor vinculado. El siguiente paso es mostrar Nested Loops (izquierda anti semi-unión) como consumiendo el 96.3% de la consulta. ¡La línea entre los dos operadores está en 5,398MB!
El plan de consulta para el SQL 2005 no muestra el uso de tempdb ni el uso de una Anti Semi Join Izquierda.
A continuación se muestra el código desinfectado y los planes de ejecución, el plan de 2005 en la parte superior, el 2008R2 en la parte inferior.
¿Qué está causando la drástica desaceleración y cambio? Esperaba ver un plan de ejecución diferente, así que eso no me molesta. La dramática desaceleración en el tiempo de consulta es lo que me preocupa.
¿Tengo que mirar el hardware subyacente, ya que la versión 2008R2 está usando tempdb, tengo que ver cómo optimizar el uso de eso?
¿Hay una mejor manera de escribir la consulta?
Gracias por la ayuda.
INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT
Table1.iGroupID,
GETDATE()
FROM Table1
WHERE
NOT EXISTS (
SELECT 1
FROM LinkedServer.Database.Table2 Alias2
WHERE
(
Alias2.FirstName + Alias2.LastName = dbo.fnRemoveNonLetter(Table1.FullName)
AND NOT dbo.fnRemoveNonLetter(Table1.FullName) IS NULL
AND NOT Alias2.FirstName IS NULL
AND NOT Alias2.LastName IS NULL
) OR (
Alias2.FamilyName = dbo.fnRemoveNonLetter(Table1.FamilyName)
AND Alias2.Child1Name = dbo.fnRemoveNonLetter(Table1.Child1Name)
AND NOT dbo.fnRemoveNonLetter(Table1.FamilyName) IS NULL
AND NOT dbo.fnRemoveNonLetter(Table1.Child1Name) IS NULL
AND NOT Alias2.Familyname IS NULL
AND NOT Alias2.Child1Name IS NULL
) OR (
Alias2.StepFamilyName = dbo.fnRemoveNonLetter(Table1.StepFamilyName)
AND Alias2.StepFamilyNameChild1 = dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2)
AND NOT Alias2.StepFamilyName IS NULL
AND NOT Alias2.StepFamilyNameChild1 IS NULL
AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyName) IS NULL
AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2) IS NULL
)
) AND NOT EXISTS (
SELECT 1
FROM Table3
INNER JOIN Table4
ON Table4.FirstNameType = Table3.FirstNameType
INNER JOIN table5
ON table5.LastNameType = Table3.LastNameType
WHERE
Table3.iGroupID = Table1.iGroupID
AND Table3.bIsClosed = 0
AND Table4.sNameTypeConstant = 'new_lastname'
AND table5.sFirstNameConstant = 'new_firstname'
)
:: EDITAR :: Ejecuté la consulta desde una instancia SQL2005 diferente, más o menos el mismo plan de ejecución que el "bueno". Todavía no estoy seguro de cómo las dos versiones de 2005 funcionan mejor para el servidor vinculado 2008R2, que las instancias de 2008R2 a las instancias de 2008R2.
Si bien no niego que el código podría usar algo de trabajo, si el problema fuera el código, ¿no vería los mismos planes ejecutivos en todas mis pruebas? Independientemente de la versión de SQL?
:: EDITAR :: He aplicado SP1 y CU3 a las dos instancias de 2008R2, todavía no hay dados. He establecido específicamente la colocación en el servidor vinculado, sin dados. He establecido específicamente permisos de mi cuenta de usuario para ser administrador del sistema en ambas instancias, sin dados. También he recordado mis aspectos internos y la resolución de problemas de mi servidor sql 2008, veremos si puedo rastrear esto de alguna manera.
Gracias a todos por la ayuda y los consejos.
:: EDITAR :: He realizado varios cambios de permisos en el servidor vinculado. He usado inicios de sesión de SQL, inicios de sesión de dominio, he suplantado a usuarios, he usado la opción "hacerse usando este contexto de seguridad". He creado usuarios en ambos lados del servidor vinculado que tienen derechos de administrador del sistema en el servidor. Se me acabaron las ideas.
Todavía me gustaría saber por qué SQL2005 está ejecutando la consulta tan dramáticamente diferente de SQL2008R2. Si la consulta fuera mala, vería el tiempo de ejecución de más de 4 horas en SQL2005 y SQL2008R2.
fuente
+1 en Intente reescribir su comentario de consulta de datagod.
También me pregunto si se topa con un problema de permisos en el lado del servidor vinculado que conduce a esta desaceleración. Hace un blog escribí sobre esta desaceleración del servidor vinculado hace un tiempo. Puede valer la pena verificar los permisos (¿es un servidor vinculado a SQL? ¿O es otro DBMS? Si es el último, entonces no obtendrá excelentes estadísticas de todos modos)
¿Todavía tiene SQL Server 2005 en el entorno de prueba para probar esta consulta y descartar el entorno?
¿Has reconstruido las estadísticas desde la actualización?
fuente
Hay tantos problemas con esta comparación ... Simplemente no sé por dónde empezar.
Obtenga las especificaciones exactas para sus máquinas de producción y prueba.
Determine los enlaces de red entre los diversos servidores vinculados en ambos entornos. ¿Son la misma velocidad? ¿Están los servidores ubicados uno al lado del otro en ambos entornos?
¿Hay alguna forma de reescribir la consulta para NO usar servidores vinculados? Unir tablas en los servidores lo deja vulnerable a los cambios de topología, y su espantosa lentitud en la mayoría de los casos.
El uso de NOT y OR generalmente lleva a escaneos completos de la tabla. Intente reescribir la consulta.
fuente