环境:
表格/数据库我来自:
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代码(请注意,NODES
和MATCHERS
是由jooq的代码生成包生成的),只有nodes
/ {{1表格很有意思。
NODES
表中的一行表示匹配事件;这里感兴趣的是nodes
,start_index
和end_index
列。保证level
小于或等于start_index
;至于end_index
列,它是匹配树中的深度,深度从0开始;也就是说,对于匹配路径level
中的某些匹配器c
,/a/b/c
&#39; s c
将为2。
现在,我想获得的结果如下:
给定一个行范围(10,25或50),返回一个映射,其中键是行号,值是该行的解析树的最大深度;应该只被视为当前对此行有效的匹配器
一个行以level
([start, end)
包含,start
独占)的间隔具体化。如果以下两个陈述都成立,则匹配器被视为对给定行有效:
现在,我如何解决这个问题:
end
语句组成的虚拟列,每行一个,检查匹配器是否对给定行有效;此列名为case
; line
并按select line, max(level)
分组,添加的条件是结束索引应该大于或等于第一行的起始索引,并且起始索引应该是严格小于最后一行的结束指数。代码:
line
如果我查询25行(即某些n的行n到n + 24),这个请求在2200万个表项的最繁忙部分大约需要15秒,但是有什么方法可以改进它吗? / p>
请注意,更改SQL引擎不是一个选项;这是一个GUI应用程序,数据库可以忘记&#34 ;;我并不想要一个完全成熟的&#34;安装RDBMS引擎!
答案 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