SQL Server veritabanında kimlik artışı atlıyor


126

FeeSQL Server 2012 veritabanı "ReceiptNo" sütunundaki tablolarımdan birinde , aşağıdaki iki şeye bağlı olarak aniden kimlik artışı 1 yerine 100'lere atlamaya başladı.

  1. 1205446 ise 1206306'ya, 1206321 ise 1207306'ya, 1207314 ise 1208306'ya atlar. Size not etmek istediğim son üç rakamın sabit kalması, yani 306 aşağıdaki resimde gösterildiği gibi oluşur.

  2. bu sorun bilgisayarımı yeniden başlattığımda ortaya çıkıyor

görüntü açıklamasını buraya girin


order by ReceiptNoSorgunuza eklerseniz , bu kayıtlar gerçekten orada değil mi? Kayıtlar eklenirken hata olmadığından emin misiniz? Bir kayıt yerleştirilmeye çalışırsa ve başarısız olursa, kimlik artacaktır, kayıtlar silinirse de aynı şey olacaktır. Kayıtlar silinirse ReceiptNosıfırlanmaz. Tablo için oluşturma tablosunu gönderebilir misiniz Fee?
Taryn

4
İlk soru - neden önemli? keyfi benzersiz bir kimlik olmalıdır
Andrew

1
Bu bir sunucuda mı çalışıyor yoksa bir masaüstünde mi ifade ediliyor? Hizmetin neden bu kadar sık ​​yeniden başlatıldığını merak ediyor musunuz?
Martin Smith

@ bluefeet Hata oluştuğunda biliyorum, kimlik artışı oluyor. Hata olmadığına% 100 eminim. Tabloyu ve satırları eklemek için kullandığım saklı yordamı ekleyerek sorumu düzenliyorum.
kashif

@kashif - Bunun gerekli olmadığından% 99 emin. Tam olarak 1.000 atlarsa ( 1206306, 1207306, 1207806) Bağlan Öğe in Konu açıklama neredeyse kesin geçerlidir anlamına gelir.
Martin Smith

Yanıtlar:


158

SQL Server 2012'den bu yana bir performans artışı nedeniyle bu davranışla karşılaşıyorsunuz.

