【问题标题】:Adding columns versus adding rows - which offers better performance?添加列与添加行 - 哪个提供更好的性能?
【发布时间】:2014-08-14 05:36:36
【问题描述】:

搜索和搜索。不知道如何使用解释/分析来回答这个问题,没有构建真正的大测试表,我没有办法或时间去追求。当然,有人可以自信地为我回答这个可能很简单的问题,并节省我数小时的测试时间。

我有一个看起来像这样的表:

id | destination_id | key | value | json_profile_data | deleted_bool | deleted_timestamp

键和值是表的原始用途,但我们最近开始存储 json 数组,现在键/值字段未使用。我想在这个记录 id 中添加 3 个新的数据位。我的直觉是在每行中为 3 个新字段创建新列,但我的同事希望使用键/值列使用相同的 destination_id 添加信息。

我的建议意味着表格中的行数更少,如下所示:

id | destination_id | key | value | json_profile_data | claim_code | claim_date | claim_approved_bool | deleted_bool | deleted_timestamp

HIS 解决方案是添加新行,使用键/值 cols 在这些新行上插入与它们的父行具有相同destination_id 的三个新信息位。

id | destination_id | null                | null  | json_profile_data | deleted_bool | deleted_timestamp
id | destination_id | claim_code          | value | null              | deleted_bool | deleted_timestamp
id | destination_id | claim_date          | value | null              | deleted_bool | deleted_timestamp
id | destination_id | claim_approved_bool | value | null              | deleted_bool | deleted_timestamp

他的解决方案为每个destination_id 生成4 行,我的解决方案为给定的destination_id 在现有行上生成3 个新列。

针对此表进行选择时哪个性能更高?还是有关系?我希望我以一种清晰的方式写了这个。如果需要更详细的说明,请告诉我。

【问题讨论】:

  • 您的解决方案更加规范化,但性能的问题对于您的特定数据和用例而言非常具体,我不知道是否在这里可以给出一个自信的答案。有时,获得更快读取或其他东西的最佳方法是对数据结构进行反规范化。
  • 这是非规范化与规范化的争论...我相信您可以使用 google 找到 20 年值得阅读的主题。他的方法无法被索引...如果您使用已添加的三列中的任何一列进行搜索,则您的方法允许对它们进行索引,而他的方法则不允许。另一方面,如果这三列非常稀疏,他的方法可能会更好。这是一场漫长的辩论^^
  • 与大多数事物数据库一样,答案是“取决于”,特别是需要返回什么结果集、指定了哪些谓词以及可用的索引.话虽如此,向表中添加列可能会比添加行提供更好的性能。我认为,一个更重要的问题是插入/更新/删除操作的设计。原始表看起来像是 EAV 模型的实现。为了坚持 EAV 模型,我们将添加行。如果提高性能是目标,我们将完全避免使用 EAV 模型,而只是将属性存储为列。
  • 感谢您的意见。既然你们都评论了我不能投票或选择这些答案中的任何一个,但我学到了我需要知道的东西,在我们的案例中,能够索引是我决定的关键,并且“我赢得了办公室辩论“, 或多或少。 ;) 谢谢大家!
  • 这样的问题必须提供正确的表定义,显示数据类型(\dt tblin psql)。并且总是你的 Postgres 版本,即使我们在这里可能不依赖它。

标签: sql postgresql database-design entity-attribute-value


【解决方案1】:

与大多数事物数据库一样,答案是“视情况而定”。特别是主要取决于需要返回什么结果集,指定什么谓词,索引可用,基数等。

话虽如此,一般来说,向表中添加列可能会比添加行提供更好的性能。

一个更重要的问题(我认为)是插入/更新/删除操作的设计。

原始表看起来像是 EAV(实体属性值)模型的实现;当需要“透视”结果并以不同的格式返回时,针对 EAV 的查询会变得非常复杂;或者当我们有多个属性的谓词时。

