Remus telah membantu menunjukkan bahwa panjang maksimal VARCHAR
kolom berdampak pada perkiraan ukuran baris dan oleh karena itu pemberian memori yang disediakan SQL Server.
Saya mencoba melakukan sedikit penelitian lebih lanjut untuk memperluas bagian "dari ini pada hal kaskade" jawabannya. Saya tidak memiliki penjelasan yang lengkap atau singkat, tetapi inilah yang saya temukan.
Skrip repro
Saya membuat skrip lengkap yang menghasilkan set data palsu yang pembuatan indeksnya kira-kira 10 kali lebih lama pada mesin saya untuk VARCHAR(256)
versi. Data yang digunakan adalah persis sama, tapi tabel pertama menggunakan panjang max sebenarnya 18
, 75
, 9
, 15
, 123
, dan 5
, sementara semua kolom menggunakan panjang maksimum 256
pada tabel kedua.
Mengunci tabel asli
Di sini kita melihat bahwa kueri asli selesai dalam sekitar 20 detik dan pembacaan logis sama dengan ukuran tabel ~1.5GB
(195K halaman, 8K per halaman).
-- CPU time = 37674 ms, elapsed time = 19206 ms.
-- Table 'testVarchar'. Scan count 9, logical reads 194490, physical reads 0
CREATE CLUSTERED INDEX IX_testVarchar
ON dbo.testVarchar (s1, s2, s3, s4)
WITH (MAXDOP = 8) -- Same as my global MAXDOP, but just being explicit
GO
Mengunci tabel VARCHAR (256)
Untuk VARCHAR(256)
tabel, kita melihat bahwa waktu yang berlalu telah meningkat secara dramatis.
Menariknya, baik waktu CPU maupun bacaan logis tidak bertambah. Ini masuk akal mengingat bahwa tabel memiliki data yang sama persis, tetapi tidak menjelaskan mengapa waktu yang berlalu jauh lebih lambat.
-- CPU time = 33212 ms, elapsed time = 263134 ms.
-- Table 'testVarchar256'. Scan count 9, logical reads 194491
CREATE CLUSTERED INDEX IX_testVarchar256
ON dbo.testVarchar256 (s1, s2, s3, s4)
WITH (MAXDOP = 8) -- Same as my global MAXDOP, but just being explicit
GO
I / O dan tunggu statistik: asli
Jika kita menangkap sedikit lebih detail (menggunakan p_perfMon, prosedur yang saya tulis ), kita dapat melihat bahwa sebagian besar I / O dilakukan pada LOG
file. Kami melihat jumlah I / O yang relatif sederhana pada file aktual ROWS
(file data utama), dan tipe tunggu utamanya adalah LATCH_EX
, yang menunjukkan pertentangan halaman dalam memori.
Kita juga dapat melihat bahwa disk pemintalan saya berada di antara "buruk" dan "sangat buruk", menurut Paul Randal :)
I / O dan tunggu statistik: VARCHAR (256)
Untuk VARCHAR(256)
versi, statistik I / O dan tunggu terlihat sangat berbeda! Di sini kita melihat peningkatan besar dalam I / O pada file data ( ROWS
), dan waktu kios sekarang membuat Paul Randal hanya mengatakan "WOW!".
Tidak mengherankan bahwa tipe menunggu # 1 sekarang IO_COMPLETION
. Tetapi mengapa begitu banyak I / O dihasilkan?
Paket permintaan aktual: VARCHAR (256)
Dari rencana kueri, kita dapat melihat bahwa Sort
operator memiliki tumpahan rekursif (sedalam 5 level!) Dalam VARCHAR(256)
versi kueri. (Tidak ada tumpahan sama sekali dalam versi aslinya.)
Kemajuan permintaan langsung: VARCHAR (256)
Kita bisa menggunakan sys.dm_exec_query_profiles untuk melihat kemajuan permintaan langsung dalam SQL 2014+ . Dalam versi asli, keseluruhan Table Scan
dan Sort
diproses tanpa tumpahan ( spill_page_count
tetap ada di 0
seluruh).
VARCHAR(256)
Namun dalam versi, kita dapat melihat bahwa tumpahan halaman dengan cepat menumpuk untuk Sort
operator. Ini adalah snapshot dari kemajuan permintaan tepat sebelum permintaan selesai. Data di sini dikumpulkan di semua utas.
Jika saya menggali masing-masing utas, saya melihat bahwa 2 utas menyelesaikan pengurutan dalam waktu sekitar 5 detik (keseluruhan @ 20 detik, setelah 15 detik dihabiskan untuk pemindaian tabel). Jika semua utas berkembang pada tingkat ini, VARCHAR(256)
pembuatan indeks akan selesai dalam waktu yang hampir sama dengan tabel aslinya.
Namun, 6 utas yang tersisa berkembang dengan kecepatan yang jauh lebih lambat. Ini mungkin karena cara memori dialokasikan dan cara benang ditahan oleh I / O saat mereka menumpahkan data. Saya tidak tahu pasti.
Apa yang bisa kau lakukan?
Ada beberapa hal yang mungkin ingin Anda coba:
- Bekerja dengan vendor untuk memutar kembali ke versi sebelumnya. Jika itu tidak memungkinkan, biarkan vendor yang Anda tidak senang dengan perubahan ini sehingga mereka dapat mempertimbangkan untuk mengembalikannya di rilis mendatang.
- Saat menambahkan indeks Anda, pertimbangkan untuk menggunakan di
OPTION (MAXDOP X)
mana X
angka yang lebih rendah dari pengaturan tingkat server Anda saat ini. Ketika saya menggunakan OPTION (MAXDOP 2)
set data spesifik ini di komputer saya, VARCHAR(256)
versi selesai 25 seconds
(dibandingkan dengan 3-4 menit dengan 8 utas!). Mungkin saja perilaku tumpah diperburuk oleh paralelisme yang lebih tinggi.
- Jika ada investasi perangkat keras tambahan, buat profil I / O (kemungkinan kemacetan) pada sistem Anda dan pertimbangkan untuk menggunakan SSD untuk mengurangi latensi I / O yang ditimbulkan oleh tumpahan.
Bacaan lebih lanjut
Paul White memiliki posting blog yang bagus di internal jenis SQL Server yang mungkin menarik. Itu memang berbicara sedikit tentang tumpah, kemiringan utas, dan alokasi memori untuk jenis paralel.