H2数据库性能陌生---或者如何高效`count(*)`

时间:2017-02-09 09:05:18

标签: database h2

设置不可能更简单:

  • H2版本1.3.176
  • 一个表,10列,其中两列有点冗长,300和3500个字符是典型值长度
  • 简单查询:select count(*) from requestrepository where request_type = 'ADD'
  • 索引位于查询列中。
  • 查询的列只是varchar(20)(即不是较长的列之一)
  • 查询列只包含两个不同的值,一个出现200k次,另一个出现1200万次。
  • DB运行SSD,当前服务器硬件,当前Java 8(稍有不同但结果没有变化)

我做什么:(0)运行analyze,(1)通过键字段删除一行,(2)为刚刚删除的键插入一行,(3)运行上面引用的查询,计数到10并重复。

我看到的内容:上面提到的查询每次需要3到5秒,explain analyze说:

SELECT
    COUNT(*)
FROM PUBLIC.REQUESTREPOSITORY
    /* PUBLIC.IX_REQUESTS: REQUEST_TYPE = 'ADD' */
    /* scanCount: 12098748 */
WHERE REQUEST_TYPE = 'ADD'
/*
REQUESTREPOSITORY.IX_REQUESTS read: 126700
*/

我在不同的机器上尝试了相同的数据库,硬件/ linux / ssd,VM / Windows / netapp,但趋势总是一样:count(*)也需要(?)长。

这是我不确定的。可以预料这需要很长时间吗?我原以为至少在第二轮中,缓存已经填满了,而且速度要快得多,但explain analyze总是列出126700个读取。

有关H2参数或设置如何改进的任何提示均值得赞赏。

编辑(不确定这是否应该作为答案) 与此同时,我们尝试了很多东西,包括mvstore,1.4.x,并行线程,具有不同磁盘的计算机,Linux,Windows。情况总是一样的。占用10或1200万行,一个varchar列,其中包含三个状态值,例如PROCESSING,ADD,DELETE,列上的索引和一个严重过多的状态:然后count(*) where colname='ADD'之类的内容需要1到几秒之后每次更新表格。

为了防止这种情况造成问题,我们最终修复了我们自己的代码,该代码执行了三个count(*),每个状态一个,而不是一个group by,并且每5秒运行一次而不是随需应变。当然不是我们最好的设计。

我唯一的理由是,我仍然感到惊讶的是count(*)在这样的设置中需要很长时间。我的预感是必须通过在更新后真正计数来计算索引的计数,而我预计计数可以在某处读取数据结构。 (没有批评,我自己肯定无法实现数据库。)

1 个答案:

答案 0 :(得分:0)

不确定H2,但您是否尝试过COUNT(request_type)而不是COUNT(*)

SQL标准的COUNT(*)往往需要很长时间才能进行计算,因为它需要全表扫描来过滤掉仅包含NULL值的行。

在单个索引列上使用COUNT()可以加快速度。这样就不需要读取表行了,因为索引足以决定列的值是否为NULL。