Setelah mengajukan pertanyaan ini membandingkan GUID berurutan dan non-berurutan, saya mencoba membandingkan kinerja INSERT pada 1) tabel dengan kunci primer GUID yang diinisialisasi secara berurutan newsequentialid()
, dan 2) tabel dengan kunci primer INT yang diinisialisasi secara berurutan identity(1,1)
. Saya berharap yang terakhir menjadi yang tercepat karena lebar integer yang lebih kecil, dan juga tampaknya lebih mudah untuk menghasilkan integer berurutan daripada GUID berurutan. Tapi yang mengejutkan saya, INSERT di atas meja dengan kunci integer secara signifikan lebih lambat daripada tabel GUID berurutan.
Ini menunjukkan penggunaan waktu rata-rata (ms) untuk pengujian berjalan:
NEWSEQUENTIALID() 1977
IDENTITY() 2223
Adakah yang bisa menjelaskan ini?
Eksperimen berikut digunakan:
SET NOCOUNT ON
CREATE TABLE TestGuid2 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
CREATE TABLE TestInt (Id Int NOT NULL identity(1,1) PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000
WHILE (@BatchCounter <= 20)
BEGIN
BEGIN TRAN
DECLARE @LocalCounter INT = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuid2 (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @LocalCounter = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestInt (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @BatchCounter +=1
COMMIT
END
DBCC showcontig ('TestGuid2') WITH tableresults
DBCC showcontig ('TestInt') WITH tableresults
SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [NEWSEQUENTIALID()]
FROM TestGuid2
GROUP BY batchNumber
SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [IDENTITY()]
FROM TestInt
GROUP BY batchNumber
DROP TABLE TestGuid2
DROP TABLE TestInt
UPDATE: Memodifikasi skrip untuk melakukan penyisipan berdasarkan tabel TEMP, seperti dalam contoh oleh Phil Sandler, Mitch Wheat dan Martin di bawah ini, saya juga menemukan bahwa IDENTITAS lebih cepat sebagaimana mestinya. Tapi itu bukan cara konvensional memasukkan baris, dan saya masih tidak mengerti mengapa percobaan itu salah pada awalnya: bahkan jika saya menghilangkan GETDATE () dari contoh asli saya, IDENTITY () masih jauh lebih lambat. Jadi sepertinya satu-satunya cara untuk membuat IDENTITY () mengungguli NEWSEQUENTIALID () adalah menyiapkan baris untuk dimasukkan dalam tabel sementara dan melakukan banyak penyisipan sebagai penyisipan batch menggunakan tabel temp ini. Secara keseluruhan, saya tidak berpikir kami telah menemukan penjelasan tentang fenomena tersebut, dan IDENTITY () tampaknya masih lebih lambat untuk sebagian besar penggunaan praktis. Adakah yang bisa menjelaskan ini?
sumber
INT IDENTITY
IDENTITY
tidak memerlukan kunci tabel. Secara konseptual saya bisa melihat Anda mungkin mengharapkannya mengambil MAX (id) +1, tetapi pada kenyataannya nilai selanjutnya disimpan. Ini sebenarnya harus lebih cepat daripada menemukan GUID berikutnya.Jawaban:
Saya memodifikasi kode @Phil Sandler untuk menghapus efek memanggil GETDATE () (mungkin ada efek perangkat keras / interupsi yang terlibat ??), dan membuat baris dengan panjang yang sama.
[Sudah ada beberapa artikel sejak SQL Server 2000 yang berkaitan dengan masalah waktu dan timer resolusi tinggi, jadi saya ingin meminimalkan efek itu.]
Dalam model pemulihan sederhana dengan data dan file log yang berukuran sama dengan apa yang diperlukan, berikut adalah timing (dalam detik): (Diperbarui dengan hasil baru berdasarkan kode persis di bawah ini)
Kode yang digunakan:
Setelah membaca investigasi @ Martin, saya menjalankan kembali dengan TOP yang disarankan (@num) dalam kedua kasus, yaitu
dan inilah hasil waktunya:
Saya tidak bisa mendapatkan rencana eksekusi yang sebenarnya, karena permintaan tidak pernah kembali! Tampaknya ada bug. (Menjalankan Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64))
sumber
SORT
operator untuk GUID?NEWSEQUENTIALID
. Ini akan membuat indeks lebih dalam, menggunakan halaman data 20% lebih banyak dalam kasus OP dan hanya dijamin akan semakin meningkat sampai mesin di-reboot sehingga memiliki banyak kelemahan lebih dari satuidentity
. Tampaknya dalam kasus ini bahwa Rencana Kueri menambahkan yang tidak perlu lebih lanjut!Pada database baru dalam model pemulihan sederhana dengan file data berukuran 1GB dan file log pada 3GB (mesin laptop, kedua file pada drive yang sama) dan interval pemulihan diatur ke 100 menit (untuk menghindari pos pemeriksaan yang memiringkan hasil) Saya melihat hasil yang mirip dengan Anda dengan satu baris
inserts
.Saya menguji tiga kasus: Untuk setiap kasus saya melakukan 20 batch memasukkan 100.000 baris secara individual ke dalam tabel berikut. Skrip lengkap dapat ditemukan di riwayat revisi jawaban ini .
Untuk tabel ketiga tes memasukkan baris dengan
Id
nilai tambah tetapi ini dihitung sendiri dengan menambah nilai variabel dalam satu lingkaran.Rata-rata waktu yang diambil di 20 batch memberi hasil berikut.
Kesimpulan
Jadi sepertinya merupakan
identity
proses penciptaan yang bertanggung jawab atas hasilnya. Untuk bilangan bulat peningkatan yang dihitung sendiri maka hasilnya jauh lebih sesuai dengan apa yang diharapkan untuk dilihat ketika hanya mempertimbangkan biaya IO.Ketika saya memasukkan kode sisipan yang dijelaskan di atas ke dalam prosedur tersimpan dan mengulasnya
sys.dm_exec_procedure_stats
memberikan hasil sebagai berikutJadi dalam hasil
total_worker_time
tersebut sekitar 30% lebih tinggi. Ini mewakiliJadi hanya muncul seolah-olah kode yang menghasilkan
IDENTITY
nilai lebih banyak CPU intensif daripada yang menghasilkanNEWSEQUENTIALID()
(Perbedaan antara 2 angka adalah 10231308 yang rata-rata keluar sekitar 5μs per sisipan.) Dan untuk definisi tabel ini biaya CPU tetap ini cukup tinggi untuk melebihi pembacaan dan penulisan logis tambahan yang terjadi karena lebarnya kunci. (NB: Itzik Ben Gan melakukan pengujian serupa di sini dan menemukan penalti 2μs per sisipan)Jadi mengapa
IDENTITY
CPU lebih intensif daripadaUuidCreateSequential
?Saya yakin ini dijelaskan dalam artikel ini . Untuk setiap
identity
nilai kesepuluh yang dihasilkan, SQL Server harus menulis perubahan ke tabel sistem pada diskBagaimana dengan MultiRow Sisipan?
Ketika 100.000 baris dimasukkan dalam satu pernyataan, saya menemukan perbedaan menghilang dengan mungkin masih sedikit manfaat untuk
GUID
kasus ini tetapi tidak mendekati hasil pemotongan yang jelas. Rata-rata untuk 20 batch dalam pengujian saya adalahAlasan bahwa itu tidak memiliki penalti jelas dalam kode Phil dan hasil set pertama Mitch adalah karena kebetulan bahwa kode saya digunakan untuk melakukan memasukkan multi baris yang digunakan
SELECT TOP (@NumRows)
. Ini mencegah pengoptimal memperkirakan jumlah baris yang akan dimasukkan dengan benar.Ini tampaknya bermanfaat karena ada titik kritis tertentu di mana ia akan menambahkan operasi pengurutan tambahan untuk (seharusnya berurutan!)
GUID
S.Operasi semacam ini tidak diperlukan dari teks penjelasan dalam BOL .
Jadi sepertinya saya bug atau optimasi hilang bahwa SQL Server tidak mengenali bahwa output dari skalar komputasi akan sudah dipilah sebelumnya seperti yang tampaknya sudah dilakukan untuk
identity
kolom. ( Sunting Saya melaporkan ini dan masalah sortir yang tidak perlu sekarang diperbaiki di Denali )sumber
Cukup sederhana: dengan GUID, lebih murah untuk menghasilkan nomor berikutnya dalam baris daripada untuk IDENTITAS (Nilai saat ini dari GUID tidak harus disimpan, IDENTITAS harus). Ini berlaku bahkan untuk NEWSEQUENTIALGUID.
Anda bisa membuat tes lebih adil dan menggunakan SEQUENCER dengan CACHE besar - yang lebih murah daripada IDENTITAS.
Tetapi seperti yang dikatakan MR, ada beberapa keuntungan besar bagi GUID. Faktanya, mereka JAUH lebih scalable daripada kolom IDENTITAS (tetapi hanya jika mereka TIDAK berurutan).
Lihat: http://blog.kejser.org/2011/10/05/boosting-insert-speed-by-generating-scalable-keys/
sumber
IDENTITY
juga. karenanya keluhan di siniSaya terpesona dengan jenis pertanyaan ini. Mengapa Anda harus mempostingnya pada Jumat malam? :)
Saya pikir bahkan jika tes Anda HANYA dimaksudkan untuk mengukur kinerja INSERT, Anda (mungkin) telah memperkenalkan sejumlah faktor yang dapat menyesatkan (pengulangan, transaksi jangka panjang, dll.)
Saya tidak sepenuhnya yakin versi saya membuktikan apa pun, tetapi identitas memang berkinerja lebih baik daripada GUID di dalamnya (3,2 detik vs 6,8 detik pada PC di rumah):
sumber
Saya menjalankan skrip sampel Anda beberapa kali membuat beberapa penyesuaian untuk menghitung jumlah dan ukuran (dan terima kasih banyak telah menyediakannya).
Pertama saya akan mengatakan bahwa Anda hanya mengukur sekali aspek kinerja tombol -
INSERT
kecepatan. Jadi kecuali Anda secara khusus hanya peduli dengan memasukkan data ke dalam tabel secepat mungkin, ada lebih banyak lagi untuk hewan ini.Temuan saya secara umum mirip dengan Anda. Namun, saya akan menyebutkan bahwa varians dalam
INSERT
kecepatan antaraGUID
danIDENTITY
(int) sedikit lebih besar denganGUID
dibandingkan denganIDENTITY
- mungkin +/- 10% antara berjalan. Batch yang digunakanIDENTITY
bervariasi kurang dari 2 - 3% setiap kali.Juga untuk dicatat, kotak pengujian saya jelas kurang kuat dari milik Anda sehingga saya harus menggunakan jumlah baris yang lebih kecil.
sumber
Saya akan merujuk kembali ke konv lain di stackoverflow untuk topik yang sama ini - https://stackoverflow.com/questions/170346/what-are-the-performance-improvement-of- berikutnyaential - guid - over - standard - guid
Satu hal yang saya tahu adalah bahwa memiliki GUID berurutan adalah bahwa penggunaan indeks lebih baik karena pergerakan daun yang sangat sedikit, dan karenanya mengurangi pencarian HD. Saya akan berpikir karena ini, sisipan akan lebih cepat juga, karena tidak harus mendistribusikan kunci ke sejumlah besar halaman.
Pengalaman pribadi saya adalah ketika Anda menerapkan DB lalu lintas tinggi yang besar, lebih baik menggunakan GUID, karena itu membuatnya jauh lebih skalabel untuk integrasi dengan sistem lain. Itu berlaku untuk replikasi, khususnya, dan batas int / bigint .... bukan berarti Anda akan kehabisan bigints, tetapi akhirnya Anda akan, dan siklus kembali.
sumber