Basis data di belakang Antarmuka Pengguna Multilingual

8

Pertanyaan ini adalah tentang masalah yang agak lebih rumit daripada yang telah dibahas dalam pertanyaan-pertanyaan lama ini, yang semuanya merupakan duplikat satu sama lain:

Saran untuk struktur database untuk multilanguage (2011 Jun)

Apa struktur basis data terbaik untuk menyimpan data multibahasa? (2010 Feb)

Apa praktik terbaik untuk desain basis data multi-bahasa? (2009 Mei)

Skema untuk basis data multi bahasa (2008 November)


Skema basis data yang paling populer untuk mendukung antarmuka pengguna multibahasa tampaknya memiliki semua teks yang diterjemahkan dari semua bahasa dalam satu tabel dengan 3 kolom: id teks, kode bahasa, dan teks itu sendiri. Id teks dan kode bahasa bersama-sama membentuk kunci utama.

Semuanya baik-baik saja, tetapi sekarang pertimbangkan komplikasi: anggaplah bahwa teks-teks tersebut perlu dicari. Misalkan, misalnya, ini adalah e-shop multi-bahasa. Ini berarti bahwa untuk setiap kategori produk yang dimasukkan ke dalam basis data, pemilik toko akan memasukkan nama kategori produk di setiap bahasa N yang didukung, dan kemudian pembelanja akan dapat mencari kategori produk dengan nama, dalam bahasa mereka sendiri .

Ada masalah: Collation .

Bahasa yang berbeda memiliki urutan susunan yang berbeda, dan urutan susunan yang berfungsi untuk satu bahasa tidak berfungsi untuk yang lain. Jadi jika semua teks dari semua bahasa berada pada satu kolom, urutan kolasi apa yang akan mereka miliki? Bagaimana kita akan meminta database untuk menemukan id teks dari teks tertentu? Sementara dalam sebuah produk web, akurasi dan kinerja pencarian mungkin tidak terlalu penting, untuk keperluan diskusi ini, mari kita asumsikan bahwa itu benar-benar penting.

Sebagian besar administrator basis data akrab dengan konsep collation dalam arti "collation of the database". Untungnya, itu hanya susunan standar, yang digunakan jika tidak ada informasi susunan lainnya, tetapi ada tempat lain juga, tempat susunan dapat ditentukan:

  • Perintah SQL CREATE INDEX mendukung spesifikasi pemeriksaan. (Meskipun rumor mengatakan bahwa Microsoft SQL Server tidak mendukungnya; apakah ada yang tahu tentang itu?)

  • Pernyataan SQL SELECT juga mendukung collation, tetapi dalam hal ini spesifikasi collation berfungsi sebagai fungsi, yang menyebabkan pemindaian indeks alih-alih pencarian indeks, sesuatu yang mungkin tidak diizinkan jika kita menginginkan kinerja. (Kemudian lagi, jika itu yang terbaik yang bisa kita miliki, itu mungkin lebih baik daripada tidak sama sekali.)

  • Saya juga mendengar bahwa di Microsoft SQL Server Anda dapat memiliki kolom yang tidak bertahan, dihitung di mana Anda dapat menentukan susunan dan membuat indeks yang difilter, meskipun saya belum pernah mendengar ini sebelumnya, dan jika itu hanya Microsoft-SQL-Server-saja fitur, maka saya lebih suka menahan diri dari menggunakannya, tidak peduli seberapa keren dan dipikirkan dengan baik itu.

Jadi, mengingat semua itu, bagaimana kita menyusun basis data kita, dan bagaimana kita melakukan pertanyaan kita, jika tujuannya adalah basis data multibahasa yang dapat diperbarui dan dicari?


Pertanyaan ini terinspirasi oleh sebuah diskusi yang terjadi di sini: bagaimana nvarchar (max) akan menyimpan data dalam database akan lebih cepat jika beberapa data kurang dari 4000 karakter?

Mike Nakis
sumber
2
Jika fitur hanya produk Microsoft benar - benar keren dan dipikirkan dengan baik, seharusnya peluang yang adil untuk mendapatkan dukungan dalam produk serupa oleh vendor lain tepat waktu. Hanya pemikiran saja.

Jawaban:

8

Hal ini dimungkinkan untuk menyimpan string dengan Collations berbeda pada kolom yang sama menggunakan sql_variant :

CREATE TABLE dbo.Localized
(
    text_id     INTEGER NOT NULL,
    lang_id     INTEGER NOT NULL,
    text_body   SQL_VARIANT NOT NULL,

    CONSTRAINT [PK dbo.Localized text_id, lang_id]
        PRIMARY KEY CLUSTERED (text_id, lang_id),
)
GO
INSERT dbo.Localized
    (text_id, lang_id, text_body)
VALUES
    (1001, 2057, N'Database problems' COLLATE Latin1_General_CI_AS);
GO
INSERT dbo.Localized
    (text_id, lang_id, text_body)
