pau*_*l23 15 postgresql normalization
过去,我被告知(在这个站点上)我应该规范化数据库中的值 - 使用查找表而不是使用直接(字符串)键。
我很困惑为什么这很好,以至于有几个人推荐了这个。仅仅是为了内存消耗吗?但是在我的情况下(如下所述)那是多少?
考虑我有一个网站的字典数据库:
CREATE TABLE dictionary
(
id serial NOT NULL,
key text NOT NULL,
language text NOT NULL,
value text,
PRIMARY KEY (id)
)
Run Code Online (Sandbox Code Playgroud)
然后插入会发生如下:
INSERT INTO public.dictionary VALUES
('yes_button', 'en', 'yes'), ('yes_button', 'nl', 'ja')
Run Code Online (Sandbox Code Playgroud)
或者,我会使用“en-us”来代替“en”。现在我被告知要“规范化”数据库——这意味着有一个查找表来绑定语言的字符串表示('en'、'nl' 到一个值):
CREATE TABLE languages
(
id serial NOT NULL,
language text
)
CREATE TABLE dictionary
(
id serial NOT NULL,
key text NOT NULL,
language integer NOT NULL,
value text,
PRIMARY KEY (id),
FOREIGN KEY (language)
REFERENCES public.languages (id)
)
Run Code Online (Sandbox Code Playgroud)
然而,这会增加相当多的复杂性,因为插入不再简单——它需要检查后端的外部表,或者使用一些更复杂的 SQL。因此,更新此设计需要付出实际成本。
有哪些优势?
它只是存储大小吗?无论如何,整数外键引用是 4 个字节,大小为 2 的字符串为 3 个字节(而大小为 5 的字符串为 6 个字节 - 所以最多节省 2 个字节)。
是数据库的速度吗?但这不就是微优化,是“万恶之源”吗?
是否只是为了在插入之前确保每种语言“存在”?还有其他机制,无论如何都应该即时创建语言。存在不是基于我们数据库中的内容,而是对标准的外部查找,一旦用户提供单个翻译,就会正确添加语言。
在我之前的问题改进数据库设计的评论中提到了这个想法的例子,这是实体属性值的有效案例吗?:
语言应该是一个 int 并引用一个单独的表(规范化你的表)——nbk Jan 13 at 16:54
@nbk 有趣 -> 为什么?ISO 国家/地区 + 语言代码已经是唯一的,因此字符串也可以成为关键,对吗?当文本描述是唯一性的有力保证时,为什么我要使用额外的整数重定向?– paul23 1 月 13 日 17:58
@paul23 像在我的描述或答案中一样的规范化表有助于减少查询的大小和速度,假设您有 255 种语言,并且您保存了一个可大幅减少大小的 int。规范化数据设计有助于避免表中存在冗余数据 – nbk Jan 13 at 18:20
字典数据库实际上与数据数据库是分开的,因为它被多个应用程序使用。
如果我通过规范化表使用字符串键,则 'en-us'、'nl-nl'... 本身很可能是完美的键。它们本身是独一无二的,那么我为什么要使用uuid或其他随机字符串?换句话说,'en-us' 不仅仅是一个字符串,它是由 ISO 639 标准专门确定为语言环境字符串的。因此,字符串的数量非常有限。它非常用作“标识符”,就像“pi”是用于 3.1415...
关于数据质量,我不必使用整数键——我可以使用字符串——但是字符串 'en-us' 是代表“美国英语”语言环境的正确字符串。
Joe*_*own 34
您的问题是您将两条不同的建议合并为一条,并且没有清楚地提出每条建议的理由。
建议 1:规范化您的数据库
在任何事务数据库中,这通常被认为是最佳实践。有很多原因可能会让您放弃这一点,而且有些应用程序(如 BI 数据仓库)不一定是您想要的。但是,对于事务性数据库,根据经验,您可以在必要时开始规范化和非规范化。
似乎有些混乱的地方是为什么要规范化。在这种混乱中,您并不孤单。很多人对规范化数据库的目的有很多误解。
规范化不是(主要)关于:
规范化是关于:
规范化您的数据库设计意味着您不会在多个位置存储一段数据,因此如果您出于任何原因需要更新或删除它,您可能会遇到麻烦,因为数据需要在多个位置更改。当您不规范化时,您的数据很可能会随着时间的推移变得不一致,因为更改不一致。 这有点过于简化,因为规范化还有其他好处,例如简化的查询逻辑。然而,数据质量是迄今为止最重要的好处,具有讽刺意味的是,未经正规数据库设计培训的程序员往往无法清楚地理解这一点。
建议 2:使用整数代理键
这比其他任何事情都更属于共同习惯的范畴。许多人喜欢在他们所有的关系数据库表中使用无意义的整数主键。这本身实际上是两条建议:(i) 在每个表中使用代理键和 (ii) 使用整数作为代理键。
不同的人会给出不同的理由来说明他们考虑这些最佳实践的原因,所有这些理由都可以根据具体情况进行辩论。我能想到的使用代理键的最佳论点是自然键更有可能被更改。更改任何主键都是一个巨大的痛苦,因此最好尽可能避免。我能想到的为代理键使用整数的最佳论点是,它是一种简洁高效的不错的简单数据类型。同样,这是高度情境化的,因此人们会在不同的情况下对此提出支持或反对意见。
我对建议 2 的总体看法是:选择一条通道并坚持下去,以便您的代码相对一致,并且仅当您有一个非常引人注目的关键性能或关键效率案例并且您可以清楚地证明这种分歧时才与此不同从你通常的方法来看有很大的好处。
一般来说,我避免使用自然键,但有时你可以逃避它,甚至有时使用它们更有意义。您需要用自然键问自己的问题是“这种情况将来会改变吗?”
我的经验法则是“如果用户可以看到它,他们总有一天会想要改变它”。但是,在您的特定情况下,语言代码是由国际标准机构设置的,因此它们可能更改的可能性非常小——这太痛苦了。在您的情况下,我会毫不犹豫地使用“en-us”作为键值。