web-dev-qa-db-ja.com

SQL ServerデータベースでIDの増分が急増しています

SQL Server 2012データベースIDの列「ReceiptNo」の私のテーブルのFeeで、次の2つのことにより、突然1から100にジャンプし始めました。

  1. 1205446の場合は1206306にジャンプし、1206321の場合は1207306にジャンプし、1207314の場合は1208306にジャンプします。最後の3桁は一定のままです。次の図に示すように発生します。

  2. この問題は、コンピューターを再起動すると発生します

enter image description here

113
kashif

おそらくここで問題が発生しています(ウェイバックマシン)

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を予約しました。

異常な頻度でサービスを再起動しない限り、「失われた」値がデータ型で許可されている値の範囲に大きな凹みを作る可能性は低いため、最善のポリシーはそれを心配しないことです。

これが何らかの理由で実際の問題である場合、リンクされた接続項目スレッドの回避策が表示されます。

  1. たとえば、ID列の代わりに SEQUENCE を使用し、より小さいキャッシュサイズを定義して、列のデフォルトでNEXT VALUE FORを使用できます。
  2. または、IDENTITY割り当てを以前のバージョンと同様に記録するトレースフラグ272を適用します。

これらの回避策はいずれもギャップを保証しないことに注意してください。これは、IDENTITYによって保証されたことはありません。テーブルへの挿入をシリアル化することによってのみ可能になるからです。ギャップのない列が必要な場合は、IDENTITYまたはSEQUENCEとは異なるソリューションを使用する必要があります。

143
Martin Smith

この問題は、SQL Serverの再起動後に発生します。

解決策は次のとおりです。

  • SQL Server Configuration Managerを実行します。

  • SQL Serverサービスを選択します。

    SQL Server Configuration Manager

  • SQL Serverを右クリックし、プロパティを選択します。

  • スタートアップパラメータの最初のウィンドウで、-T272と入力し、追加をクリックしてから、適用ボタンを押して再起動します。

    SQL Server startup parameters

53
Harun ERGUL

私の回答はパーティーに遅れる可能性があることを知っています。しかし、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';

テーブルが少ない場合、これは良い考えです。しかし、多くのテーブルに対して行う必要がある場合、この方法は機能しますが、良いアイデアではありません。

24
Jeyara

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 ;
24
Lukasz Szozda

これは、サイズに関係なく多くの開発者とアプリケーションの間で依然として非常に一般的な問題です。

残念ながら、上記の提案はすべてのシナリオ、つまり共有ホスティングを修正するわけではありません。ホストに依存して-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行だけで、うまくいくはずです。それほどパフォーマンスに影響を与えることはありません。つまり、目立たなくなります。

幸運を。

14

ID値をジャンプする理由は多数考えられます。それらは、ロールバックされた挿入からレプリケーションのためのID管理にまで及びます。あなたのケースでこれを引き起こしているのは、あなたのシステムで少し時間を費やさずにはわかりません。

ただし、ID列を連続であると想定することはできません。ギャップを引き起こす可能性のあるものが多すぎます。

これについてもう少し情報を見つけることができます: http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/

7
Sebastian Meine