社交应用程序的数据库设计和优化注意事项

时间:2011-03-26 11:24:13

标签: mysql database database-design query-optimization scalability

通常的情况。我有一个简单的应用程序,允许人们上传照片和关注其他人。结果,每个用户将具有诸如“墙”或“活动馈送”之类的东西,其中他或她看到从他/她的朋友(他或她跟随的人)上传的最新照片。

大多数功能都易于实现。然而,当涉及到这个历史活动源时,由于纯粹的性能原因,事情很容易变成混乱。

我在这里陷入了以下两难境地: 我可以轻松地将活动源设计为数据库的规范化部分,这将节省我的写入周期,但是在为每个用户选择这些结果时会极大地增加复杂性(对于在特定时间段内上传的每张照片,请选择一定数量,我关注的上传者/我关注的每个人,选择他的照片)

优化选项可能是引入一系列阈值约束,例如,允许我根据上次上传的日期对我关注的人进行排序,甚至排除一些,以节省周期,以及每个用户,只选择5个(例如)上次上传的照片。

第二种方法是为活动源引入完全非规范化的架构,其中每一行代表我的一个关注者的通知。这意味着每次上传照片时,DB都会在这个“drop bucket”中放入n行,n表示我遵循的人数,即大量的写入周期。但是,如果我有这样的表,我可以轻松地应用一些优化技术,例如聪明的索引,以及修剪早于特定时间段(队列)的条目。

然而,我想到的第三种方法是甚至是一种较少非规范化的模式,其中服务器端应用程序将从数据库中获取部分复杂性。我看到一些社交应用程序(如friendfeed)严重依赖于序列化对象(如DB中的JSON对象)的存储。

我当然还在掌握可扩展数据库设计的技巧,所以我确信有很多我错过或仍在学习的东西。如果有人能给我一个朝正确方向发光的话,我将非常感激。

5 个答案:

答案 0 :(得分:14)

如果您的申请成功,那么您可以获得更多的阅读而不是写作 - 我只会上传一次(写入)照片,但我的每个朋友都会在刷新Feed时读取它。因此,您应优化快速读取,而不是快速写入,这指向非规范化模式的方向。

这里的问题是,如果您拥有大量用户,您创建的数据量很快就会失控。数据库很难查询非常大的表,因此再次存在潜在的性能问题。 (还有一个问题就是有足够的存储空间,但这更容易解决)。

如果按照您的建议,您可以在一定时间后删除行,那么这可能是一个很好的解决方案。随着您的成长和遇到性能问题,您可以减少这段时间(最多一点)。

关于存储序列化对象,如果这些对象是不可变的(写入后不会更改它们),并且您不需要对它们进行索引或查询,那么这是一个很好的选择。请注意,如果您对数据进行非规范化,则可能意味着您有一个活动源表。在那种情况下,我看到存储blob的收益很少。 如果您使用序列化对象方式,请考虑使用一些NoSQL解决方案,例如CouchDB - 它们可以更好地优化处理这类数据,因此原则上您应该为相同的硬件设置获得更好的性能。 请注意,我并不是建议您将所有数据移动到NoSQL - 仅适用于那些更好的解决方案。

最后,从经验中提到一句谨慎的话:建立一个可以扩展的应用程序很难,并且需要花费更多时间在其他地方。在您担心如何为数百万人提供服务之前,您应该花时间担心如何让数百万用户访问您的应用 - 首先是更难的问题。当您达到非常成功的程度时,您可以重新构建并重建您的应用程序。

答案 1 :(得分:7)

您可以选择许多选项

  • 添加更多硬件,内存,CPU - Enter cloud hosting
  • Hows 24GB of memory sound?大多数重要访问的数据库信息都可以放在内存中。
  • 选择具有可扩展 SSD的主机。
  • 在您的应用程序中使用基于事件的系统来编写所有用户的“历史记录”。所以它会是这样的:id, user_id, event_name, date, event_parameters' - 一个例子是:1, 8, CHANGED_PROFILE_PICTURE, 26-03-2011 12:34, <id of picture>最重要的是,这个表格将在内存中。不再需要担心写性能。在记录过去,即3天后,如果用户选择返回那么远,则可以将它们清除到另一个表(在非存储器中)并包括在查询结果中。通过将所有这些放在一个表中,您可以删除必须执行多个查询和SELECT以构建此信息。
  • Consider using INNODB用于历史记录/供稿表。

阅读的好资源

答案 2 :(得分:2)

这些问题是目前使用NOSql解决方案的原因。我在previos项目中所做的非常简单。我不保留user-gt; wall user-&gt;历史记录,其中包含内存存储中的纯粹feed'ids(我最喜欢的是redis)。所以在每个插入中我做1个插入操作数据库和(n *读优化)插入操作在内存存储中。我设计了内存存储来优化我的读取。如果我想过滤视频的用户历史记录(或墙),我会将推送feedid放到像user :: {userid} :: wall :: videos这样的列表中。

当然,你可以在memstores中纯粹构建系统,但是很高兴有2个系统做他们正在做的最好的事情。

编辑: 检查这些应用程序以获得一个想法:

http://retwis.antirez.com/

http://twissandra.com/

答案 3 :(得分:2)

我正在阅读越来越多的关于NoSQL解决方案和人们提出它们的建议,但是没有人提到过这种选择的缺点。 对我来说最明显的是缺乏交易 - 想象一下,你不时会丢失一些记录(有些情况经常报告这种情况)。

但是,令我惊讶的是,没有人提到MySQL被用作NoSQL - here's a link for some reading

最后,无论您选择何种解决方案(关系数据库或NoSQL存储),它们都会以类似的方式扩展 - 通过跨网络分割数据(当然,有更多选择,但这是最明显的选择)。由于NoSQL的工作量较少(没有SQL层,所以CPU周期不会浪费在解释SQL上),所以速度更快,但它也可以达到顶峰。

正如Elad已经指出的那样 - 构建一个可以从一开始就可扩展的应用程序是一个痛苦的过程。你最好把时间花在让它变得流行然后再缩小它上面。

答案 4 :(得分:2)

我可能会首先使用规范化架构,以便您可以快速而紧凑地编写。然后使用非事务性(无锁定)读取将信息拉回来确保使用游标,以便您可以在返回结果时处理结果,而不是等待整个结果集。由于听起来信息没有任何特定的重要含义,因此您并不需要担心通常会使您远离事务性读取的问题锁定。