alwayson
可用性グループに関係するサーバーで、実行中のジョブがある場合、ジョブ内で、現在のサーバーが可用性グループのprimary
かどうかを常にテストします。
したがって、 ジョブのみ実行AGのプライマリサーバー上 となります。
このようなものはうまく機能しています:
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
ただし、プロシージャの代わりにdbo.usp_some_other_procedure_without_parameteres
はJunoReporting
というデータベースに存在します。パラメータを持つ別のプロシージャを呼び出したいのですが、SQL Serverはそれを好みません。
彼は馬の前にカートを置いていると思いますが、どうすれば彼にわかりますか?
ジョブ内に次のコードがあると、ジョブが失敗します。
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
退屈で明らかなエラーメッセージが表示されます。それが、現在のサーバーが主な役割を果たしているかどうかをテストしている理由です。
メッセージ976、レベル14、状態1、行22
ターゲットデータベース「JUNOReporting」は可用性グループに参加しており、現在クエリでアクセスできません。データの移動が一時停止されているか、可用性レプリカで読み取りアクセスが有効になっていません。このデータベースと可用性グループ内の他のデータベースへの読み取り専用アクセスを許可するには、グループ内の1つ以上のセカンダリ可用性レプリカへの読み取りアクセスを有効にします。詳細については、SQL Server Books Onlineの「ALTER AVAILABILITY GROUPステートメント」を参照してください。
これを回避する方法はありますか?プロシージャ内にそのコードを追加したくないので、parameters
の問題を回避するためにSQLサーバーがその機会に持っているようです。
誤解を解消するためだけに:
私の可用性グループの2番目のサーバー(2つのサーバーのみで構成される)では、下の図に示すようにデータベースにアクセスできません。
これは、プロシージャにパラメータがあり、プロシージャがジョブステップからも呼び出されるために発生します。
ジョブコンテキスト(ssms)外でクエリを実行すると、問題なく実行されます。これが発生する正確な理由はまだはっきりしていません。プロファイラーを使用してコマンドを取得し、クエリウィンドウで再作成しようとしましたが、ダイスはありませんでした。
ただし、エージェントがジョブステップを実行すると、デフォルト以外の動作が発生する可能性があることは知っています。この例は、quoted_identifierがジョブステップコンテキスト内でオフになるという事実です。
マイクロソフトから:
SET QUOTED_IDENTIFIERがON(デフォルト)
とにかく、私があなたの問題に使用した回避策は、それを動的SQLに入れることです。
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
私は自分の過ちから学び、この問題の真の犯人を見つけました。
犯人は
sys.fn_hadr_is_primary_replica
問題のデータベースにアクセスします。
私の同僚は、DBの代わりにAGをチェックして、より優れた機能を提供してくれました。
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
次に、ジョブステップで関数を呼び出す:
IF [dbo].[fn_hadr_group_is_primary] 'AG1' = 1
BEGIN
EXEC DBO.TestProc @dbname = 'test'
END
これは、パラメーターを使用しても、プロシージャを呼び出す同じ問題をジョブに与えなくなりました。
SQLエージェントにはまだデフォルト以外の設定がいくつかありますが、この場合の回避策は、AGチェックでデータベースにアクセスするのではなく、可用性グループにアクセスすることです。