Je rencontre une situation avec un serveur lié que je ne peux pas comprendre.
Nous avons donc un serveur lié d'un serveur 2008R2 à un serveur 2014. L'exemple de requête ci-dessous s'exécute à partir du serveur 2008R2 et fonctionne correctement.
SET XACT_ABORT ON;
Declare @BatchSize int = 10
DELETE from LINKEDSRV.DB.DBO.Table
INSERT INTO LINKEDSRV.DB.DBO.Table (ECN)
SELECT TOP (10) C1 from LINKEDSRV.DB.DBO.Table22 --order by C1
SELECT * FROM LINKEDSRV.DB.DBO.Table
Mais quand j'exécute la même chose avec le order by C1
Cela ne renvoie aucun résultat.
Deuxième cas - Si je remplace la TOP(10)
par TOP(@BatchSize)
et non order by
Aussi je ne reçois aucun résultat. par exemple
SELECT TOP (@BatchSize) C1 from LINKEDSRV.DB.DBO.Table22
Tous les scénarios fonctionnent si je SET XACT_ABORT OFF
. Est-ce que XACT_ABORT a une sorte de restriction en ce qui concerne le serveur lié?
Edit - A fait quelques tests supplémentaires et il semble que cela doive aussi faire quelque chose avec le nombre de lignes
Repo possible
Sur le serveurA
use testdb
go
create table t1( c1 int, c2 datetime)
create table t2( c1 int, c2 datetime)
insert into t2 select 1, GETDATE()
insert into t2 select * from t2 -- insert close to 5000 rows, I found the issue around over around 35000 rows
Sur ServerB
Créer un serveur lié à ServerA
SET XACT_ABORT ON;
Declare @BatchSize int = 10
delete from ServerA.testdb.dbo.t1
insert into ServerA.testdb.dbo.t1 (c1)
select top (@BatchSize) c1 from ServerA.testdb.dbo.t2 --order by c2
select * from ServerA.testdb.dbo.t1
Aucune sortie. Mais si vous réduisez le nombre de lignes dans le tableau t2 pour dire environ 2000, cela fonctionne très bien.
Tous les scénarios fonctionnent si je
SET XACT_ABORT OFF
.XACT_ABORT
a une sorte de restriction en ce qui concerne le serveur lié?
Le réglage de XACT_ABORT
est propagé au serveur SQL distant, comme indiqué dans Gestion des erreurs dans les procédures stockées à distance de serveur à serveur .
Le paramètre affecte également si les mises à jour sont possibles et comment elles sont gérées, comme indiqué dans Requêtes distribuées et transactions distribuées . Votre INSERT
est autorisé avec XACT_ABORT OFF
car SQL Server prend en charge les transactions imbriquées.
Néanmoins, il semble y avoir un bogue d'implémentation, car le suivi de l'activité sur le serveur 2014 lors de l'insertion révèle qu'une erreur se produit lorsque SQL Server tente de libérer un verrou de schéma:
Cette erreur annule l'instruction (tentative de libération du verrou de schéma) sur le serveur distant, mais lorsque XACT_ABORT
est OFF
, le serveur distant continue de traiter l'instruction suivante. L'insertion se termine, malgré l'erreur de libération du verrouillage du schéma.
Quand XACT_ABORT
est ON
, tout le lot distant est abandonné, donc l'insertion est annulée.
J'ai pu reproduire votre problème localement, mais le ORDER BY
la clause n'était pas significative.
Vous pouvez éviter le problème de plusieurs manières, notamment en enveloppant le INSERT
dans une transaction explicite (en supposant que DTC soit disponible).
Je vous recommande d'éviter la syntaxe de nom en quatre parties pour les modifications à distance, car l'implémentation est basée sur un modèle de curseur. Vous obtiendrez normalement de meilleures performances en utilisant une méthode en bloc, ou en en tirant les données sur le serveur distant (plutôt que en le poussant depuis le serveur local).
Voir les questions et réponses connexes Laquelle est la plus efficace: sélectionner à partir du serveur lié ou insérer dans le serveur lié?
D'après mon expérience, l'exécution de commandes en plusieurs parties via un serveur lié est généralement confrontée à des problèmes, en particulier lorsque les tables sont grandes. Essaye ça :
SET XACT_ABORT ON;
Declare @BatchSize int = 10
delete from ServerA.testdb.bbo.t1
select top (@BatchSize) c1 INTO #t2temp from ServerA.testdb.dbo.t2
insert into ServerA.testdb.dbo.t1 (c1)
SELECT * FROM #t2temp
select * from ServerA.testdb.dbo.t1