数据抓取/仓库应用程序的数据库设计建议?

时间:2014-07-30 08:40:33

标签: mysql sql database database-design

我正在研究一个数据仓库项目的数据库设计,每天涉及大量的插入。数据存档将进一步用于生成报告。我将有一个用户列表。 s(例如200万用户),我需要监控与之相关的日常社交网络活动。

例如,让一组100个用户说U1,U2,...,U100

我需要将他们的每日状态计数插入我的数据库。

考虑6月30日至7月6日期间用户U1获得的总状态计数如下

June 30 - 99
July 1 - 100
July 2 - 102
July 3 - 102
July 4 - 105
July 5 - 105
July 6 - 107

数据库应保持每个用户的每日状态计数,例如

对于用户U1,

July 1- 1 (100-99)
July 2- 2 (102-100) 
July 3- 0 (102-102) 
July 4- 3 (105-102) 
July 5- 0 (105-105) 
July 6- 2 (107-105) 

同样,数据库应保存整套用户的存档详细信息。

在稍后阶段,我设想从这些数据中收集汇总报告,例如每天,每周,每月等得分总分;并将其与旧数据进行比较。

我需要从头开始。我经历过PHP作为服务器端脚本和MySQL。我在数据库方面感到困惑?由于我每天需要处理大约一百万次插入,所以应该注意什么?

我对如何在这方面设计MySQL数据库感到困惑?要使用哪个存储引擎和设计模式,请记住,数据以后可以有效地用于聚合函数。

目前我设想数据库设计有一个表存储所有用户ID,每个日期都有一个外键和单独的状态计数表。很多表可能会产生一些开销吗?

MySQL 符合我的要求吗?每天完成200万或更多数据库操作。在这种情况下如何考虑服务器和其他事项。

1)数据库应该处理并发插入,每天应该启用1-2百万次插入。

在插入之前,我建议计算每日状态计数,即今天与昨天的差异。

2)在稍后阶段,档案数据(过去几天收集)用作数据仓库,并在其上执行聚合任务。

评论:

我读过MyISAM是数据仓库项目的最佳选择,同时听说INNODB在很多方面都表现出色。许多人建议进行适当的调整以完成它,我也想对此有所了解。

5 个答案:

答案 0 :(得分:2)

创建数据仓库时,您不必担心规范化。您正在插入行并读取行。

我只有一张这样的桌子。

Status Count
------------
User id
Date
Count

主(群集)密钥是(用户ID,日期)。另一个唯一索引是(日期,用户ID)。

至于MySQL是否可以处理这个数据仓库,这取决于运行MySQL的硬件。

由于您不需要参照完整性,我使用MyISAM作为引擎。

答案 1 :(得分:1)

对于表格设计,具有星型模式的维度模型通常是数据集市的一个很好的选择,其中主要是插入和读取。我看到状态数据有两个不同的粒度,一个用于每天状态,一个用于每个用户的状态,因此我推荐类似于以下的表:

user_status_fact(user_dimension_id int, lifetime_status int)

daily_status_fact (user_dimension_id int, calendar_dimension_id int, daily_status int)

user_dimension(user_dimension_id, user_id, name, ...)

calendar_dimension(calendar_dimension_id, calendar_date, day_of_week, etc..)

您可能还会考虑使用最详细的数据,即使您没有最新的数据,因为它可能会在将来更容易构建聚合:

status_fact (user_dimension_id int, calendar_dimension_id int, hour_dimension_id,  status_dimension_id, status_count int DEFAULT 1)

hour_dimension(hour_dimension_id, hour_of_day_24, hour_of_day_12, ...)

status_dimension(status_dimension_id, status_description string, ...)

如果您不熟悉维模型,我会推荐Kimball的图书数据仓库工具包。

我还推荐MyISAM,因为在处理大部分读取仓库时,您不需要InnoDB提供的事务完整性。

我会问你是否想要在生产数据库中进行并发插入。通常在仓库环境中,这些数据会随着时间的推移而被批量处理并大量插入,并且可能会通过促销流程进行。

至于可伸缩性,mysql当然可以在适度硬件上每天处理2M写操作。我在基于云的服务器上插入500K +行/天(每小时批量),8GB的ram运行apache + php + mysql,并且插入对于访问相同数据库的php用户来说并不是很明显。

