11

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

我需要能够支持的操作是:

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

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

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

看来我可能会在 Key 列中复制大量数据,因为我可能会为大量文档定义任何给定的键。用整数查找替换 Key varchar 到另一个表中似乎可以缓解这个问题(并使枚举所有活动键的效率显着提高),但让我遇到了维护该查找表的问题(只要我想就插入它)定义一个属性并可能在任何时候清除键/值时删除条目)。

最好的方法是什么?

4

6 回答 6

30

您正在使用一个名为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';

Entity-Attribute-Value 的一些问题是:

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

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

于 2009-02-08T03:17:33.920 回答
6

除非必须,否则不要优化它。密钥的平均长度是多少?如果您以幼稚的方式实现它,这张表会不会太大而无法全部放入服务器的内存中?我建议以最简单的方式实现它,衡量性能,然后仅在性能出现问题时重新实现。

如果性能是一个问题,那么使用整数键和单独的表可能是可行的方法(整数列上的 JOINS 通常比使用可变长度字符串列的 JOINS 快)。但是优化的第一条规则是测量优先——确保你所谓的优化代码确实让事情运行得更快。

于 2009-02-06T19:20:13.417 回答
2

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

这将允许您摆脱查找表,但您将无法遍历键,因为它只有一种方式。

于 2009-02-05T04:50:03.550 回答
1

创建可更新的视图!. 另请查看此示例。

于 2009-02-05T04:51:28.773 回答
1

It seems to me like you might have a couple design choices.

Choice 1: A two table design you hinted at in your answer

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

Choice 2: perhaps as sambo99 pointed out you could modify this:

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

--

于 2009-02-05T05:13:44.533 回答
0

键值对一般不是关系数据库的好用处。关系数据库的好处是随之而来的约束、验证和结构。通过在表中使用通用键值结构,您将失去使关系数据库良好的验证和约束。如果您想要灵活地设计键值对,最好使用像 MongoDB 或类似的 NoSQL 数据库。

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

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

关系数据模型具有性能和节省空间的优势。规范化的关系数据可以更容易地理解和验证数据,因为有表键关系和约束可以帮助您。从长远来看,这将使您的应用程序更易于维护和支持。另一种方法是在代码中使用数据抽象层,例如用于 Python 的 Django 或 SQL Alchemy,用于 .NET 的实体框架。这样,当您的代码更改时,您的数据库将自动随之更改。

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

于 2018-04-09T20:39:46.550 回答