Penambahan identitas melonjak di database SQL Server

126

Di salah satu tabel saya Feedi kolom "ReceiptNo" di peningkatan identitas database SQL Server 2012 tiba-tiba mulai melompat ke 100, bukan 1, tergantung pada dua hal berikut.

  1. jika 1205446 itu melompat ke 1206306, jika 1206321, itu melompat ke 1207306 dan jika 1207314, itu melompat ke 1208306. Yang saya ingin Anda perhatikan adalah bahwa tiga digit terakhir tetap konstan yaitu 306 setiap kali lompatan terjadi seperti yang ditunjukkan pada gambar berikut.

  2. masalah ini terjadi saat saya me-restart komputer saya

masukkan deskripsi gambar di sini

kashif
sumber
Jika Anda menambahkan order by ReceiptNoke kueri Anda, apakah rekaman itu benar-benar tidak ada? Apakah Anda yakin saat record disisipkan tidak ada kesalahan? Jika rekaman mencoba untuk dimasukkan dan gagal, identitas akan bertambah, hal yang sama jika rekaman dihapus. Jika catatan dihapus, ReceiptNotidak direset. Bisakah Anda memposting buat tabel untuk Feetabel?
Taryn
4
Pertanyaan pertama adalah - mengapa itu penting? itu harus berupa ID unik yang sewenang-wenang
Andrew
1
Apakah ini berjalan di server atau mungkin diekspresikan di desktop? Ingin tahu mengapa tampaknya layanan begitu sering dimulai ulang?
Martin Smith
@bluefeet Saya tahu saat kesalahan terjadi, terjadi peningkatan identitas. Saya 100% yakin tidak ada kesalahan. Saya mengedit pertanyaan saya dengan menambahkan tabel dan prosedur tersimpan yang saya gunakan untuk menyisipkan baris.
kashif
@ kashif - 99% yakin itu tidak diperlukan. Melompat dengan tepat 1.000 ( 1206306, 1207306, 1207806) berarti penjelasan di Connect Barang Thread hampir pasti berlaku.
Martin Smith

Jawaban:

158

Anda mengalami perilaku ini karena peningkatan kinerja sejak SQL Server 2012.

Sekarang secara default menggunakan ukuran cache 1.000 ketika mengalokasikan IDENTITYnilai untuk intkolom dan memulai kembali layanan dapat "kehilangan" nilai yang tidak digunakan (Ukuran cache 10.000 untuk bigint/ numeric).

Ini disebutkan dalam dokumentasi

SQL Server mungkin menyimpan nilai identitas untuk alasan kinerja dan beberapa nilai yang ditetapkan bisa hilang selama kegagalan database atau server restart. Hal ini dapat menyebabkan kesenjangan dalam nilai identitas saat dimasukkan. Jika celah tidak dapat diterima maka aplikasi harus menggunakan mekanismenya sendiri untuk menghasilkan nilai kunci. Menggunakan generator urutan dengan NOCACHEopsi dapat membatasi celah pada transaksi yang tidak pernah dilakukan.

Dari data yang Anda tunjukkan sepertinya ini terjadi setelah entri data untuk 22 Desember lalu ketika restart SQL Server mencadangkan nilai 1206306 - 1207305. Setelah entri data untuk 24 - 25 Desember dilakukan restart lagi dan SQL Server memesan kisaran berikutnya yang 1207306 - 1208305terlihat di entri untuk tanggal 28.

Kecuali jika Anda memulai ulang layanan dengan frekuensi yang tidak biasa, setiap nilai yang "hilang" kemungkinan tidak akan membuat perubahan signifikan dalam rentang nilai yang diizinkan oleh tipe data, jadi kebijakan terbaik adalah tidak mengkhawatirkannya.

Jika ini karena alasan tertentu menjadi masalah nyata bagi Anda, beberapa solusi yang mungkin adalah ...

  1. Anda dapat menggunakan sebagai SEQUENCEpengganti kolom identitas dan menentukan ukuran cache yang lebih kecil misalnya dan digunakan NEXT VALUE FORdalam default kolom.
  2. Atau terapkan bendera pelacakan 272 yang membuat IDENTITYalokasi dicatat sebagai versi hingga 2008 R2. Ini berlaku secara global untuk semua database.
  3. Atau, untuk versi terbaru, jalankan ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFFuntuk menonaktifkan cache identitas untuk database tertentu.

