统计数据每天1000万次更新 - 我应该使用哪种DB / Cache系统?

时间:2015-02-02 10:13:51

标签: sql-server caching windows-server-2012 nosql

我目前在我的网站上遇到了性能问题。可以通过以下方式总结这种情况:

  • 它是使用SQL Server 2012 Express的.Net Mvc网站。它托管在Windows Server 2012上。
  • 核心系统每天有大约1000万次UPDATE查询(2个不同的表上有500万次),另外还有1000万次用于自定义统计目的(再次,2 * 5百万次)。
  • INSERT查询少得多。
  • MVC网站没有性能问题,大多数请求都是由1个方法处理,返回普通内容(不是html)。

由于统计数据不像核心系统那么重要,我看到SQL Server经历了很多困难,我认为将这些统计表移到其他地方可能会很好。

主要问题是:处理以更新为主的统计数据的最佳方法是什么?这个想法也是只保留一台服务器。

我试着看看如何改善现状:

  • 在另一个硬盘上为统计信息设置单独的SQL Server数据库?也许SQL Server可以更好地呼吸,但我不确定。
  • 使用NoSQL数据库?我只是对MongoDb有一点小经验(但不是数百万的请求),我很想尝试RavenDB。
  • 使用缓存系统? Redis看起来很棒,但我不确定在Windows上运行它是个好主意。 AppFabric是一个可行的选择吗?

对于当前形势的任何相关想法将不胜感激 谢谢

以下是有关我所拥有的统计表的更多信息:

TABLE [dbo].[UserStat](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserId] [int] NOT NULL,
[Hits] [int] NOT NULL,
[Points] [decimal](38, 6) NOT NULL,
[Date] [datetime] NOT NULL,
[LastHit] [datetime] NOT NULL,
[Ip] [varchar](256) NULL,
)

我像这样更新统计数据:

UPDATE [UserStat] SET Hits = Hits + 1, Points = Points + @Points, LastHit = @Last WHERE UserId = @Id AND [Ip] = @Ip AND [Date] = @Date

如果当前用户和日期的行不存在,我创建它:

INSERT INTO [UserStat] ([UserId],[Hits],[Points],[Date],[LastHit],[Ip]) VALUES (@UserId,@Hits,@Points,@Date,@LastHit,@Ip)

有两个指数:

  • 1表示主键
  • 1用于获取和汇总用户的统计信息

    INDEX [Select_UpdateUserStatNavigation] ON [dbo].[UserStat](
    [UserId] ASC,[Date] ASC) INCLUDE ([Id],[Hits],[Points], [LastHit],[Ip])
    

服务器是VPS。日志和数据文件位于同一磁盘上。桌子上没有涉及外键。

以下是我发现查询此表的所有SELECT查询:

SELECT Points, Hits, [Date] FROM [UserStat] WHERE UserId = @UId AND [Date] >= @date

SELECT Ip FROM [UserStat] WHERE UserId = @UId AND LastHit >= DATEADD(MINUTE,-15,getdate())

SELECT COUNT(Id) FROM [UserStat] WHERE [LastHit] >= DATEADD(MINUTE,-15,getdate())

但我并不是真的担心SELECT,更多关于UPDATE的数量^^。

4 个答案:

答案 0 :(得分:2)

这是一个非常简单的好例子,适用于NoSql数据库。 NoSql是为" web-scale"诸如此类的应用程序,数据的速度和数量只会超过SQL数据库跟上的能力(关系型DBMS的一大弱点)。