Artık IDENTITYbir intsütun için değer tahsis ederken varsayılan olarak 1000 önbellek boyutu kullanır ve hizmeti yeniden başlatmak kullanılmayan değerleri "kaybedebilir" ( bigint/ için önbellek boyutu 10.000'dir numeric).

Bu belgelerde belirtilmiştir

SQL Server, performans nedenleriyle kimlik değerlerini önbelleğe alabilir ve atanan değerlerden bazıları bir veritabanı hatası veya sunucunun yeniden başlatılması sırasında kaybolabilir. Bu, eklendikten sonra kimlik değerinde boşluklara neden olabilir. Boşluklar kabul edilebilir değilse, uygulama anahtar değerleri oluşturmak için kendi mekanizmasını kullanmalıdır. NOCACHESeçenekle birlikte bir sıra üreteci kullanmak , boşlukları asla taahhüt edilmeyen işlemlerle sınırlayabilir.

Göstermiş olduğunuz verilerden, 22 Aralık veri girişinden sonra ve ardından SQL Server yeniden başlatıldığında değerleri rezerve ettiğinde meydana gelmiş gibi görünüyor 1206306 - 1207305. 24-25 Aralık veri girişi yapıldıktan sonra, başka bir yeniden başlatma yapıldı ve SQL Server 1207306 - 1208305, 28'inci girişlerde görünen sonraki aralığı ayırdı .

Hizmeti alışılmadık sıklıkta yeniden başlatmadığınız sürece, herhangi bir "kayıp" değerin veri türü tarafından izin verilen değerler aralığında önemli bir değişiklik yapması olası değildir, bu nedenle en iyi politika bu konuda endişelenmemektir.

Bu herhangi bir nedenle sizin için gerçek bir sorunsa, bazı olası geçici çözümler ...

  1. SEQUENCEBir kimlik sütunu yerine bir kullanabilir ve daha küçük bir önbellek boyutu tanımlayabilir ve NEXT VALUE FORbir sütun varsayılanı olarak kullanabilirsiniz.
  2. Veya IDENTITYtahsisin 2008 R2'ye kadar olan sürümlerde olduğu gibi günlüğe kaydedilmesini sağlayan izleme bayrağı 272'yi uygulayın . Bu, global olarak tüm veritabanları için geçerlidir.
  3. Veya son sürümler ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFFiçin, belirli bir veritabanı için kimlik önbelleğe almayı devre dışı bırakmak için yürütün .

Bu geçici çözümlerin hiçbirinin boşlukları garanti etmediğinin farkında olmalısınız. Bu, IDENTITYyalnızca ekleri tabloya serileştirmekle mümkün olacağından hiçbir zaman garanti edilmemiştir . Eğer bir boşluksuz sütun gerekirse farklı bir çözüm kullanmak gerekir ya IDENTITYyaSEQUENCE


1
Söylediğinizi doğrulamak için bazı değerler ekledim ve 1208309, 1208310 aldım ve sonra sunucuyu yeniden başlattım ve sonra satırı eklediğimde 1209309 aldım, bu söylediğinizin kesinlikle doğru olduğu anlamına gelir. çok teşekkürler. şimdi lütfen bana bu sorunu nasıl çözebilirim söyler misin? Daha önce kullandığım 2012 yerine sql server 2008'i kullanmamı önerir misiniz, hatta 2012'yi kullanırken bu sorun çözülebilir mi?
kashif

1
@kashif - Aslında sizin için bir sorun mu? Günde 1.000 kimlik değeri kullansanız bile, değerlerin tükenmesi 2 milyon gün sürecektir. Eski davranışı istiyorsanız, SQL Server'ı 272 izleme bayrağıyla başlayacak şekilde ayarlayabilir veya bir SEQUENCEyerine a kullanabilir IDENTITYve Sırayı, önbellek boyutuna sahip olacak şekilde ayarlayabilirsiniz 0.
Martin Smith

Çözümüm için sizden oldukça etkileyici ve tatmin edici cevaplar aldım çok teşekkürler.
kashif

Aslında CREATE TABLEsizden kullandığınızı numeric(7)ve numaralandırmaya başladığınızı görüyorum , 1200001bu da 8,799günde 1000 kullanırsanız günler (24 yıl) sonra tükeneceğiniz anlamına gelir .
Martin Smith

"Atlanan" gerçek değerin kullanılan sütun tipine bağlı olduğu varsayılır. Örneğin, bir big intsütun genellikle yeniden başlatma başına 10.000 "atlayacaktır".
StarPilot

60

Bu sorunlar, SQL Server'ı yeniden başlattıktan sonra oluşur.

Çözüm şudur:

  • SQL Server Configuration Manager'ı çalıştırın .

  • SQL Server Hizmetleri'ni seçin .

    SQL Server Yapılandırma Yöneticisi

  • SQL Server'a sağ tıklayın ve Özellikler'i seçin .

  • Başlangıç ​​Parametreleri altındaki açılış penceresine Ekle yazın -T272ve tıklayın , ardından Uygula düğmesine basın ve yeniden başlatın.

    SQL Server başlangıç ​​parametreleri


1
Bu yöntem gerçekten işe yarıyor, çok teşekkürler! ve burada anlatıldığı gibi , bu sorun SQL Server 2012'de ve hizmet paketlerinde düzeltilmeyecektir - yalnızca bir sonraki sürüm sürümünde.
Parçacık

2
İzleme bayrağını tek tek veritabanlarına uygulamanın bir yolu var mı? Bu değişikliği tüm sunucuda yapmak istemiyorum çünkü üçüncü taraf veritabanlarına sahibim ve bunun onları nasıl etkileyeceğinden emin değilim.
Ege Ersöz

1
Sebepleri takip etmedim, ancak görünüşe göre bazı kullanıcılar onu çalıştırmak için küçük harf "t" kullanmak zorunda kaldı. Yukarıdaki yorumda Fragment tarafından yayınlanan bağlantıya bakın.
Savage

33

Gönderen SQL Server 2017+Kullanabileceğin alter database Dürbünlü YAPILANDIRMA :

IDENTITY_CACHE = {ON | OFF}

Veritabanı düzeyinde kimlik önbelleğini etkinleştirir veya devre dışı bırakır. Varsayılan AÇIK'tır. Kimlik önbelleğe alma, Kimlik sütunları olan tablolarda INSERT performansını artırmak için kullanılır. Sunucunun beklenmedik şekilde yeniden başladığı veya ikincil bir sunucuya devredildiği durumlarda Kimlik sütununun değerlerindeki boşlukları önlemek için IDENTITY_CACHE seçeneğini devre dışı bırakın. Bu seçenek, yalnızca sunucu düzeyinde değil, veritabanı düzeyinde ayarlanabilmesi dışında, mevcut SQL Server İzleme Bayrağı 272'ye benzer.

(...)

G. IDENTITY_CACHE ayarla

Bu örnek, kimlik önbelleğini devre dışı bırakır.

ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE=OFF ;

25

Cevabımın partiye geç kalabileceğini biliyorum. Ancak SQL Server 2012'de bir başlangıç ​​saklı yordamı ekleyerek başka bir şekilde çözdüm.

Ana DB'de aşağıdaki saklı yordamı oluşturun.

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

Ardından, aşağıdaki sözdizimini kullanarak Başlangıç'a ekleyin.

EXEC sp_procoption 'ResetOrderIdentityAfterRestart', 'startup', 'on';

Birkaç tablonuz varsa bu iyi bir fikirdir. ancak birçok tablo için yapmanız gerekiyorsa, bu yöntem yine de işe yarar ama iyi bir fikir değildir.


İyi fikir. Ama bağımlı tablolar için çalışmıyor, değil mi? Demek istediğim, yabancı anahtar değerlerini sabitliyor mu?
rom5jp

@ rom5jp Bu cevabın amacı FK'yi tamir etmek değil. Her şey bir tablonun olası bir sonraki PK değerini düzeltmekle ilgili. MAX (id), FK'nin hiçbirinde olmadığı sürece çalışmalıdır.
Jeyara

14

Bu, boyutundan bağımsız olarak birçok geliştirici ve uygulama arasında hala çok yaygın bir sorundur.

Ne yazık ki yukarıdaki öneriler tüm senaryoları, yani Paylaşılan barındırma, düzeltmez, ana makinenizin -t272 başlangıç ​​parametresini ayarlamasına güvenemezsiniz.

Ayrıca, birincil anahtarlar için bu kimlik sütunlarını kullanan mevcut tablolarınız varsa, bu sütunları kaldırmak ve BS dizisi geçici çözümünü kullanmak için yenilerini yeniden oluşturmak BÜYÜK bir çabadır. Sıra geçici çözümü yalnızca SQL 2012+ sürümünde tabloları sıfırdan yeni tasarlıyorsanız işe yarar

Alt satırda, eğer Sql Server 2008R2 üzerindeyseniz, ONUN ÜZERİNDE KALIN. Cidden, üzerinde kalın. Microsoft, Sql Server 2016'da bile hala var olan BÜYÜK bir hata çıkardığını kabul edene kadar, ona sahip olana ve BT'yi düzeltene kadar yükseltmemeliyiz.

Microsoft, doğrudan bir çığır açan değişiklik başlattı, yani sistemleri yeniden başlatıldığında mevcut kimliklerini unuttuğu için artık tasarlandığı gibi çalışmayan çalışan bir API'yi bozdu. Önbellek veya önbellek yok, bu kabul edilemez ve dünyaya "tasarım gereği" ve "özellik" olduğunu söylemek yerine, Bryan adındaki Microsoft geliştiricisinin ona sahip olması gerekiyor. Elbette, önbelleğe alma bir özelliktir, ancak bir sonraki kimliğin ne olması gerektiğinin izini kaybetmek BİR ÖZELLİK DEĞİLDİR. Bu lanet bir HATA !!!

Kullandığım geçici çözümü paylaşacağım, çünkü DB'lerim Paylaşılan Barındırma sunucularında, ayrıca Birincil Anahtar sütunlarımı bırakıp yeniden oluşturmuyorum, bu çok büyük bir PITA olurdu.

Bunun yerine, bu benim utanç verici hack'im (ancak microsoft'un sunduğu bu POS hatası kadar utanç verici değil).

Hack / Düzelt:

Ekleme komutlarınızdan önce, her eklemeden önce kimliğinizi yeniden göndermeniz yeterlidir. Bu düzeltme yalnızca Sql Server örneğiniz üzerinde yönetici kontrolünüz yoksa önerilir, aksi takdirde sunucuyu yeniden başlattığınızda yeniden beslemenizi öneririm.

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)

Sadece ekinizden hemen önceki 3 satır ve gitmekte fayda var. Gerçekten performansı o kadar fazla etkilemeyecek, yani fark edilmeyecek.

İyi şanslar.


7

Kimlik değerlerini atlamanın birçok olası nedeni vardır. Geri alınan eklemelerden çoğaltma için kimlik yönetimine kadar çeşitlilik gösterirler. Sizin durumunuzda buna neyin sebep olduğunu sisteminizde biraz zaman harcamadan anlayamıyorum.

Bununla birlikte, hiçbir durumda bir kimlik sütununun bitişik olduğunu varsayamayacağınızı bilmelisiniz. Boşluklara neden olabilecek çok fazla şey var.

Bununla ilgili biraz daha fazla bilgiyi burada bulabilirsiniz: http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.