为了坚持使用 EAV 模型,我们将向表中添加行,并仔细研究处理该模型所需的更复杂的 SQL。

但如果提高性能是目标,我们可能会完全避免使用 EAV 模型,而只是将属性存储为列。这就是传统的关系数据库模型:每一行代表一个“实体”(即可以唯一标识的人、地点、事物、概念或事件,我们需要存储有关信息),每一列代表一个“属性”,一个片段关于实体的信息。

【讨论】:

  • 确实这是 EAV 和非 EAV 的混合体。正如我在上面的其他 cmets 中所指出的,我认为我们需要添加 cols 以允许索引,这反过来将最大限度地提高该表的预期使用和数据内容的效率。干杯!
【解决方案2】:

正如您所说,您必须尝试使用​​实际数据量才能凭经验看到它,但毫无疑问,“添加列”方法的性能会更高。另一种方法需要四个连接,这几乎肯定会减慢速度。

【讨论】:

  • 不需要使用 postgres 枢轴语法的 4 个连接。当他发现他无法索引其他方法中的任何行时,会出现较慢的组件
  • 连接不是指 4 个 where 子句说明符吗?无论如何,我想我在主评论线程中得到了答案,那就是“我的方式”允许索引,这将使我们在处理数据的情况下受益。谢谢!
【解决方案3】:

您的同事建议 EAV 存储。 dba.SE 上这个相关问题的详细信息:

其余部分用于Postgres,仅部分适用于 MySQL。
您已经拥有一个json 列,这是该问题的明显第三种解决方案,但你们似乎都没有考虑到这一点?甚至可能只是在适当的位置添加到 json 列(不过,这不是我通常会这样做。)实际上,如果你走这条路,请考虑即将推出的 Postgres 9.4 中的新 jsonb。 p>

但是,只要我们只讨论这三列(而不是每 n 周新的一列),您的方法赢得了几乎在性能上的赌注任何可能的方面,从长远来看也是如此。额外的列要便宜得多。即使他们大部分时间是NULL,因为 NULL 存储非常便宜:

存储大小是影响性能的主要因素。

任何一种方法都可以编入索引。对于 EAV 存储,您可以使用partial indexes。为了优化这一点,需要了解典型的查询、访问模式、要求和优先级。您的方法通常更易于管理。

你的方法会松散的明显方面:

  • 如果存在可变(未知)数量的新列,您需要即时添加。使用 EAV 方法要简单得多。

  • 如果您对新列(其中之一)有大量更新。单独的小行更便宜。

最近的相关答案讨论了表格中的许多列,并带有用于交叉制表的代码,通常是 EAV 存储所需要的:

【讨论】:

  • Storage size is a major contributor to performance. 避免这种情况的另一种方法是将附加的库(或它们的组)存储在附加的中,然后将它们连接到基表中。 (“一个穷人的基于列的 DBMS”)表相对便宜,1::0..1 连接也是如此,给定正确的 PK/FK。 (这种方案可以通过动态SQL自动化)
  • @erwin Brandstetter 感谢您的周到和详尽的回复。我们确实讨论了将 cols 添加到 json 对象,但希望将它们分开,因为 json 包含用户管理的配置文件信息。新列在幕后系统控制/标志类型信息。我们不想将用户生成的数据与系统生成的数据混合在一起,并因此排除了这种方法。我们是你的 2cd 子弹。大量的 json 行更新,只是一次插入到“标志”类型的行,但是在 where 子句中有很多选择。不需要更多的标志字段。非常感谢!
  • @wildplasser - 加入可能确实是要走的路,但我们现在已经采用了最初在我的第一篇文章中描述的额外 cols 想法。我们会看看情况如何。我感谢所有回答的人,但我在这里还没有足够的地位来投票给任何人/每个人。请大家接受我的感激之情,因为我是帮助陌生人渡过难关的出色互联网英雄。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-11
相关资源
最近更新 更多