以下是来自 io 监控的一些数字:
我使用 select 语句启动了具有监视线程的应用程序。然后我开始“sudo fsusage MYPID”。具有 4 次读取和 2 次写入的模式重复自身:
16:18:10.809774 pread F=44 B=0x400 O=0x00037000 0.000020 java.11010
16:18:10.809809 pread F=44 B=0x400 O=0x00037000 0.000005 java.11010
16:18:10.809825 pread F=44 B=0x400 O=0x00037000 0.000003 java.11010
16:18:10.809839 pread F=44 B=0x400 O=0x00037000 0.000004 java.11010
16:18:10.810044 pwrite F=44 B=0x1000 O=0x00031000 0.000034 java.11010
16:18:10.810087 pwrite F=44 B=0x2000 O=0x00000000 0.000010 java.11010
FD是文件描述符,是通过lsof -p PID确认为数据库文件的。B = 读取或写入的字节数。O 是文件中的偏移量。
我经常看到上述读写模式。读取很可能是选择。DB 上没有其他活动。因此,即使对于空表,我也会持续读取 1600 字节的内容,并在 3000 到 4000 字节的范围内进行 2 次写入。
但是比我更详细地介绍,因为我在 macosx 上,strace 不是一个选项,但 Dtruss 工作得很好。所以只是给了 dtruss -a -p PID 并且以下是读取和写入的相关输出:
632/0x653a: 2229289 37 24 pread(0x2C, "chunk:3157,block:31,len:2,map:9,max:1540,next:4d,pages:6,root:c55c0000027cf,time:18ffdc4,version:3157 \n\0", 0x400, 0x31000) = 1024 0
632/0x652c: 773689 86 2 gettimeofday(0x70000B107C68, 0x0, 0x0) = 0 0
632/0x653a: 2229327 13 5 pread(0x2C, "chunk:3157,block:31,len:2,map:9,max:1540,next:4d,pages:6,root:c55c0000027cf,time:18ffdc4,version:3157 \n\0", 0x400, 0x31000) = 1024 0
632/0x653a: 2229347 10 4 pread(0x2C, "chunk:3157,block:31,len:2,map:9,max:1540,next:4d,pages:6,root:c55c0000027cf,time:18ffdc4,version:3157 \n\0", 0x400, 0x31000) = 1024 0
632/0x653a: 2229373 11 4 pread(0x2C, "chunk:3157,block:31,len:2,map:9,max:1540,next:4d,pages:6,root:c55c0000027cf,time:18ffdc4,version:3157 \n\0", 0x400, 0x31000) = 1024 0
632/0x653a: 2229621 45 34 pwrite(0x2C, "chunk:3159,block:24,len:1,map:9,max:b80,next:35,pages:4,root:c5640000027cf,time:19001ef,version:3159 \n\0", 0x1000, 0x24000) = 4096 0
632/0x653a: 2229686 32 24 pwrite(0x2C, "H:2,block:24,blockSize:1000,chunk:3159,created:1610362b746,format:1,version:3159,fletcher:1d05a51e\n\0", 0x2000, 0x0) = 8192 0
因此,在 pread 和 pwrite 的返回值之上添加我可以看到实际读取为 1024 x 4 字节,写入为 4096 + 8192 字节。还可以看到读取和写入的内容。最后一次写入有时会出现,有时不会。fread 和 fwrite 的第一个参数是文件描述符 0x2c,它与数据库文件的描述符相匹配。第二个参数是正在写入的缓冲区。我想知道为什么我们需要在这里写任何东西。但是当我在 h2 项目页面中阅读以下架构解释时,这得到了解释:
上面的写和读可以通过h2database.com/html/mvstore.html#fileFormat来解释
浏览源代码,我发现我在分析器中注意到的 BackgroundWriterThread 类以及随着时间的推移不断增加字节(但没有内存泄漏,它会正确清理),每秒都会醒来,只是盲目地提交存储。这给出了上面代码中写入和读取的位置。
更多谷歌搜索揭示了这个问题在谷歌组中讨论过,尽管没有解决方案出现,除非后来有人发布参数 WRITE_DELAY 为他解决了问题。groups.google.com/forum/#!searchin/h2-database/... 然后我想知道他是否没有尝试将连接时的 autoCommit 设置为 false。我试过了,上面的读写模式为我停止了。
因此,将 ;AUTOCOMMIT=OFF 添加到连接参数就可以解决问题,并且查询在内存中,因此 select * from a empty table 的开销非常小。这结束了我的调查。数据在内存中,因为我使用的是版本 1.4.195,并且默认使用 MVStore 数据库。所以查询内存中的空表应该是一个相对便宜的操作。
问候