Rendimiento del servidor vinculado de SQL Server: ¿por qué las consultas remotas son tan caras?


14

Tengo dos servidores de bases de datos, conectados a través de servidores vinculados. Ambas son bases de datos SQL Server 2008R2, y la conexión del servidor vinculado se realiza a través de un enlace regular "SQL Server", utilizando el contexto de seguridad del inicio de sesión actual. Los servidores vinculados están en el mismo centro de datos, por lo que la conexión no debería ser un problema.

Utilizo la siguiente consulta para verificar qué valores de la columna identifierestán disponibles de forma remota, pero no localmente.

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT DISTINCT
    identifier 
FROM LocalDb.schema.[TableName] 

En ambas tablas hay índices no agrupados en la columna identifier. A nivel local, hay alrededor de 2,6 millones de filas, de forma remota solo 54. Sin embargo, al mirar el plan de consulta, el 70% del tiempo de ejecución se dedica a "ejecutar consultas remotas". Además, al estudiar el plan de consulta completo, el número de filas locales estimadas es en 1lugar de 2695380(que es el número de filas estimadas al seleccionar solo la consulta que viene después EXCEPT). Plan de ejecución Al ejecutar esta consulta, lleva mucho tiempo.

Me hace preguntarme: ¿por qué es esto? ¿La estimación está "simplemente" lejos, o las consultas remotas en servidores vinculados son realmente tan caras?


2
Por cierto: es el "número estimado de ejecuciones" lo que debería estar buscando para la búsqueda del índice. El número estimado de filas es la salida de filas por ejecución que no estará relacionada con el número de filas en la tabla en sí, a menos que el plan tenga una exploración completa.
Martin Smith

Respuestas:


9

El plan que tienes en este momento me parece el plan más óptimo.

No estoy de acuerdo con la afirmación en las otras respuestas de que está enviando las 2.6M filas al servidor remoto.

El plan me parece que, para cada una de las 54 filas devueltas de la consulta remota, está realizando una búsqueda de índice en su tabla local para determinar si coincide o no. Este es más o menos el plan óptimo.

Reemplazar con un hash join o merge join sería contraproducente dado el tamaño de la tabla y agregar una #temptabla intermedia solo agrega un paso adicional que no parece darle ninguna ventaja.


6

Conectarse a un recurso remoto es costoso. Período.

Una de las operaciones más caras en cualquier entorno de programación es el IO de red (aunque el IO de disco tiende a empequeñecerlo).

Esto se extiende a servidores remotos vinculados. El servidor que llama al servidor vinculado remoto debe establecer primero una conexión, luego se debe ejecutar una consulta en el servidor remoto, devolver los resultados y cerrar la conexión. Todo esto lleva tiempo en la red.


También debe estructurar su consulta de tal manera que transfiera los datos mínimos a través del cable. No esperes que la base de datos se optimice para ti.

Si tuviera que escribir esta consulta, seleccionaría los datos remotos en una variable de tabla (o en una tabla temporal) y luego usaría esto junto con la tabla local. Esto asegura que solo los datos que deben transferirse lo harán.

La consulta que está ejecutando puede enviar fácilmente 2,6 millones de filas al servidor remoto para procesar la EXCEPTcláusula.


Ok, entonces tiene altos costos de inicio para configurar la conexión. La consulta debe enviarse, procesarse de forma remota (no se necesita red para esa) y, finalmente, los resultados deben devolverse y procesarse. Pero no tomará minutos enviar datos a través de una conexión de red, ¿verdad?
vstrien

@vstrien - Podría ser. Depende de la conexión de red, latencia, saturación y otros factores. Punto de ser - no es determinista.

@vstrien: se agregó más información en mi respuesta. Creo que la consulta como está escrita enviará las filas locales al servidor remoto para su procesamiento.

2
¿De dónde deduce el hecho de que está enviando las 2.6M filas al servidor remoto? No tengo mucha experiencia con planes con operadores de consultas remotas, pero parece que las 54 filas están saliendo del operador de consultas remotas, entonces está haciendo la semi unión contra la tabla local.
Martin Smith

2
@Lieven: puede ser lógico, pero no creo que sea correcto según el plan que se muestra.
Martin Smith

1

No soy un experto, pero si está utilizando Unión, Excepto o Intersección, no tiene que usar "Distinct". Dependiendo de los valores de LocalDb.schema. [TableName], el rendimiento de la consulta puede mejorarse.

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT 
    identifier 
FROM LocalDb.schema.[TableName]

0

Oded tiene razón, el problema de rendimiento se debe al envío de las filas de 2.6M a su servidor remoto.

Para solucionar este problema, puede forzar los datos remotos (54 filas) que se le envían utilizando una tabla temporal o en la tabla de memoria.

Usando una tabla temporal

SELECT  identifier 
INTO    #TableName
FROM    LinkedServer.RemoteDb.schema.[TableName]

SELECT  identifier
FROM    #TableName
EXCEPT
SELECT  DISTINCT identifier 
FROM    LocalDb.schema.[TableName] 

DROP    #TableName

El uso de una tabla temporal podría ayudar con las estimaciones de cardinalidad en cualquier caso, aunque un bucle anidado parece razonable para solo 54 filas.
Martin Smith

Usar una tabla temporal funciona bien con 54 filas; pero en casos con mesas grandes en ambos lados ya no es factible. ¿Cuál sería su solución para dos tablas "enormes" del mismo tamaño? ¿Crear una tabla de usuario en otra base de datos?
vstrien

1
@vstrien: no hay realmente una buena solución para dos tablas enormes del mismo tamaño. Quizás crear una vista particionada distribuida sea ​​de su interés, pero no tengo experiencia alguna con ella.
Lieven Keersmaekers

0

Creo que es mejor replicar la tabla remota al servidor desde el que realiza la consulta y luego ejecutar todo su SQL localmente.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.