8

我正在使用新版本的第三方应用程序。在这个版本中,数据库结构发生了变化,他们说“提高性能”。

旧版本的 DB 具有如下一般结构:

TABLE ENTITY
(
    ENTITY_ID,
    STANDARD_PROPERTY_1,
    STANDARD_PROPERTY_2,
    STANDARD_PROPERTY_3,
    ...
)

TABLE ENTITY_PROPERTIES
(
    ENTITY_ID,
    PROPERTY_KEY,
    PROPERTY_VALUE
)

所以我们有一个包含基本属性字段的主表和一个单独的表来管理用户添加的自定义属性。

新版本的数据库 insted 具有如下结构:

TABLE ENTITY
(
    ENTITY_ID,
    STANDARD_PROPERTY_1,
    STANDARD_PROPERTY_2,
    STANDARD_PROPERTY_3,
    ...
)

TABLE ENTITY_PROPERTIES_n
(
    ENTITY_ID_n,
    CUSTOM_PROPERTY_1,
    CUSTOM_PROPERTY_2,
    CUSTOM_PROPERTY_3,
    ...
)

因此,现在当用户添加自定义属性时,会在当前ENTITY_PROPERTY表中添加一个新列,直到达到最大列数(由应用程序管理),然后创建一个新表。

所以,我的问题是:这是设计数据库结构的正确方法吗?这是“提高性能”的唯一方法吗?旧结构需要许多连接或子选择,但在我看来这个结构并不聪明(甚至不正确)......

4

5 回答 5

10

我之前已经在假设的(通常未经证实的)加入“费用”上看到了这一点——它基本上是将一个行重的数据表变成了一个列重的表。正如您所暗示的,它们在列用完时创建新表,从而遇到了自己的限制。

完全不同意。

就个人而言,我会坚持旧结构并重新评估性能问题。这并不是说旧方法是正确的方法,在我看来它只是比“改进”略好,并且不需要对数据库表和 DAL 代码进行大规模重新设计。

这些表在我看来基本上是静态的......缓存将是一个更好的性能改进,而不会破坏数据库,我会首先考虑这样做。进行一次“昂贵”的获取并将其粘贴在内存中的某个位置,然后忘记您的麻烦(注意,我正在考虑管理缓存的需要,但静态数据是最容易管理的数据之一)。

或者,等待您遇到每个数据库的最大表数的那一天 :-)

其他人则建议了完全不同的商店。这是一个完全可行的可能性,如果我没有现有的数据库结构,我也会考虑它。也就是说,我看不出为什么这种结构不能适应 RDBMS。我已经在我从事过的几乎所有大型应用程序上看到了它。有趣的是,它们都走上了类似的路线,而且大多都是“成功”的实现。

于 2012-05-03T08:15:14.507 回答
5

不,这不对。它是可怕的。

直到达到最大列数(由应用程序处理),然后创建一个新表。

这句话说明了一切。在任何情况下,应用程序都不应动态创建表。“旧”的方法也不是很理想,但既然你有让用户添加自定义属性的要求,它必须是这样的。

考虑一下:

  • 您将失去所有类型安全性,因为您必须将所有值存储在“PROPERTY_VALUE”列中
  • 根据您的用户,您可以让他们事先更改架构,然后让他们运行某种数据库更新批处理作业,因此至少所有属性都将以正确的数据类型声明。此外,您可能会丢失 entity_id/key 的东西。
  • 看看这个:http ://en.wikipedia.org/wiki/Inner-platform_effect 。这肯定有它的味道
  • 也许 RDBMS 不适合您的应用程序。考虑使用基于键/值的存储,如 MongoDB 或其他 NoSQL 数据库。( http://nosql-database.org/ )
于 2012-05-03T08:16:16.910 回答
1


根据我对数据库的了解(但我当然不是最有经验的),在您的数据库中执行此操作似乎是个坏主意。如果您已经知道用户可能拥有多少个最大自定义属性,我会说您最好将表列数设置为该值。

再说一次,我不是专家,但即时创建新列并不是像操作数据库那样。它会给你带来比什么都多的麻烦。

如果我是你,我要么修复自定义属性的数量,要么坚持使用旧系统。

于 2012-05-03T08:15:23.683 回答
0

设计数据库没有“正确”的方法——除了著名的“范式”理论之外,我不知道有一套普遍认可的标准;许多数据库设计出于性能原因而忽略了这个标准。

但是有一些评估数据库设计的方法——性能、可维护性、可理解性等。很多时候,您必须相互权衡;这就是您的更改似乎正在做的事情 - 将可维护性和可理解性与性能进行交易。

因此,确定这是否是一个好的权衡的最佳方法是查看性能提升是否已实现。找出这一点的最佳方法是创建建议的模式,使用代表性数据集加载它,然后编写您需要在生产中运行的查询。

我猜测对于诸如“从 STANDARD_PROPERTY_1 = 'banana' 的实体中查找 STANDARD_PROPERTY_1 之类的查询,新设计不会明显更快。

我猜在检索给定实体的所有属性时它不会更快。事实上,它可能会稍微慢一些,因为新设计不需要对 ENTITY_PROPERTIES 进行单个连接,而是需要对多个表进行连接。您将返回“稀疏”结果 - 可能并非所有实体都会在所有 ENTITY_PROPERTIES_n 表的 property_n 列中具有值。

当您需要自定义属性的复合 where 子句时,新设计可能会明显更快。例如,找到一个实体,其中自定义属性 1 为真,自定义属性 2 为香蕉,自定义属性 3 不在 ('kylie', 'pussycat dolls', 'giraffe') 中,如果可以的话,速度会更快(可能)指定 ENTITY_PROPERTIES_n 表中的列而不是 ENTITY_PROPERTIES 表中的行。大概。

至于可维护性 - 糟糕。您的数据库访问代码现在需要更加智能,知道哪个表包含哪个属性,以及有多少列太多。有趣的错误的可能性很高 - 有更多的移动部件,我想不出任何明显的单元测试来确保数据库访问逻辑正常工作。

可理解性是另一个问题——这个解决方案不在大多数开发人员的工具箱中,它不是行业标准模式。旧的解决方案广为人知——通常称为“实体属性值”。这成为长期项目中的一个主要问题,您无法保证原始开发团队会继续存在。

于 2012-05-03T10:06:05.267 回答
0

我相信为每个实体创建一个新表来存储属性是一个糟糕的设计,因为您最终可能会用表来填充数据库。应用第二种方法的唯一优点是您不会遍历所有不适用于所选实体的冗余行。但是,在原始 ENTITY_PROPERTIES 表上的数据库上使用索引可以极大地提高性能。

我个人会坚持您的初始设计,应用索引并让数据库引擎确定选择数据的最佳方法,而不是将每个实体属性分离到一个新表中。

于 2012-05-03T08:14:10.003 回答