【问题标题】:Need best approach for database architecture madness需要数据库架构疯狂的最佳方法
【发布时间】:2012-03-16 17:46:09
【问题描述】:

我们正在为我们的初创公司构建一个调度系统。

这只是一个普通的,除了我们愿意实现的“自动查找”功能。灯架构。没什么特别的。

这就是 DB 的样子。三个主表:

  • 办公室(id、start_time、stop_time)
  • 人员(id、office_id、start_time、stop_time)
  • 时间表(id、people_id、start_time、stop_time)

start_time/stop_time 是 TIMESTAMPS。

表格不需要这样。这正是我们目前拥有的。

Offices 表有一个办公室的打开/关闭时间。这张桌子可以大到每个办公室 365 天,因为每天的开/关时间不一样。请注意,最多可以有 1000 个办公室。这使得表中大约有 365,000 多条记录。

有加入/离开时间。这显然比办公室更严格。同样,一年中的每一天人们都可以有不同的访问时间。每个办公室大约有 50 人。这使得 1000 个办公室 * 365 天 * 50 名员工 = 18,250,000 条记录。

时间表就是谁会见谁。每个人每天最多可能有 10 次会议。是的,此时这可以轻松地在此表中创建 1.825 亿行。

除了 数字之外没有什么奇怪的。应用程序需要做的是:给定办公室、要见面的人和持续时间,显示前 5 个可用日期。

据我们所知,这个应用程序将完全杀死我们的服务器。我们只是不顾一切地进行这次比赛。我们首先想到的是“这根本不可能”。但是,嘿!在软件中一切皆有可能,不是吗?

PS:如果有人想出更好的方法使应用程序可行,我们将真的感激它。

非常感谢您的阅读。希望有铁杆程序员能帮帮我们。

更新:

出于测试目的,我们创建了两个完全相同的表:

会议和办公室(id、profesional、start、stop)。

ID 为主,其余为 BTREE 索引。 SQL 是这样的(不能 100% 工作):

SELECT a.profesional, a.stop AS desde, Min(b.start) AS hasta 
FROM meetings AS a 
  JOIN meetings AS b 
    ON  a.profesional=b.profesional 
    AND a.stop < b.start 
WHERE a.profesional = 1 
  AND b.profesional = 1 
GROUP BY a.start 

UNION 

SELECT m.profesional, MIN(m.start), MIN(j.start) 
FROM offices m 
  JOIN meetings j 
    ON  j.profesional = m.profesional 
WHERE j.profesional = 1 
  AND m.profesional = 1 

UNION 

SELECT m.profesional, MAX(j.stop), MAX(m.stop) 
FROM offices m 
  JOIN meetings j 
    ON  j.profesional = m.profesional 
WHERE j.profesional = 1 
  AND m.profesional = 1 

ORDER BY desde ASC

我们所做的如下。只需添加 1 个办公室,时间为 240 天。每天有 8 次会议,总共约 2000 行。执行此类查询需要 2.6 (!) 秒。查询错了吗?可以重写吗?

【问题讨论】:

  • 描述很清楚,但如果您提供列名和数据类型会更好。
  • 抱歉,我刚刚添加了架构。
  • 您可以考虑使用基于 Web 的服务,例如 Amazon 或 Cloud。
  • @alexy13:现在有“The”云了吗?
  • UNION 更改为UNION ALL 肯定会有所帮助。

标签: php mysql architecture


【解决方案1】:

如果给你一个人,那不是已经将要考虑的计划行数减少了 50000 倍吗?如果只考虑给定的办公室,办公室的行数也将归结为几百。适当的索引会立即找到这些行。

此外,人们真的会提前安排一整年的会议吗,还是更有可能您在未来一两个月内只有一个订满的数据库?如果您的主数据库开始出现性能问题,您可以随时将旧数据移动到存档中。

此外,“最多”估计很容易想得太大。您应该尝试弄清楚每个办公室平均将有多少人,以及他们每天平均将举行多少次会议。 “一天最多 10 次会议”可能很容易变成“通常一天两次”。当然,这取决于我们谈论的业务类型。

别忘了减去周末。他们占一年的 2/7。

【讨论】:

  • 首先,非常感谢。我无法正确格式化评论,所以我将它们分开。出于测试目的,我们创建了两个完全相同的表:会议和办公室(id、profesional、start、stop)。 ID 为主,其余为 BTREE 索引。 SQL 是这样的(不能 100% 工作)
  • SELECT a.profesional, a.stop AS desde, Min(b.start) AS hasta FROM meeting AS a JOIN meeting AS b ON a.profesional=b.profesional AND a.stop
  • 我们所做的如下。只需添加 1 个办公室,时间为 240 天。每天有 8 次会议,总共约 2000 行。执行此类查询需要 3.1 (!) 秒。查询错了吗?可以重写吗?非常感谢!!
  • @José:您在该查询中的哪个位置指定了您要为其查找日程的人员的 ID?此外,最好将查询添加到您的实际帖子中,而不是使用 cmets。这样更容易阅读。英文标识符也很受欢迎。
  • 是的,你是对的。我刚刚将更新添加到帖子中。谢谢你的建议!
【解决方案2】:

您的应用程序似乎需要一个关键查询。找出由

定义的区间
 (OfficeOpenIntervals INTERSECT PeopleAtOfficeIntervals) MINUS ScheduleIntervals

并在这些时间间隔内搜索,在某个日期附近或之后。

使用适当的索引并限制查询(仅搜索一个人、接下来的 60 天等)可能没问题。处理时间间隔操作很棘手,但您可以使用各种索引和编写查询的方式进行测试。


另一种选择(如果您通过索引进行测试并没有找到有效的方法)是有一个单独的 AvailableSlots 表,当没有预定的约会时,首先会填充一个人在办公室的所有可用天数(那将是OfficeOpenIntervals INTERSECT PeopleAtOfficeIntervals)。然后,每次在Schedule 中添加约会时,此AvailableSlots 表中的相应行将被删除、更新或拆分为两行,以存储计划开会的人的剩余可用时间间隔。

因此,显示前 5 个可用日期的查询只需在此表中进行搜索。

这不是一个规范化的解决方案,并且必须通过存储过程来维护完整性(对于所有操作,例如添加的时间表、人员离开办公室、开始等)。最初的人口也可能需要时间和空间 - 但你不必填充表格一百年。可能只需要几个月的时间,可以稍后再增加人口(每月或每年一次或在需要时)。

【讨论】:

  • 非常感谢您的留言 ypercube。我们会试一试。非常感谢!
猜你喜欢
  • 2011-08-30
  • 1970-01-01
  • 1970-01-01
  • 2011-02-09
  • 1970-01-01
  • 2017-03-14
  • 2011-02-23
  • 2020-01-13
  • 1970-01-01
相关资源
最近更新 更多