Anda harus menyadari bahwa tidak ada solusi yang menjamin tidak ada celah. Ini tidak pernah dijamin oleh IDENTITYkarena hanya mungkin dengan membuat serialisasi sisipan ke tabel. Jika Anda membutuhkan kolom tanpa celah, Anda perlu menggunakan solusi yang berbeda dari IDENTITYatauSEQUENCE

Martin Smith
sumber
1
untuk memverifikasi apa yang Anda katakan saya memasukkan beberapa nilai dan mendapatkan 1208309, 1208310 dan kemudian saya me-restart server dan kemudian ketika saya menambahkan baris saya mendapat 1209309 itu berarti apa yang Anda katakan benar. Terima kasih banyak. sekarang tolong beri tahu saya bagaimana saya bisa mengatasi masalah ini. apakah Anda menyarankan saya untuk menggunakan sql server 2008 bukan 2012 yang saya gunakan sebelumnya atau bahkan menggunakan 2012 masalah ini dapat diselesaikan ??
kashif
1
@ kashif - Apakah ini benar-benar masalah bagi Anda? Bahkan jika Anda menggunakan 1.000 nilai identitas sehari, masih perlu 2 juta hari sebelum Anda kehabisan nilai. Jika Anda ingin perilaku lama Anda dapat mengatur SQL Server untuk memulai dengan jejak bendera 272 atau Anda dapat menggunakan dan SEQUENCEbukan IDENTITYdan mengatur Urutan untuk memiliki ukuran cache 0.
Martin Smith
Saya mendapat jawaban yang Cukup Mengesankan dan memuaskan dari Anda untuk solusi saya terima kasih banyak.
kashif
Sebenarnya dari Anda, CREATE TABLEsaya melihat Anda sedang menggunakan numeric(7)dan telah memulai penomoran pada 1200001itu berarti Anda akan habis setelah 8,799hari (24 tahun) jika Anda menggunakan 1.000 per hari.
Martin Smith
Nilai sebenarnya "melompat" seharusnya bergantung pada jenis kolom yang digunakan. Misalnya, big intkolom biasanya akan "melompat" 10.000 per restart.
StarPilot
60

Masalah ini terjadi setelah memulai ulang SQL Server.

Solusinya adalah:

  • Jalankan Manajer Konfigurasi SQL Server .

  • Pilih Layanan SQL Server .

    Manajer Konfigurasi SQL Server

  • Klik kanan SQL Server dan pilih Properties .

  • Di jendela pembuka di bawah Parameter Startup , ketik -T272dan klik Add , lalu tekan tombol Apply dan restart.

    Parameter startup SQL Server

Harun ERGUL
sumber
1
Metode ini benar-benar berhasil, terima kasih banyak! dan seperti yang diceritakan di sini , masalah ini tidak akan diperbaiki di SQL Server 2012, dan dalam paket layanannya, - hanya di rilis versi berikutnya.
Fragmen
2
Apakah ada cara untuk menerapkan tanda jejak ke database individu? Saya tidak ingin membuat perubahan ini di seluruh server karena saya memiliki database pihak ketiga dan saya tidak yakin bagaimana hal ini akan memengaruhi mereka.
Ege Ersoz
1
Saya tidak mengikuti alasannya, tetapi tampaknya beberapa pengguna harus menggunakan huruf kecil "t" untuk membuatnya berfungsi. Lihat tautan yang diposting oleh Fragmen di komentar di atas.
Savage
33

Dari SQL Server 2017+Anda dapat menggunakan ALTER DATABASE SCOPED CONFIGURATION :

IDENTITY_CACHE = {ON | MATI }

Mengaktifkan atau menonaktifkan cache identitas di tingkat database. Standarnya AKTIF. Caching identitas digunakan untuk meningkatkan kinerja INSERT pada tabel dengan kolom Identity. Untuk menghindari celah dalam nilai kolom Identitas dalam kasus di mana server restart tiba-tiba atau gagal ke server sekunder, nonaktifkan opsi IDENTITY_CACHE. Opsi ini mirip dengan SQL Server Trace Flag 272 yang sudah ada, kecuali bahwa opsi ini dapat disetel di tingkat database daripada hanya di tingkat server.

(...)

G. Atur IDENTITY_CACHE

Contoh ini menonaktifkan cache identitas.

ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE=OFF ;
Lukasz Szozda
sumber
25

