Bagaimana cara kerja collation-insensitive case?

19

Jenis pemeriksaan standar dalam SQL Server memungkinkan untuk mengindeks terhadap string tidak sensitif case namun kasus data tetap ada. Bagaimana cara kerjanya? Saya mencari mur dan baut yang sebenarnya, bit dan byte, atau sumber yang bagus yang menjelaskannya secara rinci.

create table casetest (fruitnames nvarchar(50) not null);
create unique index IX_fruitnames on casetest(fruitnames);

insert into casetest values ('apples');
insert into casetest values ('Pears');
-- this insert fails
insert into casetest values ('pears');

-- this yields 'Pears' as a result
select * from casetest (forceseek) where fruitnames = 'PEARS'

update casetest set fruitnames = 'pears' where fruitnames = 'pEArs'

-- this yields 'pears' as a result
select * from casetest (forceseek) where fruitnames = 'PEARS'

Pertanyaan tentang SQL Server Collations Anda terlalu malu untuk bertanya oleh Robert Sheldon mencakup cara menggunakan collation. Itu tidak mencakup cara kerja collation. Saya tertarik pada bagaimana indeks dapat dibuat secara efisien / tanya tidak peduli tentang kasus, sementara secara bersamaan menyimpan data kasus.

cocogorilla
sumber
1
Anda dapat secara efisien melakukan kueri (misalnya menggunakan pencarian indeks) string yang tidak peka terhadap bidang yang peka terhadap huruf besar-kecil, tetapi sedikit mengganggu .
John Eisbrener
cocogorilla: silakan lihat catatan # 1 yang baru saja saya tambahkan di akhir jawaban saya ulang: susunan "default".
Solomon Rutzky

Jawaban:

26

pengindeksan terhadap string peka huruf besar kecil namun kasus data tetap ada. Bagaimana cara kerjanya?

Ini sebenarnya bukan perilaku khusus SQL Server, hanya bagaimana hal-hal ini bekerja secara umum.

Jadi, data adalah data. Jika Anda berbicara tentang indeks khusus, data perlu disimpan karena yang lain itu akan membutuhkan tampilan-up di meja utama setiap kali untuk mendapatkan nilai yang sebenarnya, dan tidak akan ada kemungkinan indeks yang meliputi (di paling tidak untuk tipe string).

Data, baik dalam tabel / indeks berkerumun atau indeks non-berkerumun, tidak mengandung informasi collation / sorting. Ini hanyalah data. Kolasi (aturan lokal / budaya dan sensitivitas) hanyalah meta data yang dilampirkan pada kolom dan digunakan saat operasi sortir dipanggil (kecuali diganti olehCOLLATEklausa), yang akan mencakup pembuatan / pembangunan kembali indeks. Aturan yang didefinisikan oleh non-binary collation digunakan untuk menghasilkan kunci sortir, yang merupakan representasi biner dari string (kunci sortir tidak diperlukan dalam collations biner). Representasi biner ini menggabungkan semua aturan lokal / budaya dan sensitivitas yang dipilih. Tombol sortir digunakan untuk menempatkan catatan dalam urutan yang tepat, tetapi tidak dengan sendirinya disimpan dalam indeks atau tabel. Mereka tidak disimpan (setidaknya saya belum melihat nilai-nilai ini di indeks dan diberitahu bahwa mereka tidak disimpan) karena:

  1. Mereka tidak benar-benar diperlukan untuk menyortir karena mereka hanya akan berada dalam urutan yang sama dengan baris dalam tabel atau indeks. Tapi, urutan fisik indeks itu hanya penyortiran, bukan perbandingan.
  2. Sementara menyimpannya mungkin membuat perbandingan lebih cepat, itu juga akan membuat indeks lebih besar karena ukuran minimum untuk satu karakter adalah 5 byte, dan itu hanya "overhead" (dari struktur kunci sortir). Sebagian besar karakter masing-masing 2 byte, ditambah 1 byte jika ada aksen, ditambah 1 byte jika huruf besar. Misalnya, "e" adalah kunci 7-byte, "E" dan "é" keduanya 8 byte, dan "É" adalah kunci 9-byte. Karenanya, tidak layak menyimpan ini pada akhirnya.

Ada dua jenis kumpulan: SQL Server dan Windows.

SQL Server

