【问题标题】:Designing schema of data with both common and arbitrary attributes设计具有通用属性和任意属性的数据模式
【发布时间】:2011-07-06 02:13:37
【问题描述】:

我不确定这个标题是否真的有意义,但这是我的普遍问题:

我有一个表格,其中包含有关跨多个不同设备和平台的事件的信息。我不确定如何有效地设计用于查询所有事件的架构,然后查询特定的事件信息。

我试图将其全部保留在下面的伪代码中,因此如果代码中的某些内容没有意义,那只是因为我试图保持其通用性。

这是一个人为的例子:

Event Table:
  int Id
  datetime Occured_On
  uniqueidentifier UserId --> Users table
  int Category (the type of event) --> Categories table
  text Summary (textual summary of the event)
  text EventSource (specifies whether this is a DesktopEvent or MobileEvent)

然后,每个设备都有自己的每个事件的数据集。例如:

DesktopEvent
  int Id
  int EventId --> Event table
  text Hostname
  text LoggedInUsername

MobileEvent
  int Id
  int EventId --> Event table
  int PlatformId 
  text ESN

...

我想查询最近 X 个最近事件的事件表。现在,我目前有一列指定事件的来源,以便我可以对相应的表进行第二次查询。

results = SELECT * FROM Event DESCENDING Occured_On LIMIT 5. 

foreach (result in results)
{
    if (result.EventSource == "DesktopEvent")
       data = SELECT * FROM DestkopEvent WHERE EventId == result.EventId

    ...
}

这似乎非常低效。

可能有许多不同的事件来源,而不仅仅是上面的 2 个(DesktopEvent 和 MobileEvent),因此情况更加复杂。尝试连接 10 多个表来检查哪个表不是 NULL 似乎比上面更糟糕。

有没有更好的方法来构建这些数据?非常感谢。

【问题讨论】:

    标签: sql sql-server database schema


    【解决方案1】:

    一种选择是将所有此类特定于事件的数据存储在 EAV 样式表中:

    http://en.wikipedia.org/wiki/Entity-attribute-value_model

    因此,您可能只需要 2 个表 - EVENT 表和 EVENT_DETAILS 表。例如,如果您的桌面事件 ID = 12,您可能在 EVENT_DETAILS 表中有以下内容:

    1, 12, hostname, myhost
    2, 12, loggedInName, myname
    ...
    25, 17, esn, <esn value> 
    etc.
    

    因此,您在一个表格中混合了不同事件类型的详细数据。此可能查询效率较低,但它是一个简单、易于理解的模型,适用于可扩展性和数据动态处理/视图。

    如果您需要优化这类事情,您可以查看面向列的 DB:

    http://en.wikipedia.org/wiki/Column-oriented_DBMS

    【讨论】:

    • 感谢您的链接。我认为因为一些子类型属性是关系的,所以只使用单个表仍然是有意义的,所以我可以保持参照完整性。不过,我还没有真正阅读过 EAV,所以我很欣赏这个链接。
    【解决方案2】:

    在数据建模中,您有时会发现并非完全不同但也不完全相同的事物。它们有一些共同的属性,所以它们并没有完全不同。但他们每个人都有一些独特的属性,所以他们并不完全相同。

    所有这些事物共有的属性都属于一个表。该表通常称为超类型。

    每组独特的属性都属于不同的表;这些表称为子类型。在数据建模中,“超类型”和“子类型”与使用相同词的面向对象编程概念没有任何关系。一样的词,大不相同的意思。小心点。

    听起来“事件”表是您的超类型。 “桌面事件”和“移动事件”是几个子类型中的两个。

    如果是这样,您可能走在正确的轨道上。低效率只是表面上的,而不是真实的。事实上,桌面事件和移动事件对您来说是不同的东西,因此它们必须存储在不同的表中。并且将它们存储在不同的表中使得完整性约束的实现变得无限简单。毕竟,这就是 SQL 数据库的设计目的。查询可以利用索引。

    通常,超类型和“n”子类型映射到“n”+1 个表和“n”视图。每个“n”个子类型都有一个表,超类型有一个表。您还需要为每个子类型构建一个视图;每个视图将一个子类型连接到超类型。您通常会使用视图,而不是直接使用子类型表。但是您可以直接使用超类型表——例如,获取最后五个事件。

    在 SO 中搜索术语超类型和子类型。所以用户 PerformaceDBA 和我都不止一次写过它们。 (向那些关注关系超类型和子类型的其他人道歉;我在记住名字时遇到了很多麻烦。)

    【讨论】:

    • 感谢您确认我的想法。我想我试图说服自己拥有如此多的个体亚型是错误的。但是,鉴于它们是不同的类型,因此对它们进行不同的建模是有意义的。
    【解决方案3】:

    您应该在 SQL 中进行联接,而不是在应用程序代码中进行两次查询。

    例如

    SELECT * FROM (
    SELECT de.*, e.* 
    FROM DestkopEvent  de , Event e
    WHERE EventId == e.EventId
    ORDER BY e.occurred_on desc
    ) 
    WHERE rownum < 6
    

    这个想法是将查询执行的复杂性留给数据库,而不是在应用程序代码中处理。此外,您可以添加索引以进一步优化查询。 但从本质上讲,如果您正在寻找优化 - 那就考虑数据库而不是考虑应用程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-06
      • 1970-01-01
      • 2015-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多