C# · 12月 30, 2021

c# – 需要数据库建议 – > Columnar,Embedded(如果可能)

编辑:作为迄今为止答案的结果,我喜欢添加更多的焦点,我喜欢零:一个数据库,允许写入内存(可以是简单的C#代码)与持久性存储选项,以访问数据从雷迪斯到目前为止看起来最有希望.我也考虑实际使用类似于Lockfree或ZeroMQ的东西,以避免将数据同时写入数据库,而是通过消息总线/其他实现发送所有被持久化的数据,并让一个“actor”处理所有的写入操作到内存数据库或其他解决方案.除了Redis(有些提到的sqlite和我还需要测试其性能)之外,还有其他的想法.任何其他建议?

我正在寻找满足我以下大部分要求的理想数据库结构/解决方案,但到目前为止,我完全失败了.你能帮忙吗

我的任务:我在.Net 4.5(C#)中运行一个进程,并生成(通常)我想用于其他应用程序进一步分析的值类型,因此要保留内存中或持久存储在磁盘上.更多以下.数据在不同的任务/线程内生成,因此基于行的数据格式本身不适合于匹配这种情况(因为在不同线程中生成的数据在不同时间生成,因此不对齐).因此,我认为一个柱状数据结构可能是合适的,但如果我错了,请更正我.

例:

任务/线程#1在给定的时间戳上生成以下数据

datetime.ticks /输出数据的值

1000000001 233.23

1000000002 233.34

1000000006 234.23

Taks / Thread#2在给定的时间戳上生成以下数据

datetime.ticks /输出数据的值

1000000002 33.32

1000000005 34.34

1000000015 54.32

我不需要在.Net运行时调整时间标记,在保留数据并在以后的R或Python中处理数据是首要的.

我的要求:

>快速写入,快速写入,快速写入:可能会发生每秒产生100,000,000个数据点,并需要持续(最坏情况)或保留内存中的数据.它可以在自己的线程上运行写入,所以这个过程可能滞后于数据生成过程,但限制是16gb RAM(64位代码),更多在下面.
>首选项是用于柱状数据库格式,因为它很好地适用于我以后如何查询数据,但如果对上述示例有意义,我可以使用任何其他结构(文档/键值也可以,如果所有其他满足要求,尤其是在写入速度方面).
>可以在.Net内引用的API.示例:HDF5可能被认为有能力,但我发现他们的.Net端口可怕.一些支持.Net一点更好会是一个加号,但如果所有其他要求都满足,那么我可以处理类似于HDF5 .Net端口.
>如果可能,并发写入:如前所述,我喜欢从不同的任务/线程同时写入数据.
>我受到16GB内存的限制(在64位运行.Net进程),因此我可能会寻找不纯内存的东西,因为有时可能会生成更多的数据.有时持续存在的内存或纯持久性模式可能更为可取.
>嵌入式的首选项,但如果客户端/服务器解决方案中的服务器可以作为Windows服务运行,那么没有问题.
>在数据访问方面,我非常喜欢一个数据库解决方案,因为R和Python的接口已经存在,因为我喜欢在Python中使用熊猫库进行时间序列比对和其他分析和运行分析.
>如果API /库支持sql / sql类似/ Linq / like的查询,这将是非常好的,但通常我只需要绝对的裸骨,如加载列数据在开始和结束日期之间(给定的“键”/索引是这样的格式),因为我在R / Python中分析和运行查询.
>如果它带有一个管理控制台或数据可视化,这将是一个加号,但不是必须的.
>应该在“达到”范围内开源或定价(不,KDB不符合条件;-)

好的,这里是我到目前为止,再次,我得到的一切,因为大多数db解决方案简单地失败了写性能要求:

> Infobright和Db4o.我喜欢我迄今为止所读的,但我承认我没有检查任何性能数据
>自己做的事情我可以轻松地以二进制格式存储值类型,并通过datetime.ticks对数据进行索引,我只需要以某种方式编写脚本来加载/反序列化Python / R中的数据.但是,如果我想添加并发,查询引擎和其他好处,这将是一项巨大的任务.所以我在那里寻找一些东西.

解决方法 我不能评论 – 低代表(我是新来的) – 所以你得到一个完整的答案,而不是…

首先,你确定你需要一个数据库吗?如果对R的快速写入速度和可移植性是您最大的担忧,那么您是否只考虑过平面文件机制?根据你的意见,你愿意批量写出,但你需要坚持;如果这些是我的要求,我会写一个快速缓冲的缓冲系统,然后构建一个单独的任务,定期将磁盘文件移动到R的数据存储中,只有当R读取档案首先还不够.

如果您可以在事后进行对齐,那么您可以将线程编写为主并行循环中的单独文件,每隔一段时间关闭每个文件,并将对齐和数据库加载到子进程.

所以(在crappy伪代码中),构建一个线程进程,你可以使用后台工作器或其他一些方法调用该进程,并且包括一个唯一标识每个工作器,从而每个filestream(任务/线程)的线程名字符串:

file_name = threadname + ‘0001.csv’ // or somethingopen(file_name for writing)while(generating_data) { generate_data() while (buffer_not_full and very_busy) { write_data_to_buffer generate_data() } flush_buffer_to_disk(file_name) if(file is big enough or enough time has passed or we’re not too busy) { close(file_name) move(file_name to bob’s folder) increment file_name open(file_name for writing) })

高效,快速的文件I / O和缓冲是a straightforward and common problem.没有什么会比这更快.那么你可以编写另一个进程来做数据库加载,而不是出现在那里的性能:

while(file_name in list of files in bob’s folder sorted by date for good measure){ read bob’s file load bob’s file to database align dates,make pretty}

我不会在C#中写这个部分,我会批量编写它,并使用数据库的本机加载程序,它将与从头构建的任何内容一样快.

如果您在同一硬件上运行,则必须确保这两个循环不会太多干扰.也就是说,以更高优先级运行任务线程,或者构建一些互斥体或性能限制器,以便数据库加载在线程运行时不会占用资源.我绝对会分离数据库服务器和硬件,以便平面文件的文件I / O不会受到影响.

如果你在Unix上,FIFO队列会工作,但是你不是.