SQL Server collations (orang-orang dengan nama dimulai dengan SQL_) adalah lebih tua, pra-SQL Server 2000 cara menyortir / membandingkan (meskipun SQL_Latin1_General_CP1_CI_ASadalah masih default instalasi pada US English OS, cukup sedih). Dalam model yang lebih tua, sederhana, non-Unicode ini, setiap kombinasi lokal, halaman kode, dan berbagai kepekaan diberikan pemetaan statis masing-masing karakter dalam halaman kode itu. Setiap karakter diberi nilai (yaitu mengurutkan bobot) untuk menunjukkan bagaimana persamaannya dengan yang lain. Perbandingan dalam model ini tampaknya melakukan operasi dua lintasan:

  1. Pertama, menghapus semua aksen (sehingga "  ü  " menjadi "  u  "), memperluas karakter seperti "  Æ  " menjadi "  A  " dan "  E  ", lalu melakukan pengurutan awal sehingga kata-kata berada dalam urutan alami (bagaimana Anda ingin berharap menemukannya di kamus).
  2. Kemudian, karakter demi karakter menentukan kesetaraan berdasarkan nilai-nilai yang mendasari ini untuk setiap karakter. Bagian kedua inilah yang dijelaskan oleh mustaccio dalam jawabannya .

Satu-satunya sensitivitas yang dapat disesuaikan dalam susunan ini adalah: "huruf" dan "aksen" ("lebar", "tipe kana" dan "pemilih variasi" tidak tersedia). Juga, tak satu pun dari kumpulan ini mendukung Karakter Tambahan (yang masuk akal karena itu adalah Unicode-spesifik dan kumpulan ini hanya berlaku untuk data non-Unicode).

Pendekatan ini hanya berlaku untuk VARCHARdata non-Unicode . Setiap kombinasi unik lokal, halaman kode, sensitivitas huruf, dan sensitivitas aksen memiliki "ID sort" yang spesifik, yang dapat Anda lihat dalam contoh berikut:

SELECT COLLATIONPROPERTY(N'SQL_Latin1_General_CP1_CI_AS', 'SortID'), -- 52
       COLLATIONPROPERTY(N'SQL_Latin1_General_CP1_CS_AS', 'SortID'), -- 51
       COLLATIONPROPERTY(N'Latin1_General_100_CI_AS',     'SortID'); --  0

Satu-satunya perbedaan antara dua pemeriksaan pertama adalah sensitivitas huruf. Susunan ketiga adalah susunan Windows dan karenanya tidak memiliki tabel pemetaan statis.

Juga, susunan ini harus mengurutkan dan membandingkan lebih cepat daripada susunan Windows karena pencarian sederhana untuk karakter untuk mengurutkan berat. Namun, susunan ini juga jauh kurang fungsional dan harus dihindari jika memungkinkan.

Windows

Windows collations (yang namanya tidak dimulai dengan SQL_) adalah yang lebih baru (dimulai pada SQL Server 2000) cara menyortir / membandingkan. Dalam model Unicode yang lebih baru, kompleks, setiap kombinasi lokal, halaman kode, dan berbagai sensitivitas tidak diberikan pemetaan statis. Untuk satu hal, tidak ada halaman kode dalam model ini. Model ini memberikan nilai sortir default untuk setiap karakter, dan kemudian setiap lokal / budaya dapat menetapkan ulang nilai sortir ke sejumlah karakter. Ini memungkinkan banyak budaya untuk menggunakan karakter yang sama dengan cara yang berbeda. Ini memang memiliki pengaruh memungkinkan beberapa bahasa untuk diurutkan secara alami menggunakan susunan yang sama jika mereka tidak menggunakan karakter yang sama (dan jika salah satu dari mereka tidak perlu menetapkan ulang nilai apa pun dan cukup menggunakan default).

Nilai sortir dalam model ini bukan nilai tunggal. Mereka adalah array nilai yang menetapkan bobot relatif ke huruf dasar, diakritik apa pun (yaitu aksen), casing, dll. Jika collation-case-sensitive, maka bagian "case" dari array itu digunakan, jika tidak maka diabaikan ( karenanya, tidak sensitif). Jika collation peka terhadap aksen, maka bagian "diakritik" dari array digunakan, jika tidak maka diabaikan (karenanya, tidak sensitif).

Perbandingan dalam model ini adalah operasi multi-pass:

  1. Pertama, string dinormalisasi sehingga berbagai cara untuk mewakili karakter yang sama akan menyamakan. Misalnya, " ü " dapat berupa satu karakter / titik kode (U + 00FC). Anda juga bisa menggabungkan non-beraksen " u " (U + 0075) dengan Diaresis Menggabungkan " ̈ " (U + 0308) untuk mendapatkan: " ü ", yang tidak hanya terlihat sama ketika diberikan (kecuali ada masalah dengan font Anda), tetapi juga dianggap sama dengan versi karakter tunggal (U + 00FC), kecuali jika menggunakan binary collation (yang membandingkan byte dan bukan karakter). Normalisasi memecah karakter tunggal menjadi berbagai bagian, yang mencakup ekspansi untuk karakter seperti "  Æ  " (seperti yang disebutkan di atas untuk kumpulan SQL Server).
  2. Operasi perbandingan dalam model ini berjalan karakter demi karakter per setiap sensitivitas . Sortir kunci untuk string ditentukan dengan menerapkan elemen yang sesuai dari setiap karakter susunan nilai array berdasarkan sensitivitas yang "sensitif". Nilai-nilai kunci sortir diatur oleh semua sensitivitas primer dari masing-masing karakter (karakter dasar), diikuti oleh semua sensitivitas sekunder (bobot diakritik), diikuti oleh berat case masing-masing karakter, dan seterusnya.
  3. Penyortiran dilakukan berdasarkan kunci penyortiran yang dihitung. Dengan masing-masing sensitivitas dikelompokkan bersama, Anda bisa mendapatkan urutan pengurutan yang berbeda dari yang Anda lakukan dengan susunan SQL Server yang setara saat membandingkan string beberapa karakter, dan aksen terlibat, dan susunan itu peka-aksen (dan bahkan lebih lagi jika susunannya adalah juga case-sensitive).

