【问题标题】:Key/Value pairs in a database table数据库表中的键/值对
【发布时间】:2009-02-05 04:42:19
【问题描述】:

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

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

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

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

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

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

最好的方法是什么?

【问题讨论】:

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


    【解决方案1】:

    您正在使用名为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 不是规范化的数据库设计。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • +1 简单。除非性能影响明显且严重,否则请始终使用最容易使用的方法,然后根据需要进行测试和优化。
      【解决方案3】:

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

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

      【讨论】:

      • 如果只取 SHA 的前四个字节,那么可以使用 int 作为密钥类型
      【解决方案4】:

      创建 updatable views! 。还有check这个例子。

      【讨论】:

        【解决方案5】:

        在我看来,您可能有几个设计选择。

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

        --

        【讨论】:

        • SHA1 碰撞的几率实际上几乎是 0,你需要超级邪恶才能引起碰撞,如果你非常担心你可以使用 SHA256
        • 我亲眼目睹了 DC++ 中的哈希冲突 (TTH),因此并非不可能。
        【解决方案6】:

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

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

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-09-12
          • 1970-01-01
          • 1970-01-01
          • 2021-09-07
          • 2012-03-09
          • 2014-09-29
          • 2018-07-24
          相关资源
          最近更新 更多