我假设你每天每个用户会插入一个新行(不是每天2行,因为有些用户会有多个状态)。您应该查看每天要创建的新行数。当你到达大量行时,你可能不得不考虑分区,分片和其他性能技巧。有很多书可以帮助你。或者您也可以考虑转移到分析数据库,例如Amazon Red Shift。

答案 2 :(得分:0)

我会为每天的每个用户状态创建一个事实表。此事实表将通过date_key连接到日期维度,并通过user_key连接到用户维度。事实表的主键应该是代理键= status_key。

因此,您的事实表现在有四个字段:status_key,date_key,user_key,status。

加载维度和事实表后,再进行处理和聚合。

编辑:我认为你对数据集市和星型模式有所了解。这是一个简单的星型模式,以您的设计为基础。 enter image description here

此设计将存储指定日期的任何用户状态。 (如果用户状态可以在白天更改,只需添加时间维度。)

此设计适用于MySQL或SQL Server。您必须每天管理一百万次插入,不要将其与之前的数据点进行比较。您可以在加载后使用datamart(星型模式)执行此操作 - 这是它的用途 - 分析和聚合。

答案 3 :(得分:0)

如果有大量的DML操作并且从数据库MYISAM引擎中选择记录则更喜欢。 INNODB主要用于TCL和参照完整性。您还可以在表级指定引擎。

如果您需要生成报告,那么MYISAM引擎的工作速度也比INNODB快。查看报告所需的表格或数据。

请记住,如果您使用PHP编程从MYSQL数据库处理生成数百万个数据的报告可能会产生问题。您可能经常遇到500或501错误。

因此,所需表格的报告生成视点MYISAM引擎将非常有用。

您还可以将数据存储在多个表中以防止开销,否则可能会导致数据库表崩溃。

答案 4 :(得分:0)

看起来您需要一个架构,每个用户每天只能保留一个计数。非常简单。您应该创建一个DAY,USER_ID和STATUS_COUNT的表。

在DAY和USER_ID上一起创建一个索引,如果可能的话,保持表中的数据按DAY和USER_ID排序。只要您按任何(或所有)用户的日期范围查询数据,这将使您能够非常快速地访问数据。

例如:

select * from table where DAY = X and USER_ID in (Y, Z);

会非常快,因为数据按天依次在磁盘上排序,然后由user_id排序,因此很少有人试图满足查询。

另一方面,如果您更有兴趣在一段时间内找到特定用户的活动:

select * from table where USER_ID = X and DAY between Y and Z;

然后前一种方法不太理想,因为查找数据需要多次搜索而不是顺序扫描。首先按USER_ID索引,然后按DAY索引,并保持数据按该顺序排序;这将需要更多的维护,因为表需要经常重新排序。同样,这取决于您的用例,以及您希望对表的查询响应的速度。

我没有广泛使用MySQL,但我相信MyISAM的插入速度更快,代价是事务隔离。对于您所描述的系统,这不应该是一个问题。

此外,如果您使用的是合适的硬件,那么每天2MM的记录应该是儿童游戏(只有23个插入/秒)。特别是如果你可以使用mysqlimport批量加载记录。如果这是不可能的,那么23次插入/秒应该仍然非常可行。

然而,我不会在插入当天的情况下计算前一天的增量。有一个名为LAG()的分析函数可以非常方便地为您完成(http://explainextended.com/2009/03/10/analytic-functions-first_value-last_value-lead-lag/),更不用说它在细节层面似乎没有任何实际用途。

使用此详细数据,您可以按照自己喜欢的方式聚合它,将DAY列截断为WEEK或MONTH,但要小心如何构建聚合。你说的是每年超过70亿条记录,而在这么多行上重新构建聚合可能会非常昂贵,尤其是在单个数据库上。您可能会考虑使用Hadoop进行聚合处理(我建议使用Spark而不是普通的旧Map / Reduce,它的功能更强大)。这将减轻数据库服务器(无法轻松扩展到多个服务器)的任何计算负担,并允许它完成记录和存储新数据的工作。

您也应该考虑对表格进行分区。分区表的一些目的是分发查询负载,简化数据归档,并可能提高插入性能。我会考虑按照您所描述的应用程序沿月边界进行分区。