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

xan*_*rus 5 mysql database database-design scalability query-optimization

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

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

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

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

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

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

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

Ela*_*lad 14

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

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

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

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

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

  • +1让数百万用户担心扩展,而不是构建一个很少人使用的可扩展应用程序. (4认同)

Gar*_*een 7

您可以选择许多选项

  • 添加更多硬件,内存,CPU - 进入云托管
  • 有24GB的内存声音?大多数重要访问的数据库信息都可以只适合内存.
  • 选择具有可扩展SSD的主机.
  • 在应用程序中使用基于事件的系统来编写所有用户的"历史记录".因此,它会像这样:id, user_id, event_name, date, event_parameters'-一个例子是:1, 8, CHANGED_PROFILE_PICTURE, 26-03-2011 12:34, <id of picture>最重要的是,此表将在内存中.不再需要担心写性能.记录经过3天之后,如果用户选择返回那么远,它们可以被清除到另一个表(非内存中)并包含在查询结果中.通过将所有这些放在一个表中,您可以删除必须执行多个查询和SELECT以构建此信息.
  • 考虑将INNODB用于history/feeds表.

阅读的好资源


小智 2

我可能会从使用规范化模式开始,以便您可以快速而紧凑地编写。然后使用非事务性(无锁定)读取将信息拉出,确保使用游标,以便您可以在结果返回时对其进行处理,而不是等待整个结果集。由于听起来这些信息没有任何特别的关键含义,因此您实际上不需要担心通常会阻止您进行事务性读取的问题锁定。