假設我在 postgres 中創建了一個表來存盤語言翻譯。假設我有一個像 EVENT 這樣的表,它有多個需要翻譯成其他語言的列。我不會在 EVENT 中為每種語言添加新列,而是在 LANGUAGE 中添加具有相同語言 ID 的新行。
事件:
| ID | EVENT_NAME(轉至 LANGUAGE.short) | EVENT_DESCRIPTION(轉至 LANGUAGE.long) |
|---|---|---|
| 0 | 1 | 2 |
語:
| 語言標識 | 語言型別 | 短(char 變化 200) | med(char 變化 50) | 長(char 變化 2000) |
|---|---|---|---|---|
| 1 | 英語 | 足球比賽 | 無效的 | 無效的 |
| 1 | 西班牙語 | 足球黨 | 無效的 | 無效的 |
| 2 | 英語 | 無效的 | 無效的 | 一場非常棒的足球比賽 |
| 2 | 西班牙語 | 無效的 | 無效的 | 足球大黨 |
如果我想要特定語言的版本,我將創建一個引數化陳述句并像這樣傳遞語言:
select event.id, name.short, desc.long
from event e, language name, language desc
where e.id = 0
and e.event_name = name.language_id
and name.language_type = ?
and e.event_desc = desc.language_id
and desc.language_type = ?
我的第一個想法是只為翻譯文本設定一列,但我必須使其足夠大以容納任何翻譯。當許多記錄只有 50 個字符時設定為 2000 似乎是錯誤的。因此,我想也許可以添加不同大小的不同列,并為 Im 存盤的資料使用適當的大小(前端的事件名稱可以限制為 50 個字符,而 desc 可以限制為 2000 個字符)。
在語言表中,每行僅設定 3 列(短、中、長)中的一列。這只是我最初的想法,但試圖了解這是否是一種不好的方法。如果我只是設定短值,磁盤是否仍然保留 2250 個字符?我不久前讀到,如果您在 oracle 中執行此類操作,則必須為磁盤塊中的所有列保留空間,否則如果您更新記錄,則必須動態執行,這可能會很慢。Postgres是一樣的嗎?
看起來您可以在沒有精度的情況下指定字符變化型別。僅定義單個列而不指定大小或僅定義單個列并將大小指定為 2000 會更有效(空間方面)嗎?
uj5u.com熱心網友回復:
只需使用單列資料型別text。這將與character varying(n)PostgreSQL 中的 a 一樣好,因為實作完全相同,減去長度檢查。PostgreSQL 只存盤字串實際具有的字符數,因此text即使是短字串也沒有開銷。
用檔案的話來說:
這三種型別之間沒有性能差異,除了使用空白填充型別時增加了存盤空間,以及在存盤到長度受限的列時需要一些額外的 CPU 周期來檢查長度。
uj5u.com熱心網友回復:
使用text.
使用 Postgres,除非您真的需要對文本大小進行硬性限制(通常您不需要),否則請使用text.
我看到沒有 n 的 varchar 和 text 的帖子具有相同的性能,但可能比 varchar(n) 稍慢。
這對于 PostgreSQL 14 是不正確的。text是性能最高的。
這三種型別[char, varchar, text]之間沒有性能差異,只是在使用空白填充型別時會增加存盤空間 [ie. char],以及一些額外的 CPU 周期來檢查存盤到長度受限列時的長度 [即。varchar,字符]。
varchar和的存盤text是相同的。
短字串(最多 126 個位元組)的存盤要求是 1 個位元組加上實際字串,其中包括字符情況下的空格填充。較長的字串有 4 個位元組的開銷,而不是 1 個。長字串由系統自動壓縮,因此對磁盤的物理要求可能會更少。非常長的值也存盤在后臺表中,因此它們不會干擾對較短列值的快速訪問。
你需要重新發明這個輪子嗎?
國際化和本地化工具已經存在;它們內置于許多應用程式框架中。
大多數本地化系統的作業方式是使用以開發人員的首選語言(例如英語)撰寫的字串,然后根據需要對該字串進行本地化。然后它就變成了一個簡單的哈希查找。
與其在資料庫中進行本地化,不如查詢訊息,然后讓應用程式框架對其進行本地化。這更簡單、更快速、更易于使用,并且避免給資料庫增加額外的負載。
如果您確實必須在資料庫中執行此操作,請注意以下幾點:
language對您的表來說是一個令人困惑的名稱,可能是messagesortranslations或localizations.- 使用標準IETF 語言標簽,例如 en-US。
- 任何固定的文本集(例如語言標簽)都放入表中以實作參照完整性。
- 您可以使用
enum,但它們很難閱讀和更改。
- 您可以使用
- 考慮為每條訊息和一列設定一行,而不是短列、中列和長列
size。這避免了很多空列。- 事實上,根本沒有“大小”。這是任意和主觀的,正如您的空列所證明的那樣。
- 不要用表名作為列的前綴,根據需要完全限定它們。
- 將訊息與其本地化分開以實作參照完整性。
create table languages (
id serial primary key,
tag text unique not null
);
-- This table might seem a bit silly, but it allows tables to refer to
-- a single message and enforce referential integrity.
create table messages (
id bigserial primary key
);
create table message_localizations (
-- If a message or language is deleted, so will its localization.
message_id bigint not null references messages on delete cascade,
language_id int not null references languages on delete cascade,
localization text not null,
-- This serves as both a primary key and enforces one localization
-- per message and language.
primary key(message_id, language_id)
);
create table events (
id bigserial primary key,
name_id bigint not null references messages,
description_id bigint not null references messages
);
然后加入每條訊息及其本地化。
select
events.id,
ml1.localization as name,
ml2.localization as description
from events
-- left join so there is a result even if there is no localization. YMMV.
left join languages lt on lt.tag = 'en-US'
left join message_localizations ml1
on ml1.message_id = name_id and ml1.language_id = lt.id
left join message_localizations ml2
on ml2.message_id = description_id and ml2.language_id = lt.id
示范。
但是,同樣,您可能想要使用現有的本地化工具。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/492786.html
標籤:PostgreSQL
上一篇:根據另一列計數不同
下一篇:如何從當前和歷史創建臨時表?
