【问题标题】:Is a text column with a small number of distinct values a bad smell?具有少量不同值的文本列是难闻的气味吗?
【发布时间】:2015-09-05 01:25:22
【问题描述】:

例如,假设我有一个这样的表:

CREATE TABLE people (
    firstname TEXT,
    lastname TEXT,
    weight FLOAT,
    zodiac_sign TEXT    
);

前三列将有许多不同的值,随着我添加更多行,它们的数量将无限增长。但zodiac_sign 始终是 12 个值之一。

我假设 SQLite 将为 'sagittarius' 的每个实例使用 11 个字节(即它不够聪明地推断 zodiac_sign 基本上是一个可以存储在单个字节中的枚举)。

这是否表明,如果我要处理的行数不小,我应该像这样拆分另一个表:

CREATE TABLE people (
    firstname TEXT,
    lastname TEXT,
    weight FLOAT,
    zodiac_id INTEGER NOT NULL REFERENCES zodiac_signs(zodiac_id)
);

CREATE TABLE zodiac_signs (
    zodiac_id INTEGER PRIMARY KEY,
    name TEXT
);

对于包含少量不同值但不受某些永远不会改变的值集的文本列来说,这仍然是一个好习惯吗?例如如果我有一个出生国家的列。

【问题讨论】:

标签: sql sqlite optimization database-design


【解决方案1】:

在第一个表设计中,字段zodiac_sign 也可以重命名为enter_anything_you_want。良好的数据完整性实践要求每个字段的域只要有意义就受到约束。例如,对于一般用途,birthdate 字段可能被限制为仅在过去,从不在未来。对于 DMV 数据库,同一字段可能被限制为过去至少 16 年。

当字段是具有固定数量的有效替代项的文本时,您可以使用检查约束对其进行定义:

zodiac_sign text (check zodiac_sign in( 'Leo', 'Cancer', ... )),

(我给出的示例可能不会直接转化为 SQLite 代码。但我想对此进行更一般的讨论。)

但是,这有点尴尬,并且必须在包含该字段的每个表中重复。这意味着如果列表发生变化,可能需要大量 alter table 命令来更新新列表。虽然很明显,十二生肖不太可能发生变化,但这通常不是此类领域的可靠方面。

实现文本值的查找表,为它们提供外键引用的键值是一种更好的方法。它像检查约束一样限制有效值,但所有值都在一个位置,因此更改是本地化的。此外,还可以添加其他字段。

create table Zodiac(
    ID        integer not null,
    Name      text    not null,
    StartDate date,
    EndDate   date,
    constraint PK_Zodiac primary key( ID )
);

日期将使计算与给定日期关联的符号变得更加容易。 (是的,Sqlite 没有原生的 Date 数据类型——使用你喜欢的任何类型。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-20
    • 2012-03-16
    • 1970-01-01
    • 1970-01-01
    • 2012-09-12
    • 1970-01-01
    • 2011-01-27
    • 2018-09-01
    相关资源
    最近更新 更多