数据库表中的键/值对

时间:2009-02-05 04:42:19

标签: sql sql-server tsql entity-attribute-value

我需要在我的数据库中设计一个Key / value表,我正在寻找最佳方法的指导。基本上,我需要能够将值与一组动态命名属性相关联,并将它们应用于外部键。

我需要支持的操作是:

  • 将键/值对应用于一组项目
  • 枚举所有当前活动的密钥
  • 确定具有给定键值的所有项目
  • 确定与给定键关联的值与某些条件匹配的所有项目。

似乎最简单的方法是定义一个表:

CREATE TABLE KeyValue (
  id    int,
  Key   varchar...,
  Value varchar...
);

似乎我可能会在Key列中复制大量数据,因为我可能会为大量文档定义任何给定的键。用一个整数查找替换Key varchar到另一个表似乎缓解了这个问题(并且使枚举所有活动密钥的效率明显提高),但是我仍然坚持维护查找表的问题(每当我想要它时都会查找它定义属性并在键/值被清除时可能删除条目。

最好的方法是什么?

6 个答案:

答案 0 :(得分:29)

您正在使用名为Entity-Attribute-Value的数据库模型。这是在关系数据库中存储键/值对的常用方法,但它在数据库规范化和效率方面存在许多缺点。

是的,您展示的表格设计是最常用的方式。在此设计中,每个实体的每个属性都会在KeyValue表中获得一个不同的行。

将一个键/值对应用于一组项目:您需要为该组中的每个项目添加一行。

INSERT INTO KeyValue (id, key, value) VALUES (101, 'color', 'green');
INSERT INTO KeyValue (id, key, value) VALUES (102, 'color', 'green');
INSERT INTO KeyValue (id, key, value) VALUES (103, 'color', 'green');

您也可以使用参数准备INSERT语句,并在循环中运行多个项目ID,或者其他任何内容。

枚举所有当前有效的键:

SELECT DISTINCT Key FROM KeyValue;

确定具有给定键值的所有项目:

SELECT id FROM KeyValue WHERE Key = 'color';

确定与给定键相关联的值与某些条件匹配的所有项目:

SELECT id FROM KeyValue WHERE Value = 'green';

实体 - 属性 - 值的一些问题是:

  • 无法确保所有项目的键拼写相同
  • 无法为所有项目强制使用某些键(即传统表格设计中的NOT NULL)。
  • 所有密钥必须使用VARCHAR作为值;不能为每个密钥存储不同的数据类型。
  • 无法使用参照完整性;不能制作适用于某些键值而不适用其他键的FOREIGN KEY。

基本上,Entity-Attribute-Value不是规范化的数据库设计。

答案 1 :(得分:5)

除非必须,否则不要对此进行优化。密钥的平均长度是多少?如果你以天真的方式实现它,那么这个表是否会如此之大以至于它们都不适合你服务器的内存?我建议以最简单的方式实现它,测量性能,然后仅在性能出现问题时重新实现。

如果性能有问题,那么使用整数键和单独的表可能是要走的路(整数列上的JOINS通常比使用可变长度字符串列的JOINS更快)。但优化的第一条规则是MEASURE FIRST--确保您所谓的优化代码确实能让事情变得更快。

答案 2 :(得分:1)

可能值得探索的选项是在将密钥插入表之前使用SHA1或MD5消化密钥。

这将允许你摆脱查找表,但你将无法遍历键,因为它只是单向的。

答案 3 :(得分:1)

创建updatable views!。另外check这是一个例子。

答案 4 :(得分:1)

在我看来,你可能会有一些设计选择。

选择1:你在答案中暗示的两桌设计

Keys (
 id int not null auto_increment
 key string/int
)
values (
 id int not null auto_increment
 key_id int
 value string/varchar/int
)

选择2:也许正如sambo99指出你可以修改它:

keys (
 id int not null auto_increment
 key string/int
 hash_code int -- this would be computed by the inserting code, so that lookups would effectively have the id, and you can look them up directly
)

values (
 id int not null auto_increment -- this column might be nice since your hash_codes might colide, and this will make deletes/updates easier
 key_id int -- this column becomes optional
 hash_code int
 value string/varchar/int...
)

-

答案 5 :(得分:0)

键值对通常不能很好地利用关系数据库。关系数据库的好处是与之相关的约束,验证和结构。通过在表中使用通用键值结构,您将失去使关系数据库变得良好的验证和约束。如果您想要灵活设计键值对,最好是使用像MongoDB或其类似的NoSQL数据库。

当基础数据非结构化,不可预测或经常更改时,键值对(例如NoSQL数据库)效果最佳。如果您没有结构化数据,那么关系数据库将比其价值更加麻烦,因为您需要进行大量的架构更改和/或跳过箍以使您的数据符合不断变化的结构。

KVP / JSON / NoSql很棒,因为对数据结构的更改不需要完全重构数据模型。向数据对象添加字段只需将其添加到数据中即可。硬币的另一面是KVP / Nosql数据库中的约束和验证检查比关系数据库更少,因此您的数据可能会变得混乱。

关系数据模型可以节省性能和空间。规范化的关系数据可以更容易理解和验证数据,因为有表关键关系和约束来帮助您。这将使您的应用程序更容易维护和长期支持。另一种方法是在代码中使用数据抽象层,如Django或SQL Alchemy for Python,Entity Framework for .NET。这样,当您的代码更改数据库时,它将自动更改。

我见过的最糟糕的模式之一是尝试两种方式。尝试将键值对放入关系数据库通常会导致灾难。我建议使用最适合您数据的技术。