在h2数据库(v1.4.195)中的空表上重复选择*有多糟糕?

时间:2018-01-17 13:44:45

标签: h2 h2db

所以我有一个h2数据库事件表,我正在监视事件。有一个线程每2秒触发一次,并使用select * from eventTable limit 10 offset 0进行检查。

我想知道这个锤击在h2数据库表中的性能影响是什么。它是基于B树的,但db本身是一个文件。 h2db是否转到文件并且必须读取块,以确定表是否为空。考虑使用Oracle Db和高水位标记来查询具有大行的表,这些表稍后会被删除而不会截断,这会导致不必要的块读取以获得select * done并且对性能不利。

如果这一点很糟糕,建议使用此qt here中描述的插入操作的Trigger方法更换线程部分。

此致

1 个答案:

答案 0 :(得分:0)

以下是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连接参数执行技巧,查询在内存中,因此从空表中选择*的开销非常小。这结束了对我的调查。数据在内存中,因为我正在使用版本1.4.195并且默认使用MVStore数据库。所以在内存中查询一个空表应该是一个相对便宜的操作。

此致