Untuk detail lebih lanjut tentang penyortiran ini, saya akhirnya akan menerbitkan posting yang menunjukkan nilai-nilai kunci semacam itu, bagaimana mereka dihitung, perbedaan antara SQL Server dan Windows collations, dll. Tetapi untuk sekarang, silakan lihat jawaban saya untuk: Accent Sensitive Sort ( harap dicatat bahwa jawaban lain untuk pertanyaan itu adalah penjelasan yang baik tentang algoritma Unicode resmi, tetapi SQL Server malah menggunakan algoritma kustom, meskipun serupa, dan bahkan tabel bobot kustom).

Semua sensitivitas dapat disesuaikan dalam susunan ini: "huruf", "aksen", "lebar", "tipe kana", dan "pemilih variasi" (mulai pada SQL Server 2017, dan hanya untuk koleksi Jepang). Juga, beberapa kumpulan ini (ketika digunakan dengan data Unicode) mendukung Karakter Tambahan (dimulai pada SQL Server 2012). Pendekatan ini berlaku untuk data NVARCHAR dan VARCHAR data (bahkan data non-Unicode). Ini berlaku untuk VARCHARdata non-Unicode dengan terlebih dahulu mengkonversi nilai ke Unicode secara internal, dan kemudian menerapkan aturan sortir / perbandingan.


Tolong dicatat:

  1. Tidak ada susunan standar universal untuk SQL Server. Ada default instalasi yang berbeda berdasarkan pengaturan lokal / bahasa OS saat ini pada saat instalasi (yang sayangnya SQL_Latin1_General_CP1_CI_ASuntuk sistem bahasa Inggris AS, jadi silakan pilih saran ini ). Ini dapat diubah selama instalasi. Susunan tingkat instance ini kemudian menetapkan susunan untuk [model]DB yang merupakan templat yang digunakan saat membuat DB baru, tetapi susunan tersebut dapat diubah saat mengeksekusi CREATE DATABASEdengan menentukan COLLATEklausa. Kumpulan tingkat database ini digunakan untuk variabel dan string literal, serta default untuk kolom baru (dan diubah!) Ketika COLLATEklausa tidak ditentukan (yang merupakan kasus untuk kode contoh dalam pertanyaan).
  2. Untuk info lebih lanjut tentang Collations / encode / Unicode, silakan kunjungi: Collations Info
Solomon Rutzky
sumber
5

Biasanya ini diimplementasikan menggunakan tabel collation yang menetapkan skor tertentu untuk setiap karakter. Rutin penyortiran memiliki pembanding yang menggunakan tabel yang sesuai, baik default atau ditentukan secara eksplisit, untuk membandingkan string, karakter dengan karakter, menggunakan skor kolasi mereka. Jika, misalnya, tabel susunan tertentu memberikan skor 1 ke "a" dan 201 ke "A", dan skor yang lebih rendah dalam implementasi khusus ini berarti diutamakan lebih tinggi, maka "a" akan disortir sebelum "A". Tabel lain mungkin menetapkan skor terbalik: 201 ke "a" dan 1 ke "A", dan urutannya akan terbalik. Namun tabel lain mungkin menetapkan skor yang sama untuk "a", "A", "Á", dan "Å", yang akan mengarah pada perbandingan dan penyortiran case-and-accentitive.

Demikian pula, komparator berbasis tabel susunan seperti itu digunakan ketika membandingkan kunci indeks dengan nilai yang diberikan dalam predikat.

mustaccio
sumber
1
Just FYI: info ini hanya benar dalam hal menggunakan collations SQL Server (yaitu yang dengan nama diawali SQL_) ketika digunakan pada VARCHARdata. Ini tidak sepenuhnya benar untuk NVARCHARdata atau VARCHARdata saat menggunakan Windows collation (nama tidak dimulai dengan SQL_).
Solomon Rutzky