Apakah ada cara untuk mengubah tipe data kolom sebagai operasi metadata saja?
Saya rasa tidak, inilah cara kerja produk saat ini. Ada beberapa solusi yang sangat bagus untuk batasan yang diusulkan dalam jawaban Joe ini .
... hasil dalam SQL Server menulis ulang seluruh tabel (dan menggunakan ukuran tabel 2x dalam ruang log)
Saya akan menanggapi dua bagian dari pernyataan itu secara terpisah.
Menulis Ulang Meja
Seperti yang saya sebutkan sebelumnya, sebenarnya tidak ada cara untuk menghindari ini. Itu tampaknya menjadi kenyataan dari situasi itu, bahkan jika itu tidak masuk akal sepenuhnya dari perspektif kita sebagai pelanggan.
Melihat DBCC PAGE
sebelum dan sesudah mengubah kolom dari 4000 menjadi 260 menunjukkan bahwa semua data diduplikasi pada halaman data (tabel pengujian saya memiliki 'A'
260 kali berturut-turut):
Pada titik ini, ada dua salinan data yang sama persis di halaman. Kolom "lama" pada dasarnya dihapus (id diubah dari id = 2 menjadi id = 67108865), dan versi "baru" kolom diperbarui untuk menunjuk ke offset baru dari data pada halaman:
Menggunakan 2x Tabel Ukuran dalam Ruang Log
Menambahkan WITH (ONLINE = ON)
ke akhir ALTER
pernyataan mengurangi aktivitas logging sekitar setengahnya , jadi ini adalah satu peningkatan yang dapat Anda lakukan untuk mengurangi jumlah penulisan ke disk / ruang disk yang dibutuhkan.
Saya menggunakan test harness ini untuk mencobanya:
USE [master];
GO
DROP DATABASE IF EXISTS [248749];
GO
CREATE DATABASE [248749]
ON PRIMARY
(
NAME = N'248749',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\DATA\248749.mdf',
SIZE = 2048000KB,
FILEGROWTH = 65536KB
)
LOG ON
(
NAME = N'248749_log',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\DATA\248749_log.ldf',
SIZE = 2048000KB,
FILEGROWTH = 65536KB
);
GO
USE [248749];
GO
CREATE TABLE dbo.[table]
(
id int IDENTITY(1,1) NOT NULL,
[col] nvarchar (4000) NULL,
CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED (id ASC)
);
INSERT INTO dbo.[table]
SELECT TOP (1000000)
REPLICATE(N'A', 260)
FROM master.dbo.spt_values v1
CROSS JOIN master.dbo.spt_values v2
CROSS JOIN master.dbo.spt_values v3;
GO
Saya memeriksa sys.dm_io_virtual_file_stats(DB_ID(N'248749'), DEFAULT)
sebelum dan sesudah menjalankan ALTER
pernyataan, dan berikut ini perbedaannya:
Default (Offline) ALTER
- File data ditulis / byte ditulis: 34.809 / 2.193.801.216
- File log menulis / byte yang ditulis: 40.953 / 1.484.910.080
On line ALTER
- File data ditulis / byte ditulis: 36.874 / 1.693.745.152 (turun 22,8%)
- File log menulis / byte ditulis: 24.680 / 866.166.272 (41% turun)
Seperti yang Anda lihat, ada sedikit penurunan pada file data tulis, dan penurunan besar dalam file log menulis.
update table set new_col = old_col where new_col <> old_col;
sebelum menjatuhkanold_col
.where new_col <> old_col
tidak menghasilkan klausa pemfilteran lainnya, Anda bisa menambahkan pemicu untuk membawa perubahan ini saat terjadi dan menghapusnya di akhir proses. Masih merupakan hit kinerja potensial, tetapi banyak jumlah kecil selama proses alih-alih satu hit besar pada akhirnya, mungkin (tergantung pada pola pembaruan aplikasi Anda untuk tabel) menambahkan total jauh lebih sedikit daripada total satu hit besar .Yah ada alternatif tergantung pada ruang yang tersedia di database Anda.
Buat salinan persis meja Anda (mis.
new_table
), Kecuali untuk kolom tempat Anda akan menyingkatNVARCHAR(4000)
menjadiNVARCHAR(260)
:Di jendela pemeliharaan salin data dari tabel "rusak" (
table
) ke tabel "tetap" (new_table
) dengan sederhanaINSERT ... INTO ... SELECT ....
:Ganti nama tabel "broken"
table
menjadi sesuatu yang lain:Ganti nama tabel "tetap"
new_table
menjaditable
:Jika semuanya baik-baik saja, letakkan tabel berganti nama "broken":
Ini dia.
Menjawab Pertanyaan Anda
Tidak. Saat ini tidak memungkinkan
Tidak.
( Lihat solusi saya dan yang lainnya. )
sumber