一个WebApp的PHP和MySQL统计报告建议

4

背景:

我在我的小公司中“继承”了一个php web应用程序,经过多年的催促,终于得到了开始丢弃混乱代码并重新开始的机会。

我们想要记录系统中进行的每个操作,例如:

  • 用户X查看了物品Y
  • 用户X更新了物品Y
  • 城市Z上有新物品Y

之后,以不同的分辨率(日、月、年)提供执行的操作的图表。

在以前的版本中,我们有一张表,自2005年以来已有2000万条记录,因此这会给您一个我们已经拥有的数据量的概念,而这只是许多统计数据之一。

实际问题:

您对构建几乎实时的系统以创建这些统计信息有何建议?

注意事项:

  1. 通过谷歌的可视化API已经涵盖了图形绘制
  2. 我不反对使用任何NoSql数据库或消息服务器、计划任务或完成工作的任何其他方式,但更喜欢mysql/php解决方案
  3. 我目前的想法是为我想要保存的每一种统计数据自动创建一个表,并创建几个聚合表(按月、按日、按年),以缓存结果。
  4. 我知道这是一个广泛的问题,但欢迎任何建议。
3个回答

2
如果所有用户都必须注册,我会选择一个完整的规范化解决方案。
USERS TABLE            OBJECTS TABLE
---------------        -----------------     
user_id (primary)      object_id (primary)


USERS_TO_OBJECTS TABLE
--------------------
user_id (index)
object_id (index)
time (index)
action (index)
? object_type (index) // could be useful to speed things up

这种设置可能会在绘制图表时为您提供最佳的灵活性,并且如果您不需要用户或对象,则也会非常快速。 编辑: 假设城市X(id 9876)由用户123(id 1234)更新...
1234    - user_id (the user that did the action)
9876    - object_id (the object where the action was done)
xyz     - time
updated - action type (so that you select only specific actions)
city    - object type (so that you select only specific objects)

我已经用40M行填充了这张表,结果还是非常可接受的。
在最后一周更新的城市数量上进行简单的COUNT操作只需要0.002秒。数据是随机插入的。 编辑2 如果你发现自己有一个非常庞大的表,可以使用MySQL分区来优化你的架构。我真的不知道你将如何使用这些表,但你可以:
按范围进行分区。按日期组织分区。每个月或更长时间后,你都会有一个新的分区。
按键进行分区。按操作组织分区。每个操作都进入其相应的分区。
你可以查看MySQL网站上的更多分区信息本文详细介绍了分区的微调

感谢@Frankie,我期望有很多行数据,把所有统计数据存储在同一张表中会让它变得非常庞大并且缓慢。此外,有些统计数据还包含了额外的信息,例如在城市Z出现新项目Y,并不总是用户ID。 - Mon Villalon
@Mon Villalon,我进行了一些测试并相应地更新了答案。如果所有查询都使用良好的索引,4000万行不应该是问题。但是,如果您发现数据库有困难,仍然可以采用分区。 - Frankie

1
您可以将“数据库”视为Redis。Redis使用链表来存储列表类型,因此您可以轻松地将LPUSH添加到列表中,如下所示:
$action = array(
    "type"=>"page_view",
    "url"=>"/example/path",
    "user"=>"user1",
    "timestamp"=>$_SERVER["REQUEST_TIME"]
);
$r = new Redis();
// Redis connection info //
$r->lPush("global_history", json_encode($action));

LPUSH 操作的运行时间为 O(1),所以这不应该是问题。检索结果可能会有点棘手(列表需要 O(n) 时间)。Redis 也主要基于内存(尽管开发版本包括“虚拟内存”支持),因此它很快,但你可能很容易就用完了空间。

我使用这种技术记录我运营的音乐网站的历史和统计数据。它非常成功,并提供非常快速的结果,而且付出的努力很少。

如果你想让它更加稳定,可以使用 Hadoop 或其他技术从列表末尾(RPOP)拉取并将结果归档到更永久的格式中(例如推送到 Amazon S3 的 XML)。然后,当查看旧数据时,你可以让 Google 可视化从存档中查找它们的数据(这将是静态编译的数据),而在查看最近数据时则使用 Redis 前端。

希望这能帮到你!


0
很高兴你终于得到了重新设计那个项目的绿灯。也许现在回复有点晚了,但是使用MongoDB(带有其Capped Collections功能)的实现可能会更好地完成这种工作。实施它并不太费时间,所以还有机会。
无论如何,希望一切顺利。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接