¿Cuál es más eficiente: seleccionar del servidor vinculado o insertar en el servidor vinculado?

32

Supongamos que tengo que exportar datos de un servidor a otro (a través de servidores vinculados). ¿Qué afirmación será más eficiente?

Ejecutando en el servidor de origen:

INSERT INTO [DestinationLinkedServer].[DestinationDB].[dbo].[Table]
SELECT a, b, c, ... FROM [dbo].Udf_GetExportData()

O ejecutando en el servidor de destino:

INSERT INTO [dbo].[Table]
SELECT a, b, c, ...
FROM OPENQUERY([OriginLinkedServer],
    'SELECT a, b, c, ... FROM [OriginDB].[dbo].Udf_GetExportData()')

¿Cuál será más rápido y consumirá menos recursos en total (tanto el servidor de origen como el de destino)? Ambos servidores son SQL Server 2005.

Guillermo Gutiérrez
fuente

Respuestas:

29

Supongamos que tengo que exportar datos de un servidor a otro.

Lo mejor es usar

  • SI desea que todos los datos utilicen Copia de seguridad / Restauración; BCP OUT y BCP IN o SSIS
  • SI desea un subconjunto de datos (solo algunas tablas) use SSIS o BCP OUT y BCP IN

Para mover datos, dependiendo de la cantidad / tamaño de datos y el ancho de banda n / w, el servidor vinculado matará el rendimiento.

Ejecutando en el servidor de origen O ejecutando en el servidor de destino: ¿Cuál será más rápido y consumirá menos recursos en total (tanto el servidor de origen como el de destino)?

- Ejecución en el servidor de origen:

INSERT INTO [DestinationLinkedServer].[DestinationDB].[dbo].[Table]
SELECT a, b, c, ... FROM [dbo].Udf_GetExportData()

Esto se llama EMPUJAR datos mientras ejecuta la consulta en el servidor de origen e inserta los datos en el servidor de destino. Esta será una operación costosa.

--- ejecutándose en el servidor de destino

INSERT INTO [dbo].[Table]
SELECT a, b, c, ...
FROM OPENQUERY([OriginLinkedServer],
    'SELECT a, b, c, ... FROM [OriginDB].[dbo].Udf_GetExportData()')

Esto se llama PULLING Data ya que está ejecutando la consulta en el servidor de destino y extrayendo datos del servidor de origen. Esto será mucho más rápido y menos intensivo en recursos en comparación con el anterior (dependiendo de la cantidad de datos que se extraigan).

En el caso del método de extracción, al usar el Analizador de SQL verá que se ejecuta una sola instrucción SQL en el servidor vinculado (servidor de origen), y el conjunto de resultados se extrae del servidor de origen al servidor de destino, lo que es una gran ganancia de rendimiento sobre PUSH método.

Otro punto a tener en cuenta es:

Entre el servidor vinculado (la convención de nomenclatura de 4 partes utilizó servername.databasename.schema.tablename aka Consultas distribuidas) y OPENQUERY, generalmente OPENQUERY será rápido. Por qué ?

Para el servidor vinculado : el optimizador de consultas crea un plan de ejecución mirando la nomenclatura de la consulta y la divide en consultas remotas y locales. Las consultas locales se ejecutan localmente y los datos de las consultas remotas se recopilan de los servidores remotos, se depuran localmente, se combinan y se presentan al usuario final como un conjunto de registros único.

Para OPENQUERY : ejecuta la consulta de paso especificada en el servidor vinculado especificado. SQL Server envía consultas de transferencia como cadenas de consulta no interpretadas a un origen de datos OLE DB. Por lo tanto, SQL no aplicará ningún tipo de lógica en la consulta y no intentará estimar qué haría esa consulta, simplemente pasaría la consulta especificada tal como es al servidor vinculado de destino. Las consultas abiertas son útiles cuando no hace referencia a varios servidores en una consulta. Generalmente es rápido ya que SQL no lo divide en múltiples operaciones y no realiza ninguna acción local en la salida recibida.

Excelentes referencias de lectura:

Kin Shah
fuente
8

¿Cómo estás midiendo la eficiencia? ¿Cuál será más rápido? ¿Cuál consumirá menos recursos en el objetivo? en la fuente? ¿Cuántas filas y qué tipo de tipos de datos son las columnas en estas filas? ¿Está seguro de que puede ejecutar un TVF a través de un servidor vinculado (es el objetivo de SQL 2008 o posterior) ? ¿Cómo está asegurando una migración 1: 1 de estos datos si está extrayendo de un TVF?

Con esas preguntas fuera del camino ...

Actualización 1

Parece que estás buscando ETL (Extract-Transform-Load). Recomiendo SSIS (SQL Server Integration Services) con el que puede extraer los datos de la fuente, aplicar las transformaciones que necesita y luego cargarlas en su destino. Esto suena como si fuera un paquete bastante sencillo (dependiendo de las transformaciones).


La sabiduría convencional establece que el enfoque del servidor vinculado saldrá al enlace, extraerá los datos al servidor local y luego aplicará cualquier lógica (filtros, uniones, etc.) en el servidor local. Hay algunos gastos generales para recuperar los datos en el servidor vinculado, pero la mayoría del procesamiento se manejará localmente.

El método OPENQUERY colocará el procesamiento en el servidor remoto y el servidor local recibirá los "resultados filtrados".

Parece que incluso si pudiera ejecutar un TVF a través de un servidor vinculado, estaría obteniendo lo peor de ambos mundos, procesando de forma remota y procesando localmente (suponiendo que tuviera una lógica adicional para aplicar en el conjunto).

Dependiendo de cómo decidas seguir adelante, también examinaría OPENQUERY como un medio para importar / exportar datos en masa.

Habiendo dicho todo eso ...

Si tanto el origen como el destino en SQL Server (y el destino no es una versión inferior), ¿por qué no hacer una copia de seguridad y restauración de los datos? Esta sería una verdadera migración de datos. Aquí hay un código para ti.

BACKUP DATABASE <DatabaseName, sysname, DatabaseName>
TO DISK=N'<backup_location, varchar, BackupLocation>.bak'
WITH INIT, FORMAT, COMPRESSION, COPY_ONLY

RESTORE DATABASE <NewDatabaseName, sysname, NewDatabaseName>
FROM DISK = N'<backup_location, varchar, BackupLocation>\
    <DatabaseName, sysname, DatabaseName>.bak'
WITH 
    MOVE '<DataFileName, sysname, DataFileName>' TO '<DataMDFPath, nvarchar(600), DataMDFPath>',
    MOVE '<LogFilePath, sysname, LogFilePath>' TO '<LogLDFPath, nvarchar(600), LogLDFPath>',
    REPLACE;

Puede consultar esta respuesta sobre cómo usar plantillas en SSMS.

swasheck
fuente