Kami sedang mengerjakan aplikasi web, belum dapat diakses oleh pengguna. Bos saya memperhatikan bahwa catatan yang baru dibuat mendapatkan ID lebih dari 10.000, meskipun kami hanya memiliki di bawah 100 catatan dalam tabel. Dia berasumsi bahwa antarmuka web untuk beberapa alasan menciptakan lebih dari 100 kali lebih banyak catatan sementara daripada yang sebenarnya (dan menghapusnya) dan ini dapat membuat kita kehabisan jangkauan dalam beberapa bulan setelah rilis.
Saya tidak berpikir dia benar tentang penyebab inflasi ID (kolega yang bisa menjawab ini sedang berlibur, jadi kita tidak tahu pasti), tapi mari kita asumsikan dia benar. Dia mengatakan bahwa dia akan benci untuk menggunakan kolom bigint, dan bahwa dia ingin kita berhenti secara otomatis meningkatkan kolom ID dan menulis kode sisi server yang memilih integer "tidak terpakai" pertama dan menggunakannya sebagai ID.
Saya seorang mahasiswa pascasarjana ilmu komputer dengan sedikit pengalaman praktis, mengisi peran pengembang junior. Dia memiliki pengalaman bertahun-tahun mengelola semua basis data organisasi kami, dan merancang sebagian besar darinya. Saya pikir dia salah dalam hal ini, bahwa ID bigint tidak perlu ditakuti, dan yang meniru fungsionalitas DBMS berbau antipattern. Tapi saya belum percaya pada penilaian saya.
Apa argumen untuk dan melawan setiap posisi? Hal-hal buruk apa yang dapat terjadi jika kita menggunakan bigint, dan apa bahaya dari menciptakan kembali fungsi autoincrementing roda ? Apakah ada solusi ketiga yang lebih baik daripada yang lain? Apa yang mungkin menjadi alasannya untuk ingin menghindari inflasi nilai ID wajah? Saya tertarik mendengar tentang alasan pragmatis juga - mungkin ID bigint bekerja secara teori, tetapi menyebabkan sakit kepala dalam praktik?
Aplikasi ini diharapkan tidak menangani jumlah data yang sangat besar. Saya ragu bahwa itu akan mencapai 10.000 catatan aktual dalam beberapa tahun mendatang.
Jika ada bedanya, kami menggunakan Microsoft SQL server. Aplikasi ini ditulis dalam C # dan menggunakan Linq to SQL.
Memperbarui
Terima kasih, saya menemukan jawaban dan komentar yang ada menarik. Tapi saya khawatir Anda salah mengerti pertanyaan saya, jadi itu berisi apa yang ingin saya ketahui.
Saya tidak terlalu peduli tentang alasan sebenarnya untuk ID tinggi. Jika kita tidak dapat menemukannya sendiri, saya dapat mengajukan pertanyaan yang berbeda. Yang saya tertarik adalah untuk memahami proses pengambilan keputusan dalam kasus ini. Untuk ini, silakan asumsikan bahwa aplikasi akan menulis 1000 catatan per hari, kemudian menghapus 9999 dari mereka . Saya hampir yakin ini bukan masalahnya, tapi inilah yang diyakini bos saya ketika dia mengajukan permintaan. Jadi, dalam keadaan hipotetis ini, apa pro dan kontra dari menggunakan bigint atau menulis kode kita sendiri yang akan menetapkan ID (dengan cara yang menggunakan ID dari catatan yang sudah dihapus, untuk memastikan tidak ada celah)?
Adapun alasan sebenarnya, saya sangat curiga bahwa ini karena kami pernah menulis kode untuk mengimpor data dari database lain, sebagai bukti konsep bahwa migrasi selanjutnya dapat dilakukan sampai batas tertentu. Saya pikir kolega saya sebenarnya membuat beberapa ribu catatan selama impor dan kemudian menghapusnya. Saya harus mengkonfirmasi apakah ini benar-benar terjadi, tetapi jika ya, bahkan tidak perlu untuk bertindak.
sumber
Jawaban:
Tanpa melihat kode, cukup sulit untuk mengatakan secara meyakinkan apa yang sedang terjadi. Meskipun, kemungkinan besar
IDENTITY
nilai sedang di-cache, menyebabkan kesenjangan dalam nilai setelah SQL Server di-restart. Lihat /programming/17587094/identity-column-value-suddenly-jumps-to-1001-in-sql-server untuk beberapa jawaban dan info bagus tentang itu.INT
Bidang sederhana dapat menyimpan nilai hingga 2.147.483.647. Anda benar-benar dapat memulai nilai identitas di -2.147.483.648, memberikan nilai 32 bit penuh. 4 Miliar nilai berbeda. Saya sangat ragu Anda akan kehabisan nilai untuk digunakan. Dengan asumsi aplikasi Anda adalah memakan nilai 1.000 untuk setiap baris sebenarnya menambahkan, Anda akan perlu menciptakan hampir 12.000 baris per hari setiap hari kehabisan ID dalam 6 bulan dengan asumsi Anda memulaiIDENTITY
nilai pada 0, dan menggunakan INT. Jika Anda menggunakan BIGINT, Anda harus menunggu 21 juta abad sebelum kehabisan nilai jika Anda menulis 12.000 baris per hari, menggunakan 1.000 "nilai" per baris.Setelah mengatakan semua itu, jika Anda ingin menggunakan
BIGINT
tipe data bidang identitas, tentu tidak ada yang salah dengan itu. Itu akan memberi Anda untuk semua maksud dan tujuan, pasokan nilai yang tidak terbatas untuk digunakan. Perbedaan kinerja antara INT dan BIGINT secara praktis tidak ada pada perangkat keras 64-bit modern, dan sangat disukai daripada menggunakan misalnyaNEWID()
untuk menghasilkan GUID.Jika Anda ingin mengelola nilai-nilai Anda sendiri untuk kolom ID, Anda bisa membuat tabel kunci, dan memberikan cara yang cukup anti peluru untuk melakukan itu menggunakan salah satu metode yang ditunjukkan dalam jawaban pada pertanyaan ini: Menangani akses bersamaan ke tabel kunci tanpa kebuntuan di SQL Server
Opsi lain, dengan asumsi Anda menggunakan SQL Server 2012+, akan menggunakan
SEQUENCE
objek untuk mendapatkan nilai ID untuk kolom. Namun, Anda harus mengonfigurasi urutan untuk tidak menembolok nilai. Sebagai contoh:Sebagai jawaban atas persepsi negatif bos Anda tentang angka "tinggi", saya akan mengatakan apa bedanya? Dengan asumsi Anda menggunakan
INT
bidang, denganIDENTITY
, Anda sebenarnya bisa memulaiIDENTITY
pada2147483647
dan "menambah" nilainya dengan-1
. Ini sama sekali tidak membuat perbedaan pada konsumsi memori, kinerja, atau ruang disk yang digunakan karena angka 32 bit adalah 4 byte, tidak masalah apakah itu0
atau2147483647
.0
dalam biner00000000000000000000000000000000
saat disimpan dalamINT
bidang bertanda 32-bit .2147483647
adalah01111111111111111111111111111111
- kedua angka membutuhkan jumlah ruang yang persis sama, baik dalam memori, dan pada disk, dan keduanya membutuhkan jumlah operasi CPU yang persis sama untuk diproses. Jauh lebih penting untuk membuat kode aplikasi Anda dirancang dengan benar daripada terobsesi dengan angka aktual yang disimpan dalam bidang kunci.Anda bertanya tentang pro dan kontra dari (a) menggunakan kolom ID berkapasitas lebih besar, seperti a
BIGINT
, atau (b) menggulirkan solusi Anda sendiri untuk mencegah kesenjangan ID. Untuk menjawab masalah ini:BIGINT
alih-alihINT
sebagai tipe data untuk kolom yang dimaksud. Menggunakan aBIGINT
membutuhkan jumlah penyimpanan, dua kali dalam disk, dan dalam memori untuk kolom itu sendiri. Jika kolom adalah indeks kunci utama untuk tabel yang terlibat, masing-masing dan setiap indeks non-cluster yang melekat pada tabel juga akan menyimpanBIGINT
nilai, dua kali ukuranINT
, lagi-lagi di memori dan di-disk. SQL Server menyimpan data pada disk di halaman 8KB, di mana jumlah "baris" per "halaman" tergantung pada "lebar" dari setiap baris. Jadi, misalnya, jika Anda memiliki tabel dengan 10 kolom, masing-masing satuINT
, Anda kira-kira dapat menyimpan 160 baris per halaman. Jika kolom-kolom itu di mana sebagai gantinyaBIGINT
kolom, Anda hanya dapat menyimpan 80 baris per halaman. Untuk tabel dengan jumlah baris yang sangat besar, ini jelas berarti I / O yang diperlukan untuk membaca dan menulis tabel akan menjadi dua kali lipat dalam contoh ini untuk jumlah baris tertentu. Memang, ini adalah contoh yang cukup ekstrem - jika Anda memiliki baris yang terdiri dari satuINT
atauBIGINT
kolom dan satuNCHAR(4000)
kolom, Anda akan (secara sederhana) mendapatkan satu baris per halaman, apakah Anda menggunakanINT
atauBIGINT
. Dalam skenario ini, itu tidak akan membuat perbedaan yang berarti.Putar skenario Anda sendiri untuk mencegah celah di kolom ID. Anda harus menulis kode sedemikian rupa sehingga menentukan nilai ID "selanjutnya" yang akan digunakan tidak bertentangan dengan tindakan lain yang terjadi pada tabel. Sesuatu yang secara
SELECT TOP(1) [ID] FROM [schema].[table]
naif muncul di benak saya. Bagaimana jika ada banyak aktor yang mencoba menulis baris baru ke tabel secara bersamaan? Dua aktor dapat dengan mudah mendapatkan nilai yang sama, menghasilkan konflik tulis. Mengatasi masalah ini membutuhkan akses serial ke tabel, mengurangi kinerja. Ada banyak artikel yang ditulis tentang masalah ini; Saya akan menyerahkannya kepada pembaca untuk melakukan pencarian pada topik itu.Kesimpulannya di sini adalah: Anda perlu memahami persyaratan Anda dan memperkirakan jumlah baris, dan lebar baris, serta persyaratan konkurensi aplikasi Anda dengan benar. Seperti biasa, Itu Tergantung ™.
sumber
bigint
Anda mungkin akan berterima kasih pada diri sendiri karena telah memutuskannya terlebih dahulu daripada perlu menambahkan ini ke meja dengan miliaran baris.Tugas utama yang harus dilakukan adalah menemukan akar penyebab mengapa nilai saat ini setinggi itu.
Penjelasan paling masuk akal untuk versi SQL Server sebelum SQL2012 - dengan asumsi Anda berbicara tentang database pengujian - adalah bahwa ada tes beban yang diikuti oleh pembersihan.
Dimulai dengan SQL2012 alasan yang paling mungkin adalah karena beberapa restart dari SQL Engine (seperti yang dijelaskan dalam tautan pertama yang diberikan Max).
Jika kesenjangan disebabkan oleh skenario pengujian, tidak ada alasan untuk khawatir dari sudut pandang saya. Tetapi untuk berada di sisi aman saya akan memeriksa nilai identitas selama penggunaan normal aplikasi serta sebelum dan sesudah mesin dinyalakan kembali.
"Lucu" bahwa MS menyatakan bahwa kedua alternatif (baik jejak flag 272 atau objek SEQUENCE baru) dapat memengaruhi kinerja.
Ini mungkin solusi terbaik untuk menggunakan BIGINT daripada INT hanya untuk berada di sisi yang aman untuk menutupi MS "perbaikan" selanjutnya ...
sumber
Rumtscho, Jika Anda hanya membuat 1000 baris per hari, ada sedikit untuk memutuskan - gunakan tipe data INT dengan bidang Identity dan selesai dengan itu. Matematika sederhana mengatakan jika Anda memberikan aplikasi siklus hidup 30 tahun (tidak mungkin), Anda bisa memiliki 200.000 baris per hari dan masih berada dalam kisaran angka positif dari tipe data INT.
Menggunakan BigInt terlalu banyak dalam kasus Anda, itu juga dapat menyebabkan masalah jika aplikasi atau data Anda akan diakses melalui ODBC (seperti dibawa ke Excel atau MS Access, dll.), Bigint tidak menerjemahkan dengan baik sebagian besar driver ODBC ke aplikasi desktop.
Sedangkan untuk GUIDS, selain dari ruang disk tambahan dan I / O ekstra, ada masalah besar bahwa mereka secara desain tidak berurutan, jadi jika mereka adalah bagian dari indeks yang diurutkan, Anda bisa menebak bahwa setiap insert akan mengharuskan indeks untuk digunakan. - Jim
sumber
Ada kesenjangan antara nilai yang digunakan? Atau nilai awal adalah 10.000 dan sejak saat itu semua menambahkan 1? Kadang-kadang jika nomor akan diberikan kepada pelanggan, angka awal lebih besar dari nol, misalkan 1500 misalnya, sehingga pelanggan tidak menyadari bahwa sistemnya "baru".
Kelemahan dari menggunakan bigint daripada smallint adalah karena bigint menggunakan "lebih banyak ruang disk", ketika pembacaan disk Anda membaca lebih sedikit blok disk untuk setiap disk. Jika ruang baris Anda kecil, maka ini bisa menjadi kelemahan, jika tidak, tidak masalah. Juga tidak masalah jika Anda tidak meminta banyak sumber daya sekaligus dan jika Anda memiliki indeks yang tepat.
Dan seperti yang dikatakan dalam respons lain, jika Anda khawatir kehabisan indeks, maka Anda tidak perlu khawatir, smallint dapat menangani kecuali Anda memiliki bisnis jutawan. Menciptakan mekanisme untuk "memulihkan id" itu mahal dan menambah titik kegagalan dan kompleksitas perangkat lunak.
Salam
sumber
Jika saya adalah bos Anda, saya akan sangat tertarik pada alasan nilai Id tinggi yang tidak terduga ... cara saya melihatnya, untuk masing-masing dari dua skenario yang Anda uraikan:
JIKA pengujian sebelumnya telah meningkatkan nilai identitas - maka komentar Anda yang lain tentang jumlah rekaman yang diharapkan juga akan mendorong saya untuk menyarankan jenis kunci yang lebih kecil. Sejujurnya saya juga akan mempertimbangkan apakah mungkin untuk mengatur ulang urutan dan memberi nomor baru catatan yang ada jika tes itu keluar dari karakter untuk penggunaan tabel yang dimaksudkan saat ini (kebanyakan akan mempertimbangkan ini berlebihan - 'itu tergantung').
JIKA mayoritas catatan yang ditulis pada tabel dihapus segera setelah saya akan cenderung untuk mempertimbangkan menggunakan dua tabel sebagai gantinya; tabel sementara di mana catatan tidak disimpan dalam jangka panjang, dan yang lain di mana hanya catatan yang akan kita buat disimpan secara permanen. Sekali lagi, harapan Anda untuk jumlah catatan jangka panjang menunjukkan kepada saya penggunaan tipe yang lebih kecil untuk kolom utama Anda, dan beberapa catatan per hari tidak akan menyebabkan Anda masalah kinerja untuk 'memindahkan' catatan dari satu tabel ke yang serupa lainnya satu. Saya menduga itu bukan skenario Anda, tetapi bayangkan bahwa situs web belanja mungkin lebih memilih untuk mempertahankan Keranjang / Keranjang Barang dan ketika pesanan benar-benar ditempatkan, data dipindahkan ke rangkaian Pesanan / Pesanan.
Untuk meringkas; menurut pendapat saya, BIGINT tidak perlu ditakuti, tetapi terus terang terlalu besar untuk banyak skenario. Jika tabel tidak pernah menjadi besar, Anda tidak akan pernah menyadari bahwa ada terlalu banyak pilihan pada tipe Anda ... tetapi ketika Anda memiliki tabel dengan jutaan baris dan banyak kolom FK yang BIGINT ketika ukurannya bisa lebih kecil - maka Anda mungkin menginginkan jenis telah dipilih lebih konservatif (pertimbangkan tidak hanya kolom kunci, tetapi semua kolom kunci depan, dan semua cadangan yang Anda simpan, dan seterusnya!). Ruang disk tidak selalu murah (pertimbangkan disk SAN di lokasi yang dikelola - yaitu ruang disk yang disewa).
Intinya saya berdebat untuk pertimbangan hati-hati dari pemilihan tipe data Anda selalu daripada kadang kadang . Anda tidak akan selalu memprediksi pola penggunaan dengan benar, tetapi saya pikir Anda akan membuat keputusan yang lebih baik sebagai aturan maka selalu mengasumsikan bahwa 'lebih besar lebih baik'. Secara umum saya memilih jenis terkecil yang dapat berisi rentang nilai yang diperlukan dan masuk akal dan saya akan dengan senang hati mempertimbangkan INT, SMALLINT dan bahkan TINYINT jika saya pikir nilainya cenderung cocok dengan jenis itu untuk masa mendatang yang dapat diduga. Tipe yang lebih kecil tidak mungkin digunakan dengan kolom IDENTITAS, tetapi mungkin dengan senang hati digunakan dengan tabel pencarian di mana nilai-nilai kunci diatur secara manual.
Akhirnya, teknologi yang digunakan orang dapat sangat mempengaruhi harapan dan jawaban mereka. Beberapa alat lebih mungkin menyebabkan kesenjangan dalam rentang misalnya dengan rentang pemesanan pra-identitas untuk setiap proses. Sebaliknya @ DocSalvager menyarankan urutan auditable menyeluruh yang tampaknya mencerminkan sudut pandang bos Anda; Saya pribadi tidak pernah membutuhkan tingkat otoritas yang cukup - meskipun aturan umum bahwa identitas bersifat berurutan dan umumnya tanpa kesenjangan sering sangat berguna bagi saya dalam situasi dukungan dan analisis masalah.
sumber
Menggunakan
bigint
sebagai identitas dan hidup dengan celah:int
masih akan memberi Anda data sekitar 2M hari; lebih banyak halaman harus dibaca & ditulis; indeks mungkin menjadi lebih dalam. (Pada volume ini, ini bukan masalah yang signifikan).Gulung sendiri:
sumber
Jika Anda benar-benar khawatir mengenai ambang batas atas INT untuk PK Anda, pertimbangkan untuk menggunakan GUID. Ya, saya tahu ini 16 byte vs 4 byte, tetapi disk murah.
Berikut adalah baik write-up dari pro dan kontra.
sumber
Kunci Utama RDBMS (kolom biasanya bernama 'ID')
Kesenjangan tidak dapat dihindari dalam kolom penambahan kolom RDBMS (bidang). Mereka terutama dimaksudkan untuk menciptakan PK yang unik. Untuk kinerja, produk-produk utama mengalokasikannya dalam batch, sehingga mekanisme pemulihan otomatis untuk berbagai gangguan operasi normal dapat menyebabkan angka dibiarkan tidak digunakan. Ini normal.
Urutan tak terputus
Ketika Anda membutuhkan nomor urut tak terputus, seperti yang sering diharapkan oleh pengguna, itu harus kolom terpisah yang ditugaskan secara program dan tidak boleh PK. Dengan demikian, 1000 catatan tersebut semuanya dapat memiliki angka yang sama di kolom itu.
Mengapa pengguna menginginkan urutan yang tidak terputus?
Nomor urutan yang hilang adalah tanda kesalahan paling mendasar yang ditemukan dalam segala jenis audit. Prinsip "Pembukuan-101" ini ada di mana-mana. Namun, apa yang berhasil untuk sejumlah kecil catatan yang dipelihara dengan tangan, memiliki masalah serius ketika diterapkan pada sejumlah besar catatan dalam basis data ...
Penggunaan kembali nilai-nilai kunci untuk catatan yang tidak terkait membatalkan database.
Menggunakan "integer pertama yang tidak digunakan" memperkenalkan kemungkinan bahwa pada titik tertentu di masa depan, angka akan digunakan kembali untuk catatan yang tidak terkait dengan aslinya. Itu membuat database tidak dapat diandalkan sebagai representasi fakta yang akurat. Ini adalah alasan prinsip bahwa mekanisme peningkatan otomatis sengaja dirancang untuk tidak pernah menggunakan kembali nilai.
sumber