6

我正在寻找一种有效的方法来存储在事件期间一起发生的对象集,这样我就可以每天对它们生成聚合统计信息。

举个例子,让我们想象一个跟踪办公室会议的系统。对于每次会议,我们都会记录它持续了多少分钟以及在哪个房间举行。

我想按人和房间细分统计数据。我不需要跟踪单独的会议(所以没有meeting_id或类似的东西),我只想知道每日汇总信息。在我的实际应用程序中,每天有数十万个事件,因此单独存储每个事件是不可行的。

我希望能够回答以下问题:

2012 年,Bob、Sam 和 Julie 在每个会议室(不一定在一起)花了多少分钟?

使用 3 个查询可能很好:

>>> query(dates=2012, people=[Bob])
{Board-Room: 35, Auditorium: 279}
>>> query(dates=2012, people=[Sam])
{Board-Room: 790, Auditorium: 277, Broom-Closet: 71}
>>> query(dates=2012, people=[Julie])
{Board-Room: 190, Broom-Closet: 55}

2012 年,Sam 和 Julie 在每个会议室中的会议时间是多少?Bob、Sam 和 Julie 在一起怎么样?

>>> query(dates=2012, people=[Sam, Julie])
{Board-Room: 128, Broom-Closet: 55}
>>> query(dates=2012, people=[Bob, Sam, Julie])
{Board-Room: 22}

2012 年,每个人在董事会会议室花费了多少分钟?

>>> query(dates=2012, rooms=[Board-Room])
{Bob: 35, Sam: 790, Julie: 190}

2012 年,董事会会议室使用了多少分钟?

这实际上非常困难,因为总结每个人花费的分钟数的幼稚策略会导致严重的过度计算。但是我们可以通过将数字单独存储为元人任何人来解决这个问题:

>>> query(dates=2012, rooms=[Board-Room], people=[Anyone])
865

我可以使用哪些好的数据结构或数据库来启用这种查询?由于我的应用程序的其余部分使用 MySQL,我很想定义一个字符串列来保存会议中每个人的(排序的)id,但是这个表的大小会很快增长:

2012-01-01 | "Bob"           | "Board-Room" | 2
2012-01-01 | "Julie"         | "Board-Room" | 4
2012-01-01 | "Sam"           | "Board-Room" | 6

2012-01-01 | "Bob,Julie"     | "Board-Room" | 2
2012-01-01 | "Bob,Sam"       | "Board-Room" | 2
2012-01-01 | "Julie,Sam"     | "Board-Room" | 3

2012-01-01 | "Bob,Julie,Sam" | "Board-Room" | 2

2012-01-01 | "Anyone"        | "Board-Room" | 7

我还可以做些什么?

4

5 回答 5

0

如果人数不变且不是很大,则可以为每个人分配一列是否存在,并将房间、日期和时间存储在另外 3 列中,这可以消除字符串拆分问题。

同样根据您问题的性质,我觉得首先您需要为所有房间、人员等分配 ID。不需要在数据库中使用长重复字符串。还可以尝试减少任何字符串操作,并使用每列中的单独数据来获得更好的交叉点性能。您还可以将所有人的排列存储在一个表中并为他们分配一个 ID,然后在实际日期和时间表中使用其中一个 ID。但是所有的技术都需要一些东西是恒定的,无论是人还是房间。

于 2013-08-11T15:55:00.283 回答
0

我不明白您是否知道设计时的所有“问题”,或者是否可以在开发/生产期间添加新问题——这种方法需要始终保留所有数据。

好吧,如果您知道所有问题,那么它似乎就像经典的“银行系统”,它每天都会重新计算数据。

我怎么想的。

  1. 似乎您的房间、人数、天数等​​数量有限。
  2. 每天收集记录数据,每天一张表。只需一个事件,一个数据库行,您需要的所有信息(字段)。
  3. 在“午夜”开始使用一些 crone 脚本分析数据。
  4. 更新人员、房间等的统计信息。只需增加 Bob 在 xyz 房间等中花费的小时数。所有您需要的。
  5. 由于分析的数据是有限的并且在您分析(压缩)它们时相对较小,您的系统还可以包含各种查询,因为索引会相对较小等。

您可以使用可扩展的 map/reduce 算法。

于 2013-08-12T06:37:00.803 回答
0

您的问题有点不清楚,因为您说您不想存储每个单独的会议,但是您如何获得当前的会议统计信息(日期)?此外,即使有很多记录,任何给定正确索引的表都可以非常快。

您应该能够使用像 log_meeting 这样的表。我想它可能包含以下内容:

employee_id, room_id, date (as timestamp), time_in_meeting

其中外键到员工 ID 到员工表,房间 ID 键到房间表

如果你索引员工 id、房间 id 和日期,你应该有一个非常快速的查找,因为 mysql 多列索引从左到右,这样你就可以获得索引(员工 id、员工 id + 房间 id 和员工 id + 房间 id +时间戳)何时进行搜索。这在以下的多索引部分中有更多解释:

http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

于 2013-08-06T15:01:30.970 回答
0

您无法避免将原子事实存储如下:(会议室、人员、持续时间、日期),当同一个人在同一天在同一个房间多次见面时,这可能只是一个弱合并。也许这在你的办公室经常发生:)。

使组具有可比性是一个有趣的问题,但只要您始终组成相同的成员字符串,您就可以通过字符串比较来做到这一点。然而,这并不“正常”。要规范化,您需要一个关系表(多对多)并从查询集中组成一个临时表以便它快速连接,或者使用“IN”子句和计数聚合来确保每个人都在那里(你会看到我的意思是当你尝试时)。

我认为您可以得出会议室正在使用的会议记录,因为会议不应重叠,因此可以计算总和。

为提高存储效率,请对带有查找表的所有内容使用整数键。在查询解析期间取消引用整数,或者如果您感觉传统,则只使用良好的旧连接。

无论如何我都会这样做:)。

于 2013-09-04T16:50:26.457 回答
0

通过拒绝单独存储会议(和相关对象),您将失去最初的信息来源。

除非您定期记住所有潜在的每日(或每月或每周或......)汇总的广泛列表,否则您将无法弥补这种数据丢失,您以后可能需要质疑!

相信我,这将是一场噩梦......

于 2013-08-09T14:18:20.043 回答