有没有办法改善这个要求?

时间:2015-02-10 00:29:28

标签: java sql h2 jooq

环境:

  • Java 8;特别是,Oracle JDK 1.8u25;
  • h2作为SQL后端;
  • jooq for querying。

表格/数据库我来自:

private static final String H2_URI_PREFIX = "jdbc:h2:";
private static final String H2_URI_POSTFIX
    = ";LOG=0;LOCK_MODE=0;UNDO_LOG=0;CACHE_SIZE=131072";
private static final String H2_USERNAME = "sa";
private static final String H2_PASSWORD = "";

private static final List<String> H2_DDL = Arrays.asList(
   "create table matchers ("
        + " id integer not null,"
        + " class_name varchar(255) not null,"
        + " matcher_type varchar(30) not null,"
        + " name varchar(1024) not null"
        + ");",
    "create table nodes ("
        + " id integer not null,"
        + " parent_id integer not null,"
        + " level integer not null,"
        + " success integer not null,"
        + " matcher_id integer not null,"
        + " start_index integer not null,"
        + " end_index integer not null,"
        + " time long not null"
        + ");",
    "alter table matchers add primary key(id);",
    "alter table nodes add primary key(id);",
    "alter table nodes add foreign key (matcher_id)"
        + " references matchers(id)"
);

// ...

private void doDdl(final DSLContext jooq)
{
    H2_DDL.forEach(jooq::execute);

    jooq.createIndex("nodes_parent_id").on(NODES, NODES.PARENT_ID)
        .execute();
    jooq.createIndex("nodes_start_index").on(NODES, NODES.START_INDEX)
        .execute();
    jooq.createIndex("nodes_end_index").on(NODES, NODES.END_INDEX)
        .execute();
}

即使我在这里显示完整的DDL代码(请注意,NODESMATCHERS是由jooq的代码生成包生成的),只有nodes / {{1表格很有意思。

NODES表中的一行表示匹配事件;这里感兴趣的是nodesstart_indexend_index列。保证level小于或等于start_index;至于end_index列,它是匹配树中的深度,深度从0开始;也就是说,对于匹配路径level中的某些匹配器c/a/b/c&#39; s c将为2。

现在,我想获得的结果如下:

给定一个行范围(10,25或50),返回一个映射,其中键是行号,值是该行的解析树的最大深度;应该只被视为当前对此行有效的匹配器

一个行以level[start, end)包含,start独占)的间隔具体化。如果以下两个陈述都成立,则匹配器被视为对给定行有效:

  • 其起始索引严格小于行的结束索引;和
  • 其结束索引大于或等于该行的起始索引。

现在,我如何解决这个问题:

  • 我创建了一个由一系列SQL end语句组成的虚拟列,每行一个,检查匹配器是否对给定行有效;此列名为case;
  • 我做line并按select line, max(level)分组,添加的条件是结束索引应该大于或等于第一行的起始索引,并且起始索引应该是严格小于最后一行的结束指数。

代码:

line

如果我查询25行(即某些n的行n到n + 24),这个请求在2200万个表项的最繁忙部分大约需要15秒,但是有什么方法可以改进它吗? / p>

请注意,更改SQL引擎不是一个选项;这是一个GUI应用程序,数据库可以忘记&#34 ;;我并不想要一个完全成熟的&#34;安装RDBMS引擎!

1 个答案:

答案 0 :(得分:1)

我不太了解H2,但由于您的谓词将始终同时点击START_INDEX END_INDEX,因此最好创建索引两栏:

 jooq.createIndex("better_index")
     .on(NODES, NODES.START_INDEX, NODES.END_INDEX)
     .execute();

原因是SQL引擎只需要访问磁盘并扫描索引一次,因为谓词的所有相关信息都已包含在索引中。这将大大减少您的IO。

同样,不确定H2是否覆盖了这个(双关语),但是如果你还要将NODES.LEVEL添加到索引中,你就会有一个所谓的covering index,即一个索引包含此特定查询所需的所有数据,无需再次点击磁盘(对于MAX()函数):

 jooq.createIndex("covering_index")
     .on(NODES, 
         NODES.START_INDEX, 
         NODES.END_INDEX
         NODES.LEVEL)
     .execute();

Here's also a very interesting question about range queries on PostgreSQL