实际上,常规SQL不适合您的场景。这有几个原因,包括:

  1. SQL对于处理关系数据很有用。这里的数据没有真正的关系或依赖关系(至少,不是你所描述的),实际上,即使是适度复杂的实际数据集也可以更好地非规范化并放入NoSql平台。
  2. SQL引入了大量的开销。简单地运行查询以从数据库中获取单个值的成本至少是NoSql数据存储区的3-5倍,这是由于查询解释,查找索引,查询索引,提取值等等,其中NoSql数据存储区只需一步即可获得记录。
  3. SQL数据库的设计主要是为了高度一致。这意味着它们通常不能驻留在多台计算机上(虽然这不再是完全正确的),并且它们还有额外的开销来确保数据保持一致。
  4. 现在,让我们看看你的特定用例:

    1. 大量更新事务,偶尔插入。大多数NoSql数据库平台使用Set操作,根据需要更新或插入。每次都不需要运行两个语句。

    2. 单个主键。 NoSql数据库是键值存储,其中键(在本例中为UserId)指向数据库中的单个记录。

    3. 简单的统计信息和索引。几个NoSql数据库提供内置的索引功能,有些甚至允许您对数据执行map-reduce以获取详细的统计信息。其他人自动进行数据聚合,您可以编写特殊查询来获取所需的数据。在这种情况下,您的" Stat Id"字段是无用的,可以删除(yay,更少的存储空间!)。

    4. 快速且可扩展。这是您无法与SQL数据库联系的内容。 NoSQL就是为此而设计的。

    5. 鉴于上述情况,您的方案是一个教科书示例,说明何时应用NoSql解决方案。我可以推荐Couchbase,这是一个非常快速的内存数据库,基于磁盘存储(一次性满足您的缓存和数据存储要求)。您也可以考虑将Elasticsearch用于统计信息存储,因为它可以开箱即用地执行一些非常好的数据聚合。无论您选择哪种NoSql解决方案,您都将获得灵活的可扩展性和易维护性。我敢说你成为一名全职DBA的日子将会结束。

答案 1 :(得分:1)

您能否确认ID是您的主键?如果是这样,那么这将是好的,因为它是单调增加的值并且对于插入物是有益的。我认为您的其他索引(出于更新目的)应为

INDEX [Select_UpdateUserStatNavigation] ON [dbo].[UserStat](
[UserId] ASC,[IP] ASC, [Date] ASC). 

确保列在索引中从最具选择性到最少选择性排序。这可以加快更新,因为行可以更快地定位。我们稍后可以查看SELECT的索引。

BY VPS,您的意思是它是虚拟服务器吗?我会看看你的IO统计数据来检查IO不是瓶颈。为SQL分配了多少内存?这可能是另一个问题。内存不足可能导致分页到磁盘 - 这是IO子系统中最慢的部分。

如果可能的话,我会看一下将日志和数据磁盘拆分到不同的磁盘上。将它们放在同一磁盘上会导致磁盘争用 - 再次出现在IO子系统中最慢的部分。

您可以发布使用的选择查询吗?如果需要,我可以给出建议的索引。

此外,您可能希望用以下的MERGE替换单独的插入和更新过程。

MERGE UserStat AS TargetTable
USING (SELECT @UserId UserID,@Hits Hits,@Points Points,@Date [Date],@LastHit LastHit,@Ip Ip) AS SourceData
ON SourceData.UserID = TargetTable.UserID 
    AND SourceData.IP = TargetTable.IP 
    AND SourceData.[Date] = TargetTable.[Date])
WHEN MATCHED THEN UPDATE SET Hits = Hits + 1, Points = Points + SourceData.Points, LastHit = SourceData.LastHit 
WHEN NOT MATCHED THEN INSERT (UserID,Hits,Points,[Date],LastHit,Ip)
                 VALUES(SourceData.UserID,SourceData.Hits,SourceData.Points,SourceData.[Date],SourceData.LastHit,SourceData.Ip)

答案 2 :(得分:0)

RavenDB在这种情况下非常容易启动和运行。您将获得快速写入和可能的快速读取。您也可以获得ACID或尽可能接近ACID。 RavenDB易于在MVC中连接。由于您拥有Mongo经验,因此文档的概念对您来说不应该是陌生的。在MVC应用程序中使用RavenDB C#客户端库,几个小时内就可以取得重大进展。请确保您了解这些限制。默认情况下,查询可能比更新后几微秒,并且像许多NoSql或CQRS解决方案一样,如果您清除查询的缓存,可能需要几分钟到几个小时才能完全重建缓存。

答案 3 :(得分:-1)

在遇到主要问题之前,必须进行一些更改:

您应该从Express版迁移到企业版或至少标准版(Express vs others

由于您对数据进行了大量更新,因此应禁用索引(如果有)

尝试重新调整表格列的大小,这样您的记录单元格可以存储在较少的页面中,这将有助于您的更新过程加速(例如,如果您有一个包含20列的表格,并且您始终更新只修复了5个已知列,然后将这5列与其他15列分开。这可以帮助您在较少的页面中排列数据,当您的页面较少时,您可以更快地找到您的记录。粗略的这不是基于正常形式,但它可以帮助您的表现)

看看你的可用内存和CPU。这两者是表现的基石。

关于你的主要问题,我需要了解更多关于你的统计数据及其表格以及它的用法。你的意思是sql server statistics,还是你的意思?