你的应用程序似乎具有与我的相同的特征。我编写了一个MySQL自定义存储引擎来高效地解决这个问题,可以在
这里找到相关描述。
想象一下,你的数据在磁盘上按照2M固定长度条目的数组布局(每个实体一个)排列,每个条目包含3650行(每天一个)20字节(每个实体每天一行)。
你的读取模式读取一个实体。它在磁盘上是连续的,因此需要1次寻道(大约8毫秒),并且以大约100MB /秒的速度读取3650x20=大约80K…因此可以在几秒钟内完成,轻松满足你每秒1个查询的读取模式。
更新必须在磁盘上的2M个不同位置中写入20字节。在最简单的情况下,这将需要2M次寻道,每次寻道需要大约8毫秒,因此需要2M * 8ms = 4.5小时。如果你将数据分散到4个“raid0”磁盘中,则可能需要1.125小时。
但是这些位置之间只有80K的距离。这意味着16MB块(典型磁盘缓存大小)中有200个这样的位置,因此它可以以高达200倍的速度运行。(1分钟)实际情况介于两者之间。
我的存储引擎基于这种哲学运作,尽管它比固定长度数组更通用。
你可以编写我所描述的代码。将代码放入MySQL可插拔存储引擎中意味着你可以使用MySQL查询数据,并使用各种报表生成器等工具。
顺便说一下,你可以从存储的行中删除日期和实体ID(因为它们是数组索引),如果你不需要唯一ID,则可以删除它-因为(实体ID,日期)是唯一的,并将2个值存储为3字节整数。然后你的存储行是6个字节,每16M有700次更新,因此插入更快,文件更小。
编辑与平面文件比较
我注意到评论普遍支持平面文件。不要忘记,目录只是由文件系统实现的索引,它们通常针对相对较少的相对较大的项目进行优化。访问文件通常会进行优化,因此它期望打开相对较少的文件,并且对于每个打开的文件都具有相对较高的开销。所有这些“相对”都是相对于数据库的典型用法而言的。
使用文件系统名称作为实体ID的索引是违反直觉的。在编程中,例如,你将使用数组而不是哈希表,并且你不可避免地会遭受昂贵访问路径的大量开销,它可以简单地是一个数组索引操作。
因此,如果您使用平面文件,为什么不只使用
一个平面文件并对其进行索引呢?
关于性能的
编辑
该应用程序的性能将受到磁盘搜索时间的支配。我上面做的计算确定了您可以做到的最好水平(尽管您可以通过减慢SELECT来加快INSERT - 您不能使它们都更好)。无论您是使用数据库、平面文件还是一个平面文件,
除非您可以添加更多不需要的查找并进一步减慢速度。例如,索引(无论是文件系统索引还是数据库索引)与“数组查找”相比会导致额外的I/O,并且这些操作会减慢您的速度。
有关基准测试测量的
编辑
我有一个表格看起来与您的非常相似(或几乎完全类似于您的某个分区)。它有64K实体而不是2M(是您的1/32),以及2788个“天”。该表格按照与您的相同的INSERT顺序创建,并具有相同的索引(entity_id,day)。选择单个实体需要20.3秒来检查2788天,预期大约需要130个寻道每秒(在平均寻道时间为8毫秒的磁盘上)。SELECT时间将与天数成比例,而与实体数量无关(在寻道时间更快的磁盘上速度会更快。我正在使用一对SATA2 RAID0,但这并没有太大的区别)。
如果您将表格重新排序为实体顺序
ALTER TABLE x ORDER BY (ENTITY,DAY)
那么同样的SELECT需要198毫秒(因为它是在单个磁盘访问中读取实体顺序)。
但是ALTER TABLE操作花费了13.98天才能完成(用于182M行)。
测量还告诉您其他几件事情:
1. 您的索引文件将与数据文件一样大。对于此示例表,它为3GB。这意味着(在我的系统上)所有索引都以磁盘速度而非内存速度运行。
2. 您的INSERT速率将对数下降。数据文件的插入是线性的,但键的插入是对数的。在180M条记录时,我每秒得到153个INSERT,这也非常接近寻道速率。它显示MySQL几乎为每个INSERT更新一个叶索引块(因为它是按实体索引但按天顺序插入的)。因此,您要花费2M / 153秒= 3.6小时来完成每天的2M行插入。(除以您可以通过系统或磁盘分区获得的任何效果)。