制約の GETDATE から SYSDATETIME への変更により問題が解決されるようです。
SQL Server 2012 の一部のテーブルの DEFAULT 制約の GETDATE
-
29-07-2022 - |
質問
ご想像のとおり、SQL Server 2012 の一部のテーブルの DEFAULT 制約で GETDATE に問題が発生しました。
以下のような 2 つのテーブル (A と B) があります。
CREATE TABLE [dbo].[TABLE_A_OR_B] (
[TABLE_A_OR_B_PK] BIGINT IDENTITY (1, 1) NOT NULL,
[CREATE_DATETIME] DATETIME2 (7) CONSTRAINT [DF_TABLE_A_OR_B_CREATE_DATETIME] DEFAULT (getdate()) NOT NULL,
[CREATE_USER] VARCHAR (100) CONSTRAINT [DF_TABLE_A_OR_B_CREATE_USER] DEFAULT (suser_sname()) NOT NULL,
...
CONSTRAINT [PK_TABLE_A_OR_B] PRIMARY KEY CLUSTERED ([TABLE_A_OR_B_PK] ASC)
);
そして、2つの挿入を実行するプロシージャがあります - 最初はテーブルAに、2番目は列CREATE_DATETIMEなしでBに挿入します。それらの間にはたくさんのものがあります。
ここで、テーブル A と B の列 CREATE_DATETIME には何が入っていると思いますか?
2 回 - おそらく 1 000 000 レコードの後ですが、これまでは一度もありませんでした - 同じ sp 実行 (検証済み) からのレコードについて、テーブル A の日時がテーブル B よりも大きいことがあります。
row in A: 2013-11-07 00:02:22.7000000
row in B: 2013-11-07 00:02:22.6970000
理由をいくつか教えていただけますか?
コメントへの回答:
1.トリガーはありません。
2.いいえ、一度に 1,000,000 レコード。これは、エラーが最初に発生した瞬間のテーブル内のレコードの合計数です。この情報は統計分析用です - 今日は最後のエラーから xx 千レコード後にエラーが発生しました - したがって、非常にランダムです。
3.はい、ステートメントは 100% この順序で実行されます。
4.トランザクションがないか、単一の 2 つの異なるプロセスで同じエラーが発生しました。
5.確かにDATETIME2。
重要!誰かが、GETDATE の精度は 3 ミリ秒であると教えてくれました。そのため、GETDATE はラウンドロビン方式でミリ秒を丸めるので、同じ時間またはほぼ同じ時間 (差分 < 3ms) を 2 回実行すると、2 つの異なる近似値が得られるのではないでしょうか?
解決 3
他のヒント
最初の挿入をテーブル A に挿入してコミットし、次にテーブル B に 2 番目の挿入を挿入してコミットすると、2 つのレコードを挿入するのに時間がかかるため、この結果が得られる可能性が非常に高くなります。個別のトランザクションで挿入をコミットしない場合でも。
テーブルが大きくなると、さまざまな理由から挿入にかかる時間が長くなります。テーブルの挿入ごとにインデックスがある場合、インデックスはレコードが保存または編成された場所を記録する必要があります。次に、SQL サーバー内部のページの断片化により、挿入に時間がかかるようになります。フィルファクタを低く保ちながら挿入を高速化したい場合は、インデックス構造を確認してください。
常に同じ時刻が必要な場合は、時刻を取得する変数を作成し、この変数を使用して両方のテーブルに挿入を行います。
それが役に立てば幸い。
GETDATE()
はオペレーティング システムのクロックから派生します。何らかの原因でサーバー上のクロックが (以前の時間に) 変化すると、(見かけ上の) タイムトラベルが達成されます。
このような変化を引き起こす原因は何でしょうか?明らかなのは、手動で調整するか、サーバーが外部ソース (ドメイン上の別のマシンや NTP 経由など) とクロックを自動的に同期するように設定されているかどうかです。他の原因も考えられます。