【问题标题】:How can I get a "traditional" single row result from a key-value oriented table layout如何从面向键值的表布局中获得“传统”单行结果
【发布时间】:2011-04-07 10:39:12
【问题描述】:

我有一个被设计成键值表的表,比如

ID | key | value
1  | abc | value 1
2  | def | value 2
3  | geh | value 3

这对我们处理数据有各种好处。唯一的缺点是,我不能在这样的键值表上轻松排序。 以传统方式获得所有键/值“展平”的结果集的智能/常用方法是什么,键显示为字段:

abc     | def     | geh
value 1 | value 2 | value 3

【问题讨论】:

标签: mysql select join key-value


【解决方案1】:

您只能使用存储过程来做到这一点,而且您不会在性能方面赢得太多。

要充分利用它,您可以在 key-kvalue 表上创建一个索引:

CREATE UNIQUE INDEX myindex ON keyvaluetable(key)

我假设您在 key 字段中有 UNIQUE 值。如果没有,您当然可以删除该部分。

【讨论】:

    【解决方案2】:

    您过度规范化,但您的示例不完整。如果您正在查看原始示例并尝试再添加一行,您会发现从表中不清楚值属于哪一行。您需要添加一个项目列:

    root@localhost [kris]> create table overnormal ( id serial, k varchar(20) not null, v varchar(20) not null);
    Query OK, 0 rows affected (0.96 sec)
    
    root@localhost [kris]> insert into overnormal values ( 1, 'abc', 'value 1'), (2, 'def', 'value 2'), (3, 'geh', 'value 3');
    Query OK, 3 rows affected (0.01 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    root@localhost [kris]> select * from overnormal;
    +----+-----+---------+
    | id | k   | v       |
    +----+-----+---------+
    |  1 | abc | value 1 |
    |  2 | def | value 2 |
    |  3 | geh | value 3 |
    +----+-----+---------+
    3 rows in set (0.00 sec)
    

    让我们添加项目列:

    root@localhost [kris]> alter table overnormal add column item integer unsigned not null;
    Query OK, 3 rows affected (0.48 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    root@localhost [kris]> update overnormal set item = 1;
    Query OK, 3 rows affected (0.01 sec)
    Rows matched: 3  Changed: 3  Warnings: 0
    
    root@localhost [kris]> insert into overnormal values (4, 'abc', 'item 1/1', 2), (5, 'def', 'item 1/2', 2), (6, 'geh', 'item 1/3', 2);
    Query OK, 3 rows affected (0.00 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    root@localhost [kris]> select * from overnormal;
    +----+-----+----------+------+
    | id | k   | v        | item |
    +----+-----+----------+------+
    |  1 | abc | value 1  |    1 |
    |  2 | def | value 2  |    1 |
    |  3 | geh | value 3  |    1 |
    |  4 | abc | item 1/1 |    2 |
    |  5 | def | item 1/2 |    2 |
    |  6 | geh | item 1/3 |    2 |
    +----+-----+----------+------+
    6 rows in set (0.00 sec)
    

    您可以使用死亡连接将其转换为传统表格:

    root@localhost [kris]> select t1.item, t1.v as abc, t2.v as def, t3.v as geh 
        from overnormal as t1 
        join overnormal as t2 
            on t1.item = t2.item 
           and t1.k = 'abc' 
           and t2.k = 'def' 
        join overnormal as t3 
            on t1.item = t3.item 
           and t3.k = 'geh';
    +------+----------+----------+----------+
    | item | abc      | def      | geh      |
    +------+----------+----------+----------+
    |    1 | value 1  | value 2  | value 3  |
    |    2 | item 1/1 | item 1/2 | item 1/3 |
    +------+----------+----------+----------+
    2 rows in set (0.00 sec)
    

    您可以通过添加ORDER BY 子句以通常的方式对其进行排序。

    这个查询并没有那么糟糕,但随着表变宽,即使有索引,效率也会迅速下降,因为优化器会在单个连接中处理 9 到 10 个表时感到困惑。

    您最好使用更接近第三范式且不太接近 DKNF 的数据模型,是的,这是可能的,而且问题比您想象的要小。无论如何,如果不对您的应用程序中合法和必需的 k 值进行假设,您就无法处理完全任意的数据类型(或者,如果您没有做出这样的假设,您不妨序列化您的应用内结构并存储斑点)。

    【讨论】:

    • 感谢您帮助我完成这个复杂的 JOIN!现在我真的不得不退后一步,考虑改变这个表格布局......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 2016-02-25
    • 2016-06-09
    相关资源
    最近更新 更多