Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Cara mendapatkan nomor berikutnya secara berurutan

Jika Anda tidak memelihara meja penghitung, ada dua opsi. Dalam transaksi, pertama pilih MAX(seq_id) dengan salah satu petunjuk tabel berikut:

  1. WITH(TABLOCKX, HOLDLOCK)
  2. WITH(ROWLOCK, XLOCK, HOLDLOCK)

TABLOCKX + HOLDLOCK agak berlebihan. Ini memblokir pernyataan pilih biasa, yang dapat dianggap berat walaupun transaksinya kecil.

Sebuah ROWLOCK, XLOCK, HOLDLOCK petunjuk tabel mungkin merupakan ide yang lebih baik (tetapi:baca alternatif dengan tabel penghitung lebih lanjut). Keuntungannya adalah tidak memblokir pernyataan pilih biasa, yaitu ketika pernyataan pilih tidak muncul dalam SERIALIZABLE transaksi, atau ketika pernyataan pilih tidak memberikan petunjuk tabel yang sama. Menggunakan ROWLOCK, XLOCK, HOLDLOCK akan tetap memblokir pernyataan penyisipan.

Tentu saja Anda perlu memastikan bahwa tidak ada bagian lain dari program Anda yang memilih MAX(seq_id) tanpa petunjuk tabel ini (atau di luar SERIALIZABLE transaksi) dan kemudian gunakan nilai ini untuk menyisipkan baris.

Perhatikan bahwa tergantung pada jumlah baris yang dikunci dengan cara ini, ada kemungkinan bahwa SQL Server akan meningkatkan kunci menjadi kunci tabel. Baca selengkapnya tentang eskalasi penguncian di sini .

Prosedur penyisipan menggunakan WITH(ROWLOCK, XLOCK, HOLDLOCK) akan terlihat sebagai berikut:

DECLARE @target_model INT=3;
DECLARE @part VARCHAR(128)='Spine';
BEGIN TRY
    BEGIN TRANSACTION;
    DECLARE @max_seq INT=(SELECT MAX(seq) FROM dbo.table_seq WITH(ROWLOCK,XLOCK,HOLDLOCK) WHERE [email protected]_model);
    IF @max_seq IS NULL SET @max_seq=0;
    INSERT INTO dbo.table_seq(part,seq,model)VALUES(@part,@max_seq+1,@target_model);
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
END CATCH

Alternatif dan mungkin ide yang lebih baik adalah memiliki penghitung meja, dan berikan petunjuk tabel ini di meja penghitung. Tabel ini akan terlihat seperti berikut:

CREATE TABLE dbo.counter_seq(model INT PRIMARY KEY, seq_id INT);

Anda kemudian akan mengubah prosedur penyisipan sebagai berikut:

DECLARE @target_model INT=3;
DECLARE @part VARCHAR(128)='Spine';
BEGIN TRY
    BEGIN TRANSACTION;
    DECLARE @new_seq INT=(SELECT seq FROM dbo.counter_seq WITH(ROWLOCK,XLOCK,HOLDLOCK) WHERE [email protected]_model);
    IF @new_seq IS NULL 
        BEGIN SET @new_seq=1; INSERT INTO dbo.counter_seq(model,seq)VALUES(@target_model,@new_seq); END
    ELSE
        BEGIN SET @new_seq+=1; UPDATE dbo.counter_seq SET [email protected]_seq WHERE [email protected]_model; END
    INSERT INTO dbo.table_seq(part,seq,model)VALUES(@part,@new_seq,@target_model);
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
END CATCH

Keuntungannya adalah lebih sedikit kunci baris yang digunakan (yaitu satu kunci baris per model di dbo.counter_seq ), dan eskalasi kunci tidak dapat mengunci seluruh dbo.table_seq tabel sehingga memblokir pernyataan tertentu.

Anda dapat menguji semua ini dan melihat efeknya sendiri, dengan menempatkan WAITFOR DELAY '00:01:00' setelah memilih urutan dari counter_seq , dan mengutak-atik tabel di tab SSMS kedua.

PS1:Menggunakan ROW_NUMBER() OVER (PARTITION BY model ORDER BY ID) bukanlah cara yang baik. Jika baris dihapus/ditambahkan, atau ID diubah, urutannya akan berubah (pertimbangkan ID faktur yang tidak boleh berubah). Juga dalam hal kinerja harus menentukan nomor baris dari semua baris sebelumnya saat mengambil satu baris adalah ide yang buruk.

PS2:Saya tidak akan pernah menggunakan sumber daya luar untuk menyediakan penguncian, ketika SQL Server sudah menyediakan penguncian melalui tingkat isolasi atau petunjuk tabel yang halus.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana saya bisa memilih dari daftar nilai di SQL Server

  2. Hitung rentang tanggal yang hilang dan rentang tanggal yang tumpang tindih antara dua tanggal

  3. SQL Server 2008 - Permintaan Bersyarat

  4. Bagaimana saya bisa melakukan pernyataan UPDATE dengan JOIN di SQL Server?

  5. Periksa Surat Tidak Terkirim di SQL Server (T-SQL)