VALUES
    (1001, 1025, N'قاعدة بيانات المشاكل' COLLATE Arabic_CI_AS)

Desain ini memiliki beberapa kelemahan (termasuk dibatasi hingga 8000 byte), paling tidak di area pencarian: SQL_VARIANTtidak dapat diindeks teks lengkap, dan beberapa fitur perbandingan string (misalnya LIKE) tidak dapat digunakan secara langsung juga. Di sisi lain, adalah mungkin untuk membuat indeks biasa pada SQL_VARIANTdan melakukan perbandingan yang lebih mendasar (misalnya <, =,>) dalam mode pemeriksaan-sadar:

CREATE UNIQUE INDEX uq1 ON dbo.Localized (text_body)
GO
-- One row
SELECT
    l.*
FROM dbo.Localized AS l 
WHERE
    l.text_body = CONVERT(SQL_VARIANT, N'Database problems' COLLATE Latin1_General_CI_AS)

-- No rows (and no collation error!)
SELECT
    l.*
FROM dbo.Localized AS l
WHERE
    l.text_body = CONVERT(SQL_VARIANT, N'Database problems' COLLATE Arabic_CI_AS)

-- One row, index seek, manual version of "LIKE 'D%'"
SELECT
    l.*
FROM dbo.Localized AS l 
WHERE
    l.text_body >= CONVERT(SQL_VARIANT, N'D' COLLATE Latin1_General_CI_AS)
    AND l.text_body < CONVERT(SQL_VARIANT, N'E' COLLATE Latin1_General_CI_AS)

Kami juga dapat menulis prosedur yang biasa:

CREATE PROCEDURE dbo.GetLocalizedString
    @text_id    INTEGER,
    @lang_id    INTEGER,
    @text_body  SQL_VARIANT OUTPUT
AS
BEGIN
    SELECT
        @text_body = l.text_body
    FROM dbo.Localized AS l
    WHERE
        l.text_id = @text_id
        AND l.lang_id = @lang_id
END
GO
DECLARE @text SQL_VARIANT

EXECUTE dbo.GetLocalizedString
    @text_id = 1001,
    @lang_id = 1025,
    @text_body = @text OUTPUT

SELECT @text

Tentu saja, pengindeksan teks lengkap juga bermasalah dalam desain "tabel tunggal untuk semua terjemahan", karena pengindeksan teks lengkap (semuanya kecuali) memerlukan pengaturan id bahasa per kolom . Desain beberapa tabel yang dijelaskan oleh Joop Eggen dapat diindeks teks lengkap (meskipun secara alami akan membutuhkan satu indeks per tabel).

Opsi utama lainnya adalah memiliki satu kolom per lokal di tabel dasar:

CREATE TABLE dbo.Example
(
    text_id     INTEGER NOT NULL,
    text_2057   NVARCHAR(MAX) COLLATE Latin1_General_CI_AS NULL,
    text_1025   NVARCHAR(MAX) COLLATE Arabic_CI_AS NULL,

    CONSTRAINT [PK dbo.Example text_id]
        PRIMARY KEY CLUSTERED (text_id)
)

Pengaturan ini memang memiliki kesederhanaan tertentu, dan berfungsi dengan baik dengan pengindeksan teks lengkap, meskipun memang membutuhkan kolom baru untuk ditambahkan dengan setiap bahasa baru, dan banyak pengembang menemukan struktur semacam ini tidak bagus dan tidak memuaskan untuk dikerjakan.

Masing-masing alternatif memiliki kelebihan dan kekurangan, dan akan membutuhkan tipuan pada tingkat tertentu, sehingga mungkin tergantung pada di mana pengembang yang bersangkutan merasa paling bahagia menemukan tipuan itu. Saya membayangkan kebanyakan orang akan lebih suka desain multi-tabel untuk sebagian besar tujuan.

Paul White 9
sumber
Saya mungkin menggunakan tabel terpisah daripada kolom terpisah untuk tata letak fisik yang lebih baik: itu adalah jawaban saya yang mengatakan bahwa yang mengilhami pertanyaan ini dba.stackexchange.com/a/9954/630
gbn
5

Jelas Anda menginginkan tabel per bahasa: xxx_en , xxx_fr , xxx_eo . Itu akan lebih optimal dan memungkinkan pengumpulan bergantung pada bahasa. Bahkan dapat dibayangkan bahwa Anda memiliki basis data per bahasa [en] [xxx] , [fr] [xxx] , [eo] [xxx] .

Rincian teknis kemudian menjadi hal yang sangat penting (baik seseorang dapat atau tidak dapat mengoptimalkan lebih banyak).

Tombol teks yang sebenarnya pergi pada tabel xxx .

Joop Eggen
sumber
2
Masalahnya adalah ini sangat tidak relasional.
Mike Nakis
Ya, pengalaman saya adalah, bahwa pencarian teks, apakah db didukung atau dilakukan sendiri, sulit untuk diintegrasikan secara relasional. Terima kasih sudah memberikan poin.