2012-08-11 19 views
5

Tengo algunas identificaciones insertado en una tabla temporal #A de la siguiente manera:Dos consultas. Misma salida. Uno tarda 2 horas y el otro 0 segundos. ¿Por qué?

SELECT DISTINCT ID 
INTO #A 
FROM LocalDB.dbo.LocalTable1 
WHERE ID NOT IN (SELECT DISTINCT ID FROM LocalDB.dbo.LocalTable2) 
GO 

CREATE INDEX TT ON #A(ID) 
GO 

Estoy tratando de obtener alguna información de un servidor vinculado remoto utilizando los identificadores que se reunieron en la etapa anterior:

de consultas 1:

SELECT ID, Desc 
FROM RemoteLinkedServer.DB.dbo.RemoteTable X 
WHERE ID IN (SELECT ID FROM #A) 

consulta 2:

SELECT ID, Desc 
FROM RemoteLinkedServer.DB.dbo.RemoteTable X 
INNER JOIN #A Y 
ON X.ID = Y.ID 

Ahora en la siguiente consulta, lo que estoy haciendo es obtener el resultado de la tabla temporal, copiar las filas y formatearlas adecuadamente en una lista separada por comas y ponerla manualmente en la consulta.

Consulta 3:

SELECT ID, Desc 
FROM RemoteLinkedServer.DB.dbo.RemoteTable X 
WHERE ID IN (-- Put all identifiers here --) 

consultas 1 y 2 toma 2 horas para ejecutar y consulta 3 toma 0 segundos (mi tabla temporal contiene alrededor de 200 filas). No sé lo que está pasando y no tengo permisos para verificar si el servidor remoto tiene los índices relevantes en el ID, pero es simplemente desconcertante ver que una consulta construida manualmente se ejecuta en un momento que indica que hay algo que está yendo mal en la fase de optimización de consultas.

¿Alguna idea sobre qué está pasando mal aquí o cómo podría acelerar mi consulta?

Respuesta

10

Las consultas 1 y 2 provocan que TODOS los datos en la RemoteTable sean arrastrados a su base de datos local para realizar la operación de unión. Esto va a comer RAM, ancho de banda de red y, en general, será muy lento mientras se ejecuta la consulta.

Query 3 permite que el servidor remoto filtre los resultados para enviar solo las coincidencias que desee.

Básicamente, todo se reduce a quién hace el trabajo. Las consultas 1/2 requieren que su DB local lo haga; Query 3 permite que el remoto lo haga.

Si usted tiene una gran cantidad de datos en esa tabla remota, entonces lo más probable es encontrarse con congestión de la red, etc.

El mejor enfoque para la consulta de los servidores vinculados es construir las consultas tales como el servidor remoto hace todo el trabajo y simplemente envía los resultados a su local. Esto optimizará la cantidad de recursos de red, memoria y disco necesarios para obtener los datos que desea.

Cada vez que tiene que unirse a los límites del servidor (utilizando un servidor vinculado) va a ser un desastre.

+1

+1 Honestamente, no sabía eso! Gracias por la aclaración. Entonces, ¿cómo envío mis valores locales al servidor vinculado remoto y obtengo los resultados? 'CURSOR's y luego enviar un identificador a la vez? La tabla remota es enorme, con alrededor de 10 millones de filas. – Legend

+2

Probablemente su mejor opción sea construir dinámicamente el sql para ejecutar contra el servidor remoto y simplemente ejecutarlo.Descubrimos que este método es mucho más rápido para cada tipo de llamada que hacemos a los servidores vinculados. Usar un cursor y ejecutar una consulta a la vez puede hacer que aciertes los límites de velocidad de transacción; que puede que no quieras – NotMe

+0

Gracias por la sugerencia. Ya no hay más cuellos de botella y mi script está funcionando bien con esta optimización. – Legend

3

Como referencia, así es como he resuelto el problema en base a @ ChrisLively de sugerencias:

SELECT DISTINCT ID 
INTO #A 
FROM LocalDB.dbo.LocalTable1 
WHERE ID NOT IN (SELECT DISTINCT ID FROM LocalDB.dbo.LocalTable2) 
GO 

CREATE INDEX TT ON #A(ID) 
GO 

DECLARE @IDList VARCHAR(MAX) 
SELECT @IDList=(SELECT TOP 1 REPLACE(RTRIM((
       SELECT DISTINCT CAST(ID AS VARCHAR(MAX)) + ' ' 
       FROM #A AS InnerTable    
       FOR XML PATH (''))),' ',', ')) 
FROM #A AS OuterResults 


DECLARE @sql AS varchar(MAX) 
SET @sql = 'SELECT * FROM RemoteLinkedServer.RemoteDB.dbo.RemoteTable X WHERE ID IN (' + @IDList + ')' 

EXEC (@sql) 

DROP TABLE #A 
GO 
+0

Así es exactamente como lo abordaría. – NotMe

+0

@ChrisLively: Gracias por la confirmación :) – Legend

Cuestiones relacionadas