Saya tahu jawaban saya mungkin terlambat ke pesta. Tetapi saya telah menyelesaikannya dengan cara lain dengan menambahkan prosedur start up yang tersimpan di SQL Server 2012.

Buat prosedur tersimpan berikut di master 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

Kemudian tambahkan ke Start up dengan menggunakan sintaks berikut.

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

Ini adalah ide yang bagus jika Anda memiliki sedikit tabel. tetapi jika Anda harus melakukannya untuk banyak tabel, metode ini masih berfungsi tetapi bukan ide yang baik.

Jeyara
sumber
Ide bagus. Tapi itu tidak berfungsi untuk tabel dependen, bukan? Maksud saya, apakah itu memperbaiki nilai kunci asing?
rom5jp
@ rom5jp Memperbaiki FK bukanlah inti dari jawaban ini. Ini semua tentang memperbaiki kemungkinan nilai PK berikutnya dari sebuah tabel. Selama MAX (id) tidak ada di salah satu FK, itu harus berfungsi.
Jeyara
14

Ini masih menjadi masalah yang sangat umum di antara banyak pengembang dan aplikasi terlepas dari ukurannya.

Sayangnya saran di atas tidak memperbaiki semua skenario, yaitu Shared hosting, Anda tidak dapat mengandalkan host Anda untuk menyetel parameter startup -t272.

Juga, jika Anda memiliki tabel yang sudah ada yang menggunakan kolom identitas ini untuk kunci utama, itu adalah upaya BESAR untuk melepaskan kolom tersebut dan membuat ulang yang baru untuk menggunakan solusi urutan BS. Solusi Urutan hanya bagus jika Anda mendesain tabel baru dari awal di SQL 2012+

Intinya adalah, jika Anda menggunakan Sql Server 2008R2, TETAP TETAP. Serius, tetaplah di sana. Hingga Microsoft mengakui bahwa mereka memperkenalkan bug BESAR, yang masih ada bahkan di Sql Server 2016, maka kita tidak boleh memutakhirkan sampai mereka memilikinya dan MEMPERBAIKI.

Microsoft langsung memperkenalkan perubahan besar, yaitu mereka merusak API yang berfungsi yang tidak lagi berfungsi seperti yang dirancang, karena fakta bahwa sistem mereka melupakan identitas mereka saat ini saat restart. Cache atau tidak ada cache, ini tidak dapat diterima, dan pengembang Microsoft bernama Bryan harus memilikinya, alih-alih memberi tahu dunia bahwa itu "berdasarkan desain" dan "fitur". Tentu, caching adalah sebuah fitur, tetapi kehilangan jejak tentang identitas selanjutnya, BUKANLAH FITUR. Ini BUG fricken !!!

Saya akan membagikan solusi yang saya gunakan, karena DB saya ada di server Shared Hosting, juga, saya tidak menghapus dan membuat ulang kolom Kunci Utama saya, itu akan menjadi PITA yang besar.

Sebaliknya, ini adalah peretasan saya yang memalukan (tetapi tidak memalukan seperti bug POS yang diperkenalkan oleh Microsoft).

Retas / Perbaiki:

Sebelum memasukkan perintah Anda, cukup reseed identitas Anda sebelum setiap sisipan. Perbaikan ini hanya disarankan jika Anda tidak memiliki kontrol admin atas instance Sql Server Anda, jika tidak, saya sarankan untuk melakukan reseeding saat restart 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)

Hanya 3 baris itu tepat sebelum sisipan Anda, dan Anda harus melakukannya dengan baik. Ini benar-benar tidak akan terlalu mempengaruhi kinerja, yaitu tidak akan terlihat.

Semoga berhasil.

green_mystic_Orb
sumber
7

Ada banyak kemungkinan alasan untuk melompati nilai-nilai identitas. Mulai dari sisipan yang digulung kembali hingga manajemen identitas untuk replikasi. Apa yang menyebabkan ini dalam kasus Anda, saya tidak tahu tanpa menghabiskan waktu di sistem Anda.

Namun Anda harus tahu, bahwa Anda tidak boleh menganggap kolom identitas bersebelahan. Ada terlalu banyak hal yang dapat menyebabkan kesenjangan.

Anda dapat menemukan lebih banyak informasi tentang ini di sini: http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/

Sebastian Meine
sumber