Dans mes serveurs impliqués dans les groupes de disponibilité alwayson
S'il existe des emplois en cours d'exécution, dans les travaux, je teste toujours si le serveur actuel est le primary
dans le groupe de disponibilité.
Donc, le le travail ne fonctionne quesur le serveur principal de l'AG .
quelque chose comme ça fonctionne bien:
If sys.fn_hadr_is_primary_replica ('JUNOReporting') =1
BEGIN
declare @reportYear int, @reportMonth int, @reportMonthPrevious int
SELECT @reportYear = CASE WHEN month(getdate()) = 1 THEN year(getdate()) - 1 ELSE year(getdate()) END,
@reportMonth = CASE WHEN month(getdate()) = 1 THEN 12 ELSE month(getdate()) - 1 END
SELECT @reportMonthPrevious = @reportMonth - 1
EXEC JUNOReporting.dbo.usp_some_other_procedure_without_parameteres
END
Cependant, si au lieu de la procédure dbo.usp_some_other_procedure_without_parameteres
Cela vit dans la base de données appelée JunoReporting
, je souhaite appeler une procédure différente comportant des paramètres, puis SQL Server n'aime pas cela.
Je pense qu'il met le chariot devant les chevaux, mais comment puis-je lui dire?
lorsque j'ai le code suivant dans un emploi, le travail échoue:
declare @reportYear int, @reportMonth int, @reportMonthPrevious int
SELECT @reportYear = CASE WHEN month(getdate()) = 1 THEN year(getdate()) - 1 ELSE year(getdate()) END,
@reportMonth = CASE WHEN month(getdate()) = 1 THEN 12 ELSE month(getdate()) - 1 END
SELECT @reportMonthPrevious = @reportMonth - 1
If sys.fn_hadr_is_primary_replica ('JUNOReporting') =1
begin
-- this server is the primary replica, do something here
print 'yes, primary'
IF @reportMonthPrevious >= 1
BEGIN
EXEC JUNOReporting.dbo.usp_ins_feesDuePaid_ForMonth @reportYear, @reportMonthPrevious
END
EXEC JUNOReporting.dbo.usp_ins_feesDuePaid_ForMonth @reportYear, @reportMonth
END
avec le message d'erreur ennuyeux et évident - c'est exactement pourquoi je testais si le serveur actuel est dans le rôle principal de toute façon:
MSG 976, niveau 14, état 1, ligne 22
La base de données cible, "Junoporting", participe à un groupe de disponibilité et n'est actuellement pas accessible pour les requêtes. Soit le mouvement de données est suspendu ou la réplique de disponibilité n'est pas activée pour l'accès en lecture. Pour permettre un accès en lecture seule à cette information et d'autres bases de données dans le groupe de disponibilité, permettez l'accès en lecture à une ou plusieurs répliques de disponibilité secondaire dans le groupe. Pour plus d'informations, voir l'instruction ALTER DISPONIBILITABLES GROUPE dans SQL Server Books Online.
Des idées comment travailler autour de celui-ci? Je préfère ne pas ajouter ce morceau de code à l'intérieur de la procédure, donc en évitant le serveur SQL parameters
émetteur SQL semble avoir à l'occasion.
Juste pour effacer tout malentendu:
Sur le serveur Seconday de mon groupe de disponibilité (se compose de 2 serveurs uniquement), les bases de données ne sont pas accessibles comme vous pouvez le constater sur l'image ci-dessous.
Cela se produit car la procédure a des paramètres et la procédure est également appelée à partir d'une étape d'emploi.
Lorsque vous exécutez la requête en dehors du contexte de travail (SSMS), il doit s'exécuter simplement. La raison exacte pour laquelle cela se produit n'est toujours pas clair pour moi, j'ai essayé d'obtenir les commandes à travers le profileur et de le recréer dans ma fenêtre de requête, mais pas de dés là-bas.
Cependant, je sais que lorsque l'agent exécute des étapes de travail, le comportement non par défaut peut se produire. Un exemple de ceci est le fait que citer_identifier est désactivé dans le contexte de l'étape du travail:
De Microsoft:
Définir cible_identifier est activé (par défaut)
Quoi qu'il en soit, la solution de contournement que j'ai utilisée pour votre problème est de la mettre en SQL dynamique.
declare @reportYear int, @reportMonth int, @reportMonthPrevious int,@sql varchar(max)
SELECT @reportYear = CASE WHEN month(getdate()) = 1 THEN year(getdate()) - 1 ELSE year(getdate()) END,
@reportMonth = CASE WHEN month(getdate()) = 1 THEN 12 ELSE month(getdate()) - 1 END
SELECT @reportMonthPrevious = @reportMonth - 1
If sys.fn_hadr_is_primary_replica ('JUNOReporting') =1
begin
-- this server is the primary replica, do something here
print 'yes, primary'
IF @reportMonthPrevious >= 1
BEGIN
set @sql = 'EXEC JUNOReporting.dbo.usp_ins_feesDuePaid_ForMonth '+ cast(@reportYear as varchar(20)) +', '+ cast(@reportMonthPrevious as varchar(20))
exec(@sql)
END
set @sql = 'EXEC JUNOReporting.dbo.usp_ins_feesDuePaid_ForMonth '+ cast(@reportYear as varchar(20)) +', '+ cast(@reportMonth as varchar(20))
exec(@sql)
END
J'ai appris de mes erreurs et j'ai trouvé le vrai coupable de cette question.
Le coupable est
sys.fn_hadr_is_primary_replica
qui accède à la base de données en question.
Un collègue de mienne m'a donné une meilleure fonction de travailler avec, en vérifiant l'AG au lieu de la DB.
CREATE FUNCTION [dbo].[fn_hadr_group_is_primary] (@AGName sysname)
RETURNS bit
AS
BEGIN
DECLARE @PrimaryReplica sysname;
SELECT @PrimaryReplica = hags.primary_replica
FROM
sys.dm_hadr_availability_group_states hags
INNER JOIN sys.availability_groups ag ON ag.group_id = hags.group_id
WHERE
ag.name = @AGName;
IF UPPER(@PrimaryReplica) = UPPER(@@SERVERNAME)
RETURN 1; -- primary
RETURN 0; -- not primary
END;
GO
puis appelant la fonction dans une étape de travail avec :
IF [dbo].[fn_hadr_group_is_primary] 'AG1' = 1
BEGIN
EXEC DBO.TestProc @dbname = 'test'
END
Ce qui n'a plus donné le même problème sur mon travail qui appelle une procédure, même avec des paramètres.
Bien que l'agent SQL ait toujours des paramètres non par défaut, dans ce cas, la solution de contournement n'accède pas à la DB avec le chèque AG, mais le groupe de disponibilité à la place.