SQL Server 2012データベースIDの列「ReceiptNo」の私のテーブルのFee
で、次の2つのことにより、突然1から100にジャンプし始めました。
1205446の場合は1206306にジャンプし、1206321の場合は1207306にジャンプし、1207314の場合は1208306にジャンプします。最後の3桁は一定のままです。次の図に示すように発生します。
この問題は、コンピューターを再起動すると発生します
SQL Server 2012は、IDENTITY
列にint
値を割り当て、サービスを再起動すると未使用の値を「失う」場合に、1,000のキャッシュサイズを使用するようになりました(bigint
/numeric
のキャッシュサイズは10,000です)。
示したデータから、12月22日のデータ入力後にSQL Serverが再起動したときに1206306 - 1207305
という値が予約されたように見えます。 12月24日から25日のデータ入力が再度行われ、SQL Serverは28日のエントリに表示される次の範囲1207306 - 1208305
を予約しました。
異常な頻度でサービスを再起動しない限り、「失われた」値がデータ型で許可されている値の範囲に大きな凹みを作る可能性は低いため、最善のポリシーはそれを心配しないことです。
これが何らかの理由で実際の問題である場合、リンクされた接続項目スレッドの回避策が表示されます。
SEQUENCE
を使用し、より小さいキャッシュサイズを定義して、列のデフォルトでNEXT VALUE FOR
を使用できます。IDENTITY
割り当てを以前のバージョンと同様に記録するトレースフラグ272を適用します。これらの回避策はいずれもギャップを保証しないことに注意してください。これは、IDENTITY
によって保証されたことはありません。テーブルへの挿入をシリアル化することによってのみ可能になるからです。ギャップのない列が必要な場合は、IDENTITY
またはSEQUENCE
とは異なるソリューションを使用する必要があります。
この問題は、SQL Serverの再起動後に発生します。
解決策は次のとおりです。
SQL Server Configuration Managerを実行します。
SQL Serverサービスを選択します。
SQL Serverを右クリックし、プロパティを選択します。
スタートアップパラメータの最初のウィンドウで、-T272
と入力し、追加をクリックしてから、適用ボタンを押して再起動します。
私の回答はパーティーに遅れる可能性があることを知っています。しかし、SQL Server 2012にスタートアップストアドプロシージャを追加することにより、別の方法で解決しました。
マスターDBに次のストアドプロシージャを作成します。
USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ResetTableNameIdentityAfterRestart]
AS
BEGIN
begin TRAN
declare @id int = 0
SELECT @id = MAX(id) FROM [DatabaseName].dbo.[TableName]
--print @id
DBCC CHECKIDENT ('[DatabaseName].dbo.[TableName]', reseed, @id)
Commit
END
次に、次の構文を使用して、スタートアップに追加します。
EXEC sp_procoption 'ResetOrderIdentityAfterRestart', 'startup', 'on';
テーブルが少ない場合、これは良い考えです。しかし、多くのテーブルに対して行う必要がある場合、この方法は機能しますが、良いアイデアではありません。
SQL Server 2017+
から ALTER DATABASE SCOPED CONFIGURATION を使用できます:
IDENTITY_CACHE = {ON |オフ}
データベースレベルでIDキャッシュを有効または無効にします。デフォルトはオンです。 IDキャッシュは、ID列を持つテーブルのINSERTパフォーマンスを改善するために使用されます。 サーバーが予期せず再起動するか、セカンダリサーバーにフェールオーバーする場合にIdentity列の値のギャップを回避するには、IDENTITY_CACHEオプションを無効にします。このオプションサーバーレベルだけでなくデータベースレベルで設定できることを除いて、既存のSQL Serverトレースフラグ272と似ています。
(...)
G。 IDENTITY_CACHEを設定します
この例では、IDキャッシュを無効にします。
ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE=OFF ;
これは、サイズに関係なく多くの開発者とアプリケーションの間で依然として非常に一般的な問題です。
残念ながら、上記の提案はすべてのシナリオ、つまり共有ホスティングを修正するわけではありません。ホストに依存して-t272スタートアップパラメーターを設定することはできません。
また、主キーにこれらのID列を使用する既存のテーブルがある場合、それらの列を削除し、BSシーケンスの回避策を使用するために新しい列を再作成するのは大変な努力です。シーケンスの回避策は、SQL 2012+で新しいテーブルをゼロから設計する場合にのみ有効です。
要するに、SQL Server 2008R2を使用している場合は、そのままにしてください。真剣に、それにとどまる。 Microsoftが巨大なバグを導入したことを認めるまで(これはSql Server 2016にも存在します)、それを所有して修正するまでアップグレードしないでください。
マイクロソフトはすぐに重大な変更を導入しました。つまり、システムは再起動時に現在のIDを忘れてしまうため、設計どおりに機能しない動作中のAPIを壊しました。キャッシュまたはキャッシュなし。これは受け入れられません。Microsoft開発者はBryanという名前で、「設計」および「機能」であることを世界に伝えるのではなく、所有する必要があります。確かに、キャッシングは機能ですが、次のアイデンティティがどうあるべきかを追跡できません。IS NOT A FEATURE。それは愚かなバグです!
私のDBは共有ホスティングサーバー上にあるため、使用した回避策を共有します。また、プライマリキー列を削除して再作成することはありません。これは巨大なPITAになります。
代わりに、これは私の恥ずべきハックです(ただし、Microsoftが導入したこのPOSバグほど恥ずべきことではありません)。
挿入コマンドの前に、各挿入の前にIDを再シードするだけです。この修正は、SQL Serverインスタンスを管理者が制御できない場合にのみお勧めします。そうでない場合は、サーバーの再起動時に再シードすることをお勧めします。
declare @newId int -- where int is the datatype of your PKey or Id column
select @newId = max(YourBuggedIdColumn) from YOUR_TABLE_NAME
DBCC CheckIdent('YOUR_TABLE_NAME', RESEED, @newId)
挿入の直前にあるこれらの3行だけで、うまくいくはずです。それほどパフォーマンスに影響を与えることはありません。つまり、目立たなくなります。
幸運を。
ID値をジャンプする理由は多数考えられます。それらは、ロールバックされた挿入からレプリケーションのためのID管理にまで及びます。あなたのケースでこれを引き起こしているのは、あなたのシステムで少し時間を費やさずにはわかりません。
ただし、ID列を連続であると想定することはできません。ギャップを引き起こす可能性のあるものが多すぎます。
これについてもう少し情報を見つけることができます: http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/