具有少量不同值的文本列是否有异味?

时间:2015-09-02 22:22:42

标签: sql sqlite optimization database-design

例如,我们说我有一张这样的表:

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
);

对于包含少量不同值的文本列,这仍然是一个很好的做法,但它不会被限制为一些永远不会改变的值集合?例如如果我有一个出生国的专栏。

1 个答案:

答案 0 :(得分: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数据类型 - 使用任何类型已经是您的偏好。)