Efek apa yang akan mengurangi ukuran kolom varchar pada file database?

15

Kami memiliki sejumlah tabel di database kami yang memiliki VARCHAR(MAX)kolom di mana cukup VARCHAR(500)(atau sesuatu yang jauh lebih kecil dari maks). Secara alami saya ingin membersihkan ini, dan mendapatkan ukuran ke tingkat yang lebih masuk akal. 'Bagaimana' melakukan ini saya mengerti: pertanyaan saya adalah apa yang akan mengubah kolom ini lakukan ke halaman dan masih ada di disk? (Ada banyak info di luar sana tentang apa yang terjadi ketika Anda menumbuhkan kolom, tetapi mengalami kesulitan menemukan info tentang apa yang terjadi ketika Anda mengecilkannya.)

Beberapa tabel memiliki jumlah baris yang sangat kecil, jadi saya tidak khawatir tentang biaya perubahan, tetapi beberapa cukup besar, dan saya khawatir tentang mereka yang berpotensi direorganisasi dan menyebabkan banyak pemblokiran / downtime. Secara praktis, saya hanya ingin cara memperkirakan jendela perawatan. Secara umum, saya ingin lebih memahami bagaimana mesin database berperilaku dalam hal ini.

Terima kasih sebelumnya!

EDIT:

Saya memiliki 20 tabel yang saya lihat, meskipun hanya setengah dari mereka yang memiliki jumlah baris lebih dari 1.000. Yang terbesar memiliki hampir satu juta baris. Pelaku terburuk adalah tabel dengan 350.000 baris dan empat VARCHAR(MAX)kolom yang dapat menyusut ke VARCHAR(500)tingkat.

nateirvin
sumber

Jawaban:

12

Hal pertama yang pertama: Berapa banyak data yang ada di tabel? Jumlah baris dan ukuran tabel?

Kedua: Dapatkah Anda mencadangkan dan mengembalikan tabel ini ke server uji dan menjalankan pernyataan perubahan untuk melihat dampaknya (dengan asumsi itu tidak tidak mungkin karena tabel terlalu besar untuk muat pada sistem non-Produksi)? Saya selalu menemukan bahwa pengujian di lingkungan saya lebih akurat daripada saran dari jalinan karena ada beberapa faktor yang dapat mempengaruhi hasil yang mungkin tidak disediakan dalam pertanyaan hanya karena tidak mengetahui bahwa faktor-faktor tersebut dapat mempengaruhi hasil.

Ketiga: meningkatkan ukuran bidang panjang variabel adalah (dengan asumsi Anda tidak melampaui batas 8060 byte) operasi meta-data sederhana karena tidak ada data aktual yang akan berubah untuk operasi semacam itu. TAPI, di sisi lain, mengurangi ukuran bidang panjang variabel, bahkan untuk sesuatu yang lebih dari jelas bekerja, tidak perubahan meta-data sederhana karena SQL Server tidak tahu, sebelum memindai semua baris , bahwa ukuran yang baru diminta valid.

Oleh karena itu: Ya, ini akan mengunci tabel untuk jangka waktu tertentu . Berapa lama? Nah, inilah tes yang baru saja saya lakukan:

Saya memiliki, dari beberapa pengujian lain, sebuah meja dengan INT NOT NULLbidang tunggal dan 1 juta baris. Saya menyalinnya ke tabel baru untuk tujuan melakukan tes ini melalui:

SELECT *, CONVERT(NVARCHAR(MAX), NEWID()) AS [StringField]
INTO dbo.ResizeTest
FROM dbo.ClusteredUnique;

Dengan cara ini saya mulai dengan skenario yang sama yaitu memiliki MAXbidang (saya baru menyadari bahwa Anda sudah VARCHARdan saya gunakan NVARCHAR, tetapi itu tidak seharusnya mengubah perilaku yang saya lihat) yang kemudian bisa saya ubah 500. Dan memiliki data di dalamnya yang dapat dengan mudah masuk dalam 500 karakter. Butuh beberapa menit.

Saya kemudian berlari:

ALTER TABLE dbo.ResizeTest ALTER COLUMN [StringField] NVARCHAR(500) NULL;

Dan itu membutuhkan waktu lebih dari 11 menit.

Saya baru saja menjalankan tes lagi, kali ini menjatuhkan [ResizeTest]meja dan mengubah keduanya NVARCHARmenjadi adil VARCHAR, hanya untuk menjadi sangat yakin bahwa saya membandingkan apel dengan sesuatu yang setidaknya terlihat seperti apel ;-).

Pembuatan tabel awal memakan waktu 20 detik sedangkan ALTER TABLE butuh 2 menit.

