【问题标题】:How to properly query a normalized database如何正确查询规范化数据库
【发布时间】:2012-04-09 20:17:56
【问题描述】:

我正在重新设计一个 MySQL 数据库,其中包含一个包含大约 1,500 列的表以及其他表。我们希望通过创建第二个表来规范化该表中的数据,该表将为初始表中存在的每一列/行提供一条记录。我们称这些表为 Master 和 MasterData。 Master 将包含该表中所有记录所需的基本信息。 MasterData 将包含一些与主表中的记录有关的附加数据的值。所以假设 Master 看起来像这样:

MasterID     Property1     Property2
1            Yes           No
2            No            Yes
3            Yes           Yes
4            No            No

假设 MasterData 看起来像这样:

MasterID     Property     Value
1            Property3    Yes
1            Property4    No
3            Property3    No
4            Property7    Yes

到目前为止和我在一起?如何查询此数据,并且每个匹配的主行仅返回一行,但包含所有相关的 MasterData 信息。我已经搜索并找到了几个示例,但它们需要很长时间才能在我们的数据上执行。我根据前面提到的一个巨大表中的现有数据创建了一个测试 MasterData 表。这导致 MasterData 有大约 450 万条记录,并且以下查询仅需要太长时间才能执行和超时。

SELECT Property1, Property2, Master.MasterID,
    GROUP_CONCAT(case when Property = "Property3" then Value end) as Property3, 
    GROUP_CONCAT(case when Property = "Property7" then Value end) as Property7
FROM Master LEFT JOIN MasterData USING (MasterID) GROUP BY MasterID
HAVING Property3='Yes' OR Property7='Yes';

Select * FROM Master AS M, MasterData AS MD1, MasterData AS MD2 
WHERE M.MasterID=MD1.MasterID AND MD1.Property='Property3' AND MD1.Value='Yes' 
AND M.MasterID=MD2.MasterID AND MD2.VAR='Property7' AND MD2.Value='Yes';

同样,我们的目标是能够在一行中检索 MasterData 中的所有数据,就好像它是 Master 中的一列一样。这可能吗?

非常感谢任何帮助!

【问题讨论】:

  • 我更喜欢第二个查询而不是第一个查询(尽管不是使用隐式连接语法),尽管我不想像你正在做的那样使用 EAV 表(有很多固有问题)。不过,1500 列太多了。这些数据的范围是什么?您可能有更多的多列表,而不是到目前为止所显示的。
  • 你能指定用例吗?我真的很想知道这种方法应该解决哪个问题。
  • 这不是标准化的设计,你知道的。查询也不高效或容易。
  • 你不应该在 21 世纪使用隐式连接。它们是一种 SQL 反模式。
  • “标准化”。我不认为它意味着你认为它的意思。

标签: mysql database


【解决方案1】:

同样,我们的目标是能够在一行中检索 MasterData 中的所有数据,就好像它是 Master 中的一列一样。这可能吗?

在不完全了解您的目标的情况下,严格来说,我会冒险说这可能可能。但这在任何实际意义上都不太可能。即使在最好的情况下(只有一两个属性),性能也可能很糟糕;在可能的情况下(30 到 500 个属性之间),您可能会完全关闭服务器。

规范化 并不意味着“创建第二个表,该表将为初始表中存在的每一列/行提供一条记录”。这并不意味着任何远程喜欢。但是可能规范化实际上会解决您的问题。 (根据我的经验,大多数数据库问题都是结构性的。)

您在此处提出的解决方案不能很好地解决您未说明的问题。要充分利用 StackOverflow 的专业知识,请说明您要解决的问题以及您尝试过的解决方案。

Wikipedia article about database normalization


如果你从这样的表开始。 . .

create table master_data (
  master_id integer not null,
  property_name varchar(30) not null,
  property_value boolean not null default true,
  primary key (master_id, property_name)
);

insert into master_data values
(1, 'Property3', true),
(1, 'Property4', false),
(3, 'Property3', false),
(4, 'Property7', true);

。 . .那么您可以通过一个简单的查询获得所有事物的所有属性。 (假设您的所有属性都是布尔值。)

select * 
from master_data
order by master_id, property_name
--
1   Property3   t
1   Property4   f
3   Property3   f
4   Property7   t

应用程序代码可以非常简单地循环。您也许可以删除 property_value 为 false 的所有行。

这种结构允许每个事物有无限数量的属性。但是您的要求是 a) 在单行中返回任意数量的属性,并且 b) 对应用程序代码进行最小的更改必须更改。没有办法。


如果您的表包含这些行。 . .

insert into master_data values
(1, 'Property3', true),
(1, 'Property4', false),
(3, 'Property3', false),
(4, 'Property7', true),
(1, 'Property7', true);

这是获取一组符合条件的“事物”并将该集合连接到主数据表的一种方法。

select md.* 
from master_data md
inner join (select master_id
            from master_data
            where (
              (property_name = 'Property3' and property_value = true) or
              (property_name = 'Property7' and property_value = true)
            )
            group by master_id 
            having count(*) = 2 ) cd
  on (md.master_id = cd.master_id)

就其价值而言,规范化仍然是可能长期维护和性能的最佳选择。这种结构(上图)没有归一化;大数据集的性能通常很差。 (在这方面,带有可选 hstore 模块的 PostgreSQL 可能比 MySQL 更好。)

【讨论】:

  • 这是我在 Stackoverflow 上的第一篇文章,我不太确定 cmets 是如何工作的,但我会重复上面刚刚写的内容。我们的问题是我们的主表中的列(属性)用完了,需要一种方法来继续添加“属性”。做这个的最好方式是什么?我知道这不是“规范化”的定义,但我之前已经在电子商务网络应用程序中看到过这种技术,所以我们想在这里尝试一下。我绝对愿意接受您可能提出的任何其他建议或您可以指向我的链接。
  • MySQL has column and row size limits. AFAIK,没有 SQL dbms 支持永远连续添加列。您可能能够添加另一个具有基本相同结构和完全相同主键数据类型(但不是自动编号)的表,并将它们与外键约束链接(使用 INNODB,而不是使用 MyISAM) .这会给你一堆你可以在第二个表中使用的列,但我认为这是一个创可贴,而不是一个解决方案。 (在运行时加入两个表;但不要超过列或行大小限制。)
  • 同意。我认为类似结构的第二张桌子将是一个创可贴。我们可以在第二个表上达到列限制,这个问题会再次出现,然后我们将不得不进入代码并调整所有查询......再次。你能想出一个“解决方案”来解决这个问题吗?有什么我可以进一步解释的吗?
  • 输出需要一行 1500+ 列是什么?不管那是什么——这似乎是你真正的问题。
  • 是的,这是真正的问题,也是我们正在努力解决的问题。 Master 中的每一行都是与单个事物有关的记录。每列都是该事物的属性。其中一些东西有 1500 个(并且还在增长)属性。有时我们只返回一个带有属性的东西,有时我们返回 1000 个带有属性的东西。我们正在尝试将单个查询或与数据库的连接保持在最低限度。为每件事查询一次 MasterData 表会大大增加查询次数,因此我们试图避免这种情况。
猜你喜欢
  • 1970-01-01
  • 2011-10-07
  • 2011-11-15
  • 2012-12-25
  • 2014-04-19
  • 2014-07-29
  • 2012-01-06
  • 1970-01-01
  • 2015-01-04
相关资源
最近更新 更多