我们的Measurement实体类是持有单一度量的类,如下所示:
public class Measurement { public virtual Guid Id { get; private set; } public virtual Device Device { get; private set; } public virtual Timestamp Timestamp { get; private set; } public virtual IList<VectorValue> Vectors { get; private set; } }
向量值存储在单独的表中,以便它们中的每一个通过外键引用其父测量.
我们已经做了几件事情来确保生成的sql(合理)的效率:我们使用Guid.Comb来生成ID,我们在单个事务中刷新大约500个项目,ADO.Net批量大小设置为100(I认为sqlIte不支持批量更新,但稍后可能会有用.
问题
现在我们可以每秒插入150-200个测量(这不够快,尽管这是我们正在讨论的sqlite).看看生成的sql,我们可以看到,在单个事务中,我们插入(如预期的):
> 1个时间戳
> 1测量
> 8个矢量值
这意味着我们实际上在做多10倍的单表插入:1500-2000每秒.
如果我们将所有(所有8个向量值和时间戳)都放入测量表(添加9个专用列)中,似乎可以将插入速度提高10倍.
切换到sql服务器将提高性能,但是我们想知道是否有可能避免与数据库组织方式相关的不必要的性能成本.
[编辑]
使用内存中的sqlite我可以获得约350个项目/秒(3500个单表插入),我相信与NHibernate一样好(参考这篇文章:http://ayende.com/Blog/archive/2009/08/22/nhibernate-perf-tricks.aspx).
但是我也可以切换到sql服务器并停止假设事情,对吧?一旦我测试,我会更新我的帖子.
[更新]
我已经转移到sql服务器并平整了我的层次结构,我通过存储3000个测量/秒来测试它几个小时,似乎工作正常.
解决方法
基本上,您的理想情况可能是拥有一个单独的数据库(或者甚至只需在同一个数据库中分离表,如果需要),将数据采集作为一个完全独立的事项,将其以需要处理的格式它.
这并不意味着您需要丢弃您在当前数据库结构周围创建的实体:只要您也应该创建这些非规范化表并使其成为一个ETL.您可以使用SSIS(尽管它仍然是相当错误和易怒)将数据定期进入您的标准化表,甚至是C#应用程序或其他批量加载过程.
编辑:这是假设,当然,您的分析不需要实时完成:只是数据的收集.人们通常不需要(有时甚至不愿意)实时更新分析数据.这是在纸上听起来不错的东西之一,但实际上是没有必要的.
如果有些分析这些数据的人需要实时访问,那么您可以根据需要构建一个针对“裸机”非规范化事务数据的工具集,但是当您真正了解需求时,您可以非常频繁地执行分析,不需要真正的实时(在某些情况下,他们更喜欢使用更静态的数据集!):在这种情况下,定期的ETL可以运行得很好.你只需要与目标用户聚在一起,找出真正需要的内容.