Saya telah mewarisi beberapa database SQL Server. Ada satu tabel (saya akan memanggil "G"), dengan sekitar 86,7 juta baris, dan lebar 41 kolom, dari basis data sumber (saya akan memanggil "Q") pada SQL Server 2014 Standard yang membuat ETL beralih ke database target (saya akan memanggil "P") dengan nama tabel yang sama pada SQL Server 2008 R2 Standard.
yaitu [Q]. [G] ---> [P]. [G]
EDIT: 3/20/2017: Beberapa orang bertanya apakah tabel sumber adalah sumber HANYA ke tabel target. Ya, itu satu-satunya sumber. Sejauh ETL berjalan, tidak ada transformasi nyata yang terjadi; itu secara efektif dimaksudkan untuk menjadi salinan data sumber 1: 1. Karenanya, tidak ada rencana untuk menambahkan sumber tambahan ke tabel target ini.
Sedikit lebih dari setengah kolom di [Q]. [G] adalah VARCHAR (tabel sumber):
- 13 kolom adalah VARCHAR (80)
- 9 kolom adalah VARCHAR (30)
- 2 kolom adalah VARCHAR (8).
Demikian pula, kolom yang sama dalam [P]. [G] adalah NVARCHAR (tabel target), dengan # kolom yang sama dengan lebar yang sama. (Dengan kata lain, panjangnya sama, tetapi NVARCHAR).
- 13 kolom adalah NVARCHAR (80)
- 9 kolom adalah NVARCHAR (30)
- 2 kolomnya adalah NVARCHAR (8).
Ini bukan desain saya.
Saya ingin ALTER [P]. [G] (target) kolom tipe data dari NVARCHAR ke VARCHAR. Saya ingin melakukannya dengan aman (tanpa kehilangan data dari konversi).
Bagaimana saya bisa melihat nilai data di setiap kolom NVARCHAR di tabel target untuk mengonfirmasi apakah kolom tersebut benar-benar berisi data Unicode atau tidak?
Kueri (DMV?) Yang dapat memeriksa setiap nilai (dalam satu lingkaran?) Dari setiap kolom NVARCHAR dan memberi tahu saya jika ada nilai yang asli Unicode akan menjadi solusi ideal, tetapi metode lain dipersilakan.
sumber
[G]
ETLed ke[P]
. Jika[G]
adalahvarchar
, dan proses ETL adalah satu-satunya cara data yang datang ke dalam[P]
, maka kecuali proses menambahkan karakter Unicode yang benar, ada tidak boleh ada. Jika proses lain menambah atau memodifikasi data[P]
, Anda harus lebih berhati-hati - hanya karena semua data saatvarchar
ini tidak berarti bahwanvarchar
data tidak dapat ditambahkan besok. Demikian pula, ada kemungkinan bahwa apa pun yang mengkonsumsi data dalam data[P]
kebutuhannvarchar
.Jawaban:
Misalkan salah satu kolom Anda tidak mengandung data unicode. Untuk memverifikasi bahwa Anda perlu membaca nilai kolom untuk setiap baris. Kecuali jika Anda memiliki indeks pada kolom, dengan tabel rowstore Anda harus membaca setiap halaman data dari tabel. Dengan mengingat hal itu, saya pikir sangat masuk akal untuk menggabungkan semua pemeriksaan kolom ke dalam satu kueri terhadap tabel. Dengan begitu Anda tidak akan membaca data tabel berkali-kali dan Anda tidak perlu kode kursor atau semacam loop lainnya.
Untuk memeriksa satu kolom yakin bahwa Anda bisa melakukan ini:
Para pemain dari
NVARCHAR
keVARCHAR
harus memberi Anda hasil yang sama kecuali jika ada karakter unicode. Karakter Unicode akan dikonversi menjadi?
. Jadi kode di atas harus menanganiNULL
kasus dengan benar. Anda memiliki 24 kolom untuk diperiksa, jadi Anda memeriksa setiap kolom dalam satu permintaan dengan menggunakan agregat skalar. Satu implementasi di bawah ini:Untuk setiap kolom Anda akan mendapatkan hasil
1
jika salah satu nilainya berisi unicode. Hasil dari0
berarti bahwa semua data dapat dikonversi dengan aman.Saya sangat menyarankan untuk membuat salinan tabel dengan definisi kolom baru dan menyalin data Anda di sana. Anda akan melakukan konversi yang mahal jika Anda melakukannya sehingga membuat salinan mungkin tidak terlalu lambat. Memiliki salinan berarti Anda dapat dengan mudah memvalidasi bahwa semua data masih ada (salah satu caranya adalah dengan menggunakan KECUALI kata kunci) dan Anda dapat membatalkan operasi dengan sangat mudah.
Perlu diketahui juga bahwa Anda mungkin tidak memiliki data unicode saat ini, mungkin saja ETL di masa depan dapat memuat unicode ke dalam kolom yang sebelumnya bersih. Jika tidak ada pemeriksaan untuk ini dalam proses ETL Anda, Anda harus mempertimbangkan untuk menambahkannya sebelum melakukan konversi ini.
sumber
NVARCHAR
kolomNVARCHAR
karena sudah tipe itu. Dan tidak yakin bagaimana Anda menentukan karakter yang tidak dapat dikonversi, tetapi Anda dapat mengonversi kolomVARBINARY
untuk mendapatkan urutan UTF-16 byte. Dan UTF-16 adalah urutan byte terbalik, jadip
=0x7000
dan kemudian Anda membalikkan dua byte tersebut untuk mendapatkan Code PointU+0070
. Tetapi, jika sumbernya adalah VARCHAR, maka itu bukan karakter Unicode. Sesuatu yang lain sedang terjadi. Perlu info lebih lanjut.VARCHAR
secara implisit akan dikonversi keNVARCHAR
, tetapi mungkin lebih baik untuk dilakukanCONVERT(NVARCHAR(80), CONVERT(VARCHAR(80), column)) <> column
.SUBSTRING
kadang-kadang berfungsi, tetapi tidak berfungsi dengan Karakter Tambahan saat menggunakan Collations yang tidak berakhir_SC
, dan yang digunakan John tidak, meskipun kemungkinan tidak menjadi masalah di sini. Tetapi mengonversi ke VARBINARY selalu berhasil. DanCONVERT(VARCHAR(10), CONVERT(NVARCHAR(10), '›'))
tidak menghasilkan?
, jadi saya ingin melihat byte. Proses ETL mungkin telah mengubahnya.Sebelum melakukan sesuatu, harap pertimbangkan pertanyaan yang diajukan oleh @RDFozz dalam komentar pada pertanyaan, yaitu:
Jika responsnya adalah sesuatu di luar "Saya 100% yakin bahwa ini adalah satu - satunya sumber data untuk tabel tujuan ini", maka jangan membuat perubahan apa pun, terlepas dari apakah data saat ini dalam tabel dapat dikonversi tanpa Data hilang.
Dan saya akan menambahkan pertanyaan terkait: Sudah ada diskusi sekitar yang mendukung beberapa bahasa dalam tabel sumber arus (yaitu
[Q].[G]
) dengan mengkonversi itu untukNVARCHAR
?Anda perlu bertanya-tanya untuk mengetahui kemungkinan-kemungkinan ini. Saya berasumsi bahwa saat ini Anda belum diberi tahu apa pun yang akan mengarah ke arah ini, Anda tidak akan mengajukan pertanyaan ini, tetapi jika pertanyaan-pertanyaan ini dianggap "tidak", maka mereka perlu ditanyakan, dan ditanya tentang audiens yang cukup luas untuk mendapatkan jawaban yang paling akurat / lengkap.
Masalah utama di sini adalah tidak begitu banyak memiliki poin kode Unicode yang tidak dapat dikonversi (pernah), tetapi lebih dari itu memiliki poin kode yang tidak akan cocok semua ke halaman kode tunggal. Itu hal yang menyenangkan tentang Unicode: itu dapat menampung karakter dari SEMUA halaman kode. Jika Anda mengonversi dari
NVARCHAR
- tempat Anda tidak perlu khawatir tentang halaman kode - keVARCHAR
, maka Anda perlu memastikan bahwa Kolasi kolom tujuan menggunakan halaman kode yang sama dengan kolom sumber. Ini mengasumsikan memiliki satu sumber, atau beberapa sumber menggunakan halaman kode yang sama (meskipun tidak harus sama dengan Collation). Tetapi jika ada banyak sumber dengan banyak halaman kode, maka Anda berpotensi mengalami masalah berikut:Pengembalian (set hasil 2):
Seperti yang Anda lihat, semua karakter itu dapat dikonversi menjadi
VARCHAR
, hanya saja tidak diVARCHAR
kolom yang sama .Gunakan kueri berikut untuk menentukan apa halaman kode untuk setiap kolom tabel sumber Anda:
YANG TELAH DIBILANG....
Anda menyebutkan berada di SQL Server 2008 R2, TAPI, Anda tidak mengatakan Edisi apa. JIKA Anda berada di Edisi Perusahaan, lupakan semua hal konversi ini (karena Anda kemungkinan melakukannya hanya untuk menghemat ruang), dan aktifkan Kompresi Data:
Implementasi Kompresi Unicode
Jika menggunakan Edisi Standar (dan sekarang sepertinya Anda adalah 😞) maka ada kemungkinan lain yang lebih mudah: perbarui ke SQL Server 2016 karena SP1 mencakup kemampuan untuk semua Edisi untuk menggunakan Kompresi Data (ingat, saya memang mengatakan "tembakan panjang" "😉).
Tentu saja, sekarang baru saja diklarifikasi bahwa hanya ada satu sumber untuk data, maka Anda tidak perlu khawatir karena sumber tidak dapat berisi karakter hanya Unicode, atau karakter di luar kode spesifiknya halaman. Dalam hal ini, satu-satunya hal yang harus Anda perhatikan adalah menggunakan Collation yang sama dengan kolom sumber, atau setidaknya satu yang menggunakan Halaman Kode yang sama. Artinya, jika kolom sumber menggunakan
SQL_Latin1_General_CP1_CI_AS
, maka Anda bisa menggunakanLatin1_General_100_CI_AS
di tempat tujuan.Setelah mengetahui Collation apa yang akan digunakan, Anda dapat:
ALTER TABLE ... ALTER COLUMN ...
menjadiVARCHAR
(pastikan untuk menentukan pengaturanNULL
/ saat iniNOT NULL
), yang membutuhkan sedikit waktu dan banyak ruang log transaksi untuk 87 juta baris, ATAUBuat kolom "ColumnName_tmp" baru untuk masing-masing kolom dan perlahan-lahan isi dengan
UPDATE
melakukanTOP (1000) ... WHERE new_column IS NULL
. Setelah semua baris diisi (dan divalidasi bahwa mereka semua disalin dengan benar! Anda mungkin perlu pemicu untuk menangani UPDATE, jika ada), dalam transaksi eksplisit, gunakansp_rename
untuk menukar nama kolom dari kolom "saat ini" menjadi " _Old "dan kemudian kolom" _tmp "baru untuk menghapus" _tmp "dari nama. Kemudian panggilsp_reconfigure
meja untuk membatalkan rencana cache yang mereferensikan tabel, dan jika ada Tampilan yang mereferensikan tabel Anda perlu meneleponsp_refreshview
(atau sesuatu seperti itu). Setelah Anda memvalidasi aplikasi dan ETL bekerja dengan benar, maka Anda dapat menjatuhkan kolom.sumber
Latin1_General_100_CI_AS
jauh lebih baik daripada yang Anda gunakan. Makna mudah bahwa perilaku penyortiran dan perbandingan akan sama di antara mereka, bahkan jika tidak sebagus Kolasi yang baru saya sebutkan.Saya memiliki beberapa pengalaman dengan ini dari belakang ketika saya memiliki pekerjaan nyata. Karena pada saat itu saya ingin menyimpan data base, dan saya juga harus memperhitungkan data baru yang mungkin memiliki karakter yang akan hilang dalam shuffle, saya pergi dengan kolom komputasi yang tidak bertahan lama.
Berikut adalah contoh cepat menggunakan salinan database Super User dari dump data SO .
Kita dapat langsung melihat bahwa ada DisplayNames dengan karakter Unicode:
Jadi mari kita tambahkan kolom yang dihitung untuk mencari tahu berapa banyak! Kolom DisplayName adalah
NVARCHAR(40)
.Hitungannya kembali ~ 3000 baris
Namun, rencana pelaksanaannya sedikit membosankan. Kueri selesai dengan cepat, tetapi kumpulan data ini tidak terlalu besar.
Karena kolom yang dikomputasi tidak perlu dipertahankan untuk menambahkan indeks, kita dapat melakukan salah satu dari ini:
Yang memberi kami rencana yang sedikit lebih rapi:
Saya mengerti jika hal ini tidak dengan jawaban, karena melibatkan perubahan arsitektur, tapi mengingat ukuran data, Anda mungkin melihat menambahkan indeks untuk mengatasi permintaan yang diri bergabung meja pula.
Semoga ini membantu!
sumber
Menggunakan contoh di Cara memeriksa apakah bidang berisi data unicode , Anda bisa membaca data di setiap kolom dan melakukan
CAST
dan periksa di bawah:sumber