Jadi, dalam hal memperkirakan downtime, itu sangat sulit dilakukan karena didasarkan pada kecepatan I / O disk, apakah operasi pertumbuhan otomatis perlu terjadi pada file data dan / atau log transaksi, dll. mungkin merupakan bagian besar dari mengapa tes pertama saya perlu 11 menit untuk mengubah dan yang kedua, bahkan dengan VARCHARmenjadi setengah dari ukuran NVARCHARdata, hanya membutuhkan waktu 2 menit (yaitu file-file itu sudah ditanam sebelumnya pada saat itu). Tapi tetap saja, Anda harus ingat bahwa pengujian saya berjalan di laptop saya yang bukan disk tercepat, tetapi itu juga hanya 1 juta baris dari 2 kolom kecil (22 atau lebih byte per baris).

Dan karena Anda bertanya apa yang akan dilakukan pada halaman data, inilah jawaban Anda. Saya melakukan sp_spaceusedsetelah membuat tabel, setelah melakukan ALTER COLUMN, dan setelah melakukan ALTER TABLE dbo.ResizeTest REBUILD;. Hasil (angka-angka berikut ini didasarkan pada tes kedua menggunakan VARCHAR, bukan tes pertama menggunakan NVARCHAR):

After initial table creation:        526,344 KB
After ALTER COLUMN VARCHAR(500):   1,031,688 KB  <--- !! Yikes!!
After ALTER REBUILD:                 526,472 KB

Jika Anda khawatir perlu menjaga operasi sesingkat mungkin, lihat artikel yang saya tulis tentang melakukan hal itu: Merestrukturisasi 100 Juta Baris (atau lebih) Tabel dalam Detik. Dengan susah payah! (diperlukan pendaftaran gratis).

Solomon Rutzky
sumber
2
Jadi saya menyalin tabel terburuk ke instance lokal saya (yaitu, disk lebih lambat dan 1/3 core). Saya ALTERmengedit setiap kolom secara berurutan - setiap tindakan memakan waktu kurang dari satu detik. Pada saat mereka selesai, tabel telah dua kali lipat, tetapi begitu saya melakukan REBUILD(yang juga merupakan operasi sub-detik), tabel kembali ke ukuran aslinya.
nateirvin
@nateirvin Bagus untuk didengar. Anda mungkin dapat mempercepat ALTER TABLEoperasi dengan melakukan semua bidang dalam satu tembakan, memisahkan setiap kolom dengan koma. Jika transaksi terlalu besar maka bagilah tabel menjadi 2 pernyataan ALTER dari masing-masing kolom. Dan tergantung pada seberapa besar tabel yang didapat, Anda bahkan dapat melakukan REBUILD antara masing-masing dari dua pernyataan ALTER. Sesuatu untuk dimainkan. Juga, perlu diingat bahwa operasi mungkin akan mengambil kunci skema untuk durasi yang akan memblokir semua akses ke tabel.
Solomon Rutzky
1
Saya melakukan masing-masing ALTERsecara terpisah sehingga saya bisa melacak perubahan ukuran antara masing-masing, tapi pasti bagus untuk diketahui. Terima kasih!
nateirvin
1

Dari apa yang saya kumpulkan menjalankan pernyataan alter seharusnya tidak terlalu lama selama meja tidak dikunci oleh proses lain. Menurut gbn itu hanya perubahan metadata: /programming/7261909/is-it-bad-to-use-alter-table-to-resize-a-varchar-column-to-a-larger -ukuran

Juga, tentang bagaimana itu disimpan, tampaknya SQL Server menyimpan data varchar di halaman 8k sampai mengisi seluruh halaman, yang pada saat ini menggantikannya dengan pointer dan menyimpannya sebagai BLOB.

Saya berasumsi bahwa ketika Anda mengubah panjangnya, Anda tidak akan memotong catatan apa pun. Jika demikian, maka maksimal data yang Anda konversi menjadi varchar (500) seharusnya, paling banyak, panjangnya 502 byte dan seharusnya tidak memiliki pointer.

Jadi, singkatnya, tidak banyak yang harus diubah selama Anda tidak memotong data apa pun.

DForck42
sumber
5
Ini benar-benar salah. Saya tidak akan downvote karena Anda benar-benar mengujinya (yang lebih dari beberapa orang, jadi terima kasih untuk melakukan itu), tetapi Anda perlu menguji ini pada skala. Jawaban yang Anda tautkan adalah tentang meningkatkan ukuran, bukan mengurangi. Itu adalah dua operasi yang sangat berbeda.
Solomon Rutzky