web-dev-qa-db-fra.com

Laquelle est la plus efficace: sélectionner à partir du serveur lié ou insérer dans le serveur lié?

Supposons que je doive exporter des données d'un serveur à un autre (via des serveurs liés). Quelle affirmation sera plus efficace?

Exécution sur le serveur source:

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

Ou en exécutant sur le serveur cible:

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

Lequel sera le plus rapide et consommera moins de ressources au total (serveur source et serveur cible)? Les deux serveurs sont SQL Server 2005.

32

Supposons que je doive exporter des données d'un serveur à un autre.

Le mieux est d'utiliser

  • SI vous voulez que toutes les données utilisent la sauvegarde/restauration; BCP OUT & BCP IN ou SSIS
  • SI vous voulez un sous-ensemble de données (certaines tables uniquement) utilisez SSIS ou BCP OUT & BCP IN

Pour déplacer des données, selon la quantité/taille des données et la bande passante n/w, le serveur lié tuera les performances.

Exécution sur le serveur source Ou exécution sur le serveur cible - Lequel sera le plus rapide et consommera moins de ressources au total (à la fois le serveur source et le serveur cible)?

- Exécution sur le serveur source:

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

Cela s'appelle PUSHING Data lorsque vous exécutez la requête sur le serveur source et que vous transférez les données vers le serveur de destination. Ce sera une opération coûteuse.

--- exécution sur le serveur cible

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

Cela s'appelle PULLING Data lorsque vous exécutez la requête sur le serveur de destination et que vous extrayez des données du serveur source. Ce sera beaucoup plus rapide et nécessitera moins de ressources par rapport à l'ancien (selon la quantité de données extraites).

Dans le cas de la méthode d'extraction, à l'aide de SQL Profiler, vous verrez qu'une seule instruction SQL est exécutée sur le serveur lié (serveur source) et l'ensemble de résultats est transféré du serveur source au serveur de destination, ce qui représente un énorme gain de performances par rapport à Push. méthode.

Un autre point à noter est:

Entre le serveur lié (convention de dénomination en 4 parties utilisée servername.databasename.schema.tablename a.k.a Distributed Queries) et OPENQUERY, OPENQUERY sera généralement rapide. Pourquoi?

Pour le serveur lié - L'optimiseur de requêtes crée un plan d'exécution en examinant la nomenclature des requêtes et la divise en requêtes distantes et locales. Les requêtes locales sont exécutées localement et les données des requêtes distantes sont collectées à partir des serveurs distants, nettoyées localement, combinées ensemble et présentées à l'utilisateur final sous la forme d'un jeu d'enregistrements unique.

Pour OPENQUERY - Exécute la requête d'intercommunication spécifiée sur le serveur lié spécifié. SQL Server envoie des requêtes directes sous forme de chaînes de requête non interprétées à une source de données OLE DB. Par conséquent, SQL n'appliquera aucun type de logique à la requête et n'essaiera pas d'estimer ce que cette requête ferait, elle transmettrait simplement la requête spécifiée telle qu'elle est au serveur lié cible. Les requêtes ouvertes sont utiles lorsque vous ne faites pas référence à plusieurs serveurs dans une même requête. C'est généralement rapide car SQL ne la décompose pas en plusieurs opérations et n'effectue aucune action locale sur la sortie reçue.

Excellentes références de lecture:

29
Kin Shah

Comment mesurez-vous l'efficacité? Lequel sera le plus rapide? Lequel consommera le moins de ressources sur la cible? sur la source? Combien de lignes et quel type de types de données les colonnes de ces lignes? Êtes-vous sûr de pouvoir exécuter un TVF via un serveur lié (est la cible SQL 2008 ou version ultérieure?) ? Comment garantissez-vous une migration 1: 1 de ces données si vous extrayez d'un TVF?

Avec ces questions à l'écart ...

Mise à jour 1

Il semble que vous recherchiez ETL (Extract-Transform-Load). Je recommanderais SSIS (SQL Server Integration Services) avec lequel vous pouvez extraire les données de la source, appliquer les transformations dont vous avez besoin, puis les charger dans votre cible. Cela ressemble à un package assez simple (selon les transformations).


La sagesse conventionnelle indique que l'approche du serveur lié ira au lien, tirera les données vers le serveur local, puis appliquera toute logique (filtres, jointures, etc.) sur le serveur local. Il y a une surcharge pour récupérer les données sur le serveur lié, mais la majorité du traitement sera gérée localement.

La méthode OPENQUERY placera le traitement sur le serveur distant et les "résultats filtrés" seront reçus par le serveur local.

Il semble que même si vous pouviez exécuter un TVF via un serveur lié, vous obtiendriez le pire des deux mondes, le traitement à distance et le traitement local (en supposant que vous aviez une logique supplémentaire à appliquer sur le ensemble).

Selon la façon dont vous décidez d'aller de l'avant, j'examinerais également OPENQUERY comme moyen d'importer/exporter des données en bloc.

Ceci dit ...

Si à la fois la source et la cible sur SQL Server (et que la cible n'est pas une version inférieure), pourquoi ne pas faire une sauvegarde et une restauration des données? Ce serait une véritable migration de données. Voici du code pour vous.

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;

Vous pouvez vous référer à cette réponse sur la façon d'utiliser les modèles dans SSMS.

8
swasheck