Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
68032a31
提交
68032a31
authored
11月 24, 2015
作者:
S.Vladykin
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
added more tests
上级
4232718e
隐藏空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
136 行增加
和
46 行删除
+136
-46
JoinBatch.java
h2/src/main/org/h2/table/JoinBatch.java
+36
-26
TableFilter.java
h2/src/main/org/h2/table/TableFilter.java
+21
-17
TestTableEngines.java
h2/src/test/org/h2/test/db/TestTableEngines.java
+79
-3
没有找到文件。
h2/src/main/org/h2/table/JoinBatch.java
浏览文件 @
68032a31
...
@@ -374,14 +374,13 @@ public final class JoinBatch {
...
@@ -374,14 +374,13 @@ public final class JoinBatch {
*/
*/
public
static
IndexLookupBatch
createViewIndexLookupBatch
(
ViewIndex
viewIndex
)
{
public
static
IndexLookupBatch
createViewIndexLookupBatch
(
ViewIndex
viewIndex
)
{
Query
query
=
viewIndex
.
getQuery
();
Query
query
=
viewIndex
.
getQuery
();
query
.
prepareJoinBatch
();
if
(
query
.
isUnion
())
{
if
(
query
.
isUnion
())
{
ViewIndexLookupBatchUnion
unionBatch
=
new
ViewIndexLookupBatchUnion
(
viewIndex
);
ViewIndexLookupBatchUnion
unionBatch
=
new
ViewIndexLookupBatchUnion
(
viewIndex
);
return
unionBatch
.
hasBatchedQueries
()
?
unionBatch
:
null
;
return
unionBatch
.
initialize
()
?
unionBatch
:
null
;
}
}
JoinBatch
jb
=
((
Select
)
query
).
getJoinBatch
();
JoinBatch
jb
=
((
Select
)
query
).
getJoinBatch
();
if
(
jb
==
null
)
{
if
(
jb
==
null
||
jb
.
getLookupBatch
(
0
)
==
null
)
{
// our sub-query is not batched
, will run usual wa
y
// our sub-query is not batched
or is top batched sub-quer
y
return
null
;
return
null
;
}
}
assert
!
jb
.
batchedSubQuery
;
assert
!
jb
.
batchedSubQuery
;
...
@@ -389,6 +388,16 @@ public final class JoinBatch {
...
@@ -389,6 +388,16 @@ public final class JoinBatch {
return
jb
.
viewIndexLookupBatch
(
viewIndex
);
return
jb
.
viewIndexLookupBatch
(
viewIndex
);
}
}
/**
* Create fake index lookup batch for non-batched table filter.
*
* @param filter the table filter
* @return fake index lookup batch
*/
public
static
IndexLookupBatch
createFakeIndexLookupBatch
(
TableFilter
filter
)
{
return
new
FakeLookupBatch
(
filter
);
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
"JoinBatch->\nprev->"
+
(
current
==
null
?
null
:
current
.
prev
)
+
return
"JoinBatch->\nprev->"
+
(
current
==
null
?
null
:
current
.
prev
)
+
...
@@ -410,10 +419,8 @@ public final class JoinBatch {
...
@@ -410,10 +419,8 @@ public final class JoinBatch {
this
.
filter
=
filter
;
this
.
filter
=
filter
;
this
.
id
=
filter
.
getJoinFilterId
();
this
.
id
=
filter
.
getJoinFilterId
();
this
.
join
=
join
;
this
.
join
=
join
;
if
(
lookupBatch
==
null
&&
id
!=
0
)
{
lookupBatch
=
new
FakeLookupBatch
(
filter
);
}
this
.
lookupBatch
=
lookupBatch
;
this
.
lookupBatch
=
lookupBatch
;
assert
lookupBatch
!=
null
||
id
==
0
;
}
}
private
void
reset
()
{
private
void
reset
()
{
...
@@ -913,34 +920,37 @@ public final class JoinBatch {
...
@@ -913,34 +920,37 @@ public final class JoinBatch {
protected
ViewIndexLookupBatchUnion
(
ViewIndex
viewIndex
)
{
protected
ViewIndexLookupBatchUnion
(
ViewIndex
viewIndex
)
{
super
(
viewIndex
);
super
(
viewIndex
);
collectJoinBatches
(
viewIndex
.
getQuery
());
}
}
private
boolean
hasBatchedQueries
()
{
private
boolean
initialize
()
{
return
joinBatches
!=
null
;
return
collectJoinBatches
(
viewIndex
.
getQuery
())
&&
joinBatches
!=
null
;
}
}
private
void
collectJoinBatches
(
Query
query
)
{
private
boolean
collectJoinBatches
(
Query
query
)
{
if
(
query
.
isUnion
())
{
if
(
query
.
isUnion
())
{
SelectUnion
union
=
(
SelectUnion
)
query
;
SelectUnion
union
=
(
SelectUnion
)
query
;
collectJoinBatches
(
union
.
getLeft
());
return
collectJoinBatches
(
union
.
getLeft
())
&&
collectJoinBatches
(
union
.
getRight
());
collectJoinBatches
(
union
.
getRight
());
}
Select
select
=
(
Select
)
query
;
JoinBatch
jb
=
select
.
getJoinBatch
();
if
(
jb
==
null
)
{
onlyBatchedQueries
=
false
;
}
else
{
}
else
{
Select
select
=
(
Select
)
query
;
if
(
jb
.
getLookupBatch
(
0
)
==
null
)
{
JoinBatch
jb
=
select
.
getJoinBatch
();
// we are top sub-query
if
(
jb
==
null
)
{
return
false
;
onlyBatchedQueries
=
false
;
}
}
else
{
assert
!
jb
.
batchedSubQuery
;
assert
!
jb
.
batchedSubQuery
;
jb
.
batchedSubQuery
=
true
;
jb
.
batchedSubQuery
=
true
;
if
(
joinBatches
==
null
)
{
if
(
joinBatches
==
null
)
{
joinBatches
=
New
.
arrayList
();
joinBatches
=
New
.
arrayList
();
filters
=
New
.
arrayList
();
filters
=
New
.
arrayList
();
}
filters
.
add
(
jb
.
filters
[
0
]);
joinBatches
.
add
(
jb
);
}
}
filters
.
add
(
jb
.
filters
[
0
]);
joinBatches
.
add
(
jb
);
}
}
return
true
;
}
}
@Override
@Override
...
...
h2/src/main/org/h2/table/TableFilter.java
浏览文件 @
68032a31
...
@@ -20,6 +20,7 @@ import org.h2.index.Index;
...
@@ -20,6 +20,7 @@ import org.h2.index.Index;
import
org.h2.index.IndexLookupBatch
;
import
org.h2.index.IndexLookupBatch
;
import
org.h2.index.IndexCondition
;
import
org.h2.index.IndexCondition
;
import
org.h2.index.IndexCursor
;
import
org.h2.index.IndexCursor
;
import
org.h2.index.ViewIndex
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.result.Row
;
import
org.h2.result.Row
;
import
org.h2.result.SearchRow
;
import
org.h2.result.SearchRow
;
...
@@ -368,6 +369,14 @@ public class TableFilter implements ColumnResolver {
...
@@ -368,6 +369,14 @@ public class TableFilter implements ColumnResolver {
joinBatch
=
null
;
joinBatch
=
null
;
joinFilterId
=
-
1
;
joinFilterId
=
-
1
;
IndexLookupBatch
lookupBatch
=
null
;
IndexLookupBatch
lookupBatch
=
null
;
if
(
getTable
().
isView
())
{
session
.
pushSubQueryInfo
(
masks
,
filters
,
filter
,
select
.
getSortOrder
());
try
{
((
ViewIndex
)
index
).
getQuery
().
prepareJoinBatch
();
}
finally
{
session
.
popSubQueryInfo
();
}
}
// For globally top table filter we don't need to create lookup batch, because
// For globally top table filter we don't need to create lookup batch, because
// currently it will not be used (this will be shown in ViewIndex.getPlanSQL()). Probably
// currently it will not be used (this will be shown in ViewIndex.getPlanSQL()). Probably
// later on it will make sense to create it to better support X IN (...) conditions,
// later on it will make sense to create it to better support X IN (...) conditions,
...
@@ -376,7 +385,7 @@ public class TableFilter implements ColumnResolver {
...
@@ -376,7 +385,7 @@ public class TableFilter implements ColumnResolver {
// in turn is not top in outer query, thus we need to enable batching here to allow
// in turn is not top in outer query, thus we need to enable batching here to allow
// outer query run batched join against this sub-query.
// outer query run batched join against this sub-query.
if
(
jb
==
null
&&
select
!=
null
&&
!
isAlwaysTopTableFilter
(
filter
))
{
if
(
jb
==
null
&&
select
!=
null
&&
!
isAlwaysTopTableFilter
(
filter
))
{
lookupBatch
=
createLookupBatch
(
filters
,
filter
);
lookupBatch
=
index
.
createLookupBatch
(
this
);
if
(
lookupBatch
!=
null
)
{
if
(
lookupBatch
!=
null
)
{
jb
=
new
JoinBatch
(
filter
+
1
,
join
);
jb
=
new
JoinBatch
(
filter
+
1
,
join
);
}
}
...
@@ -387,28 +396,23 @@ public class TableFilter implements ColumnResolver {
...
@@ -387,28 +396,23 @@ public class TableFilter implements ColumnResolver {
}
}
joinBatch
=
jb
;
joinBatch
=
jb
;
joinFilterId
=
filter
;
joinFilterId
=
filter
;
if
(
lookupBatch
==
null
&&
!
isAlwaysTopTableFilter
(
filter
))
{
if
(
lookupBatch
==
null
)
{
// createLookupBatch will be called at most once because jb can be
boolean
notTop
=
!
isAlwaysTopTableFilter
(
filter
);
// created only if lookupBatch is already not null from the call above.
if
(
notTop
||
getTable
().
isView
())
{
lookupBatch
=
createLookupBatch
(
filters
,
filter
);
// createLookupBatch will be called at most once because jb can be
// created only if lookupBatch is already not null from the call above.
lookupBatch
=
index
.
createLookupBatch
(
this
);
if
(
lookupBatch
==
null
&&
notTop
)
{
// the index does not support lookup batching, need to fake it because we are not top
lookupBatch
=
JoinBatch
.
createFakeIndexLookupBatch
(
this
);
}
}
}
}
jb
.
register
(
this
,
lookupBatch
);
jb
.
register
(
this
,
lookupBatch
);
}
}
return
jb
;
return
jb
;
}
}
private
IndexLookupBatch
createLookupBatch
(
TableFilter
[]
filters
,
int
filter
)
{
if
(
getTable
().
isView
())
{
session
.
pushSubQueryInfo
(
masks
,
filters
,
filter
,
select
.
getSortOrder
());
try
{
return
index
.
createLookupBatch
(
this
);
}
finally
{
session
.
popSubQueryInfo
();
}
}
return
index
.
createLookupBatch
(
this
);
}
public
int
getJoinFilterId
()
{
public
int
getJoinFilterId
()
{
return
joinFilterId
;
return
joinFilterId
;
}
}
...
...
h2/src/test/org/h2/test/db/TestTableEngines.java
浏览文件 @
68032a31
...
@@ -489,15 +489,15 @@ public class TestTableEngines extends TestBase {
...
@@ -489,15 +489,15 @@ public class TestTableEngines extends TestBase {
stat
.
execute
(
"CREATE INDEX T_IDX_B ON t(b)"
);
stat
.
execute
(
"CREATE INDEX T_IDX_B ON t(b)"
);
setBatchSize
(
t
,
3
);
setBatchSize
(
t
,
3
);
for
(
int
i
=
0
;
i
<
20
;
i
++)
{
for
(
int
i
=
0
;
i
<
20
;
i
++)
{
stat
.
execute
(
"insert into t values ("
+
i
+
","
+
i
+
")"
);
stat
.
execute
(
"insert into t values ("
+
i
+
","
+
(
i
+
10
)
+
")"
);
}
}
stat
.
execute
(
"CREATE TABLE u (a int, b int) ENGINE "
+
engine
);
stat
.
execute
(
"CREATE TABLE u (a int, b int) ENGINE "
+
engine
);
TreeSetTable
u
=
TreeSetIndexTableEngine
.
created
;
TreeSetTable
u
=
TreeSetIndexTableEngine
.
created
;
stat
.
execute
(
"CREATE INDEX U_IDX_A ON u(a)"
);
stat
.
execute
(
"CREATE INDEX U_IDX_A ON u(a)"
);
stat
.
execute
(
"CREATE INDEX U_IDX_B ON u(b)"
);
stat
.
execute
(
"CREATE INDEX U_IDX_B ON u(b)"
);
setBatchSize
(
u
,
0
);
setBatchSize
(
u
,
0
);
for
(
int
i
=
0
;
i
<
20
;
i
++)
{
for
(
int
i
=
10
;
i
<
25
;
i
++)
{
stat
.
execute
(
"insert into u values ("
+
i
+
","
+
i
+
")"
);
stat
.
execute
(
"insert into u values ("
+
i
+
","
+
(
i
-
15
)
+
")"
);
}
}
checkPlan
(
stat
,
"SELECT 1 FROM PUBLIC.T T1 /* PUBLIC.\"scan\" */ "
checkPlan
(
stat
,
"SELECT 1 FROM PUBLIC.T T1 /* PUBLIC.\"scan\" */ "
...
@@ -521,11 +521,87 @@ public class TestTableEngines extends TestBase {
...
@@ -521,11 +521,87 @@ public class TestTableEngines extends TestBase {
+
"INNER JOIN ( SELECT A FROM PUBLIC.T ) Z "
+
"INNER JOIN ( SELECT A FROM PUBLIC.T ) Z "
+
"/* batched:view SELECT A FROM PUBLIC.T /++ batched:test PUBLIC.T_IDX_A: A IS ?1 ++/ "
+
"/* batched:view SELECT A FROM PUBLIC.T /++ batched:test PUBLIC.T_IDX_A: A IS ?1 ++/ "
+
"WHERE A IS ?1: A = T.B */ ON 1=1 WHERE Z.A = T.B"
);
+
"WHERE A IS ?1: A = T.B */ ON 1=1 WHERE Z.A = T.B"
);
checkPlan
(
stat
,
"SELECT 1 FROM PUBLIC.T /* PUBLIC.\"scan\" */ "
+
"INNER JOIN ( ((SELECT A FROM PUBLIC.T) UNION ALL (SELECT B FROM PUBLIC.U)) "
+
"UNION ALL (SELECT B FROM PUBLIC.T) ) Z /* batched:view "
+
"((SELECT A FROM PUBLIC.T /++ batched:test PUBLIC.T_IDX_A: A IS ?1 ++/ WHERE A IS ?1) "
+
"UNION ALL "
+
"(SELECT B FROM PUBLIC.U /++ PUBLIC.U_IDX_B: B IS ?1 ++/ WHERE B IS ?1)) "
+
"UNION ALL "
+
"(SELECT B FROM PUBLIC.T /++ batched:test PUBLIC.T_IDX_B: B IS ?1 ++/ WHERE B IS ?1)"
+
": A = T.A */ ON 1=1 WHERE Z.A = T.A"
);
checkPlan
(
stat
,
"SELECT 1 FROM PUBLIC.T /* PUBLIC.\"scan\" */ "
+
"INNER JOIN ( SELECT U.A FROM PUBLIC.U INNER JOIN PUBLIC.T ON 1=1 WHERE U.B = T.B ) Z "
+
"/* batched:view SELECT U.A FROM PUBLIC.U /++ batched:fake PUBLIC.U_IDX_A: A IS ?1 ++/ "
+
"/++ WHERE U.A IS ?1 ++/ INNER JOIN PUBLIC.T /++ batched:test PUBLIC.T_IDX_B: B = U.B ++/ "
+
"ON 1=1 WHERE (U.A IS ?1) AND (U.B = T.B): A = T.A */ ON 1=1 WHERE Z.A = T.A"
);
checkPlan
(
stat
,
"SELECT 1 FROM PUBLIC.T /* PUBLIC.\"scan\" */ "
+
"INNER JOIN ( SELECT A FROM PUBLIC.U ) Z /* SELECT A FROM PUBLIC.U "
+
"/++ PUBLIC.U_IDX_A: A IS ?1 ++/ WHERE A IS ?1: A = T.A */ ON 1=1 WHERE T.A = Z.A"
);
checkPlan
(
stat
,
"SELECT 1 FROM "
+
"( SELECT U.A FROM PUBLIC.U INNER JOIN PUBLIC.T ON 1=1 WHERE U.B = T.B ) Z "
+
"/* SELECT U.A FROM PUBLIC.U /++ PUBLIC.\"scan\" ++/ "
+
"INNER JOIN PUBLIC.T /++ batched:test PUBLIC.T_IDX_B: B = U.B ++/ "
+
"ON 1=1 WHERE U.B = T.B */ "
+
"INNER JOIN PUBLIC.T /* batched:test PUBLIC.T_IDX_A: A = Z.A */ ON 1=1 WHERE T.A = Z.A"
);
checkPlan
(
stat
,
"SELECT 1 FROM "
+
"( SELECT U.A FROM PUBLIC.T INNER JOIN PUBLIC.U ON 1=1 WHERE T.B = U.B ) Z "
+
"/* SELECT U.A FROM PUBLIC.T /++ PUBLIC.\"scan\" ++/ "
+
"INNER JOIN PUBLIC.U /++ PUBLIC.U_IDX_B: B = T.B ++/ "
+
"ON 1=1 WHERE T.B = U.B */ INNER JOIN PUBLIC.T /* batched:test PUBLIC.T_IDX_A: A = Z.A */ "
+
"ON 1=1 WHERE Z.A = T.A"
);
checkPlan
(
stat
,
"SELECT 1 FROM ( (SELECT A FROM PUBLIC.T) UNION (SELECT A FROM PUBLIC.U) ) Z "
+
"/* (SELECT A FROM PUBLIC.T /++ PUBLIC.\"scan\" ++/) "
+
"UNION "
+
"(SELECT A FROM PUBLIC.U /++ PUBLIC.\"scan\" ++/) */ "
+
"INNER JOIN PUBLIC.T /* batched:test PUBLIC.T_IDX_A: A = Z.A */ ON 1=1 WHERE Z.A = T.A"
);
checkPlan
(
stat
,
"SELECT 1 FROM PUBLIC.U /* PUBLIC.\"scan\" */ "
+
"INNER JOIN ( (SELECT A, B FROM PUBLIC.T) UNION (SELECT B, A FROM PUBLIC.U) ) Z "
+
"/* batched:view (SELECT A, B FROM PUBLIC.T /++ batched:test PUBLIC.T_IDX_B: B IS ?1 ++/ "
+
"WHERE B IS ?1) UNION (SELECT B, A FROM PUBLIC.U /++ PUBLIC.U_IDX_A: A IS ?1 ++/ "
+
"WHERE A IS ?1): B = U.B */ ON 1=1 /* WHERE U.B = Z.B */ "
+
"INNER JOIN PUBLIC.T /* batched:test PUBLIC.T_IDX_A: A = Z.A */ ON 1=1 "
+
"WHERE (U.B = Z.B) AND (Z.A = T.A)"
);
checkPlan
(
stat
,
"SELECT 1 FROM PUBLIC.U /* PUBLIC.\"scan\" */ "
+
"INNER JOIN ( SELECT A, B FROM PUBLIC.U ) Z "
+
"/* batched:fake SELECT A, B FROM PUBLIC.U /++ PUBLIC.U_IDX_A: A IS ?1 ++/ "
+
"WHERE A IS ?1: A = U.A */ ON 1=1 /* WHERE U.A = Z.A */ "
+
"INNER JOIN PUBLIC.T /* batched:test PUBLIC.T_IDX_B: B = Z.B */ "
+
"ON 1=1 WHERE (U.A = Z.A) AND (Z.B = T.B)"
);
// t: a = [ 0..20), b = [10..30)
// u: a = [10..25), b = [-5..10)
checkBatchedQueryResult
(
stat
,
10
,
"select t.a from t, (select t.b from u, t where u.a = t.a) z where t.b = z.b"
);
checkBatchedQueryResult
(
stat
,
5
,
"select t.a from (select t1.b from t t1, t t2 where t1.a = t2.b) z, t where t.b = z.b + 5"
);
checkBatchedQueryResult
(
stat
,
1
,
"select t.a from (select u.b from u, t t2 where u.a = t2.b) z, t where t.b = z.b + 1"
);
checkBatchedQueryResult
(
stat
,
15
,
"select t.a from (select u.b from u, t t2 where u.a = t2.b) z left join t on t.b = z.b"
);
checkBatchedQueryResult
(
stat
,
15
,
"select t.a from (select t1.b from t t1 left join t t2 on t1.a = t2.b) z, t "
+
"where t.b = z.b + 5"
);
checkBatchedQueryResult
(
stat
,
1
,
"select t.a from t,(select 5 as b from t union select 10 from u) z "
+
"where t.b = z.b"
);
checkBatchedQueryResult
(
stat
,
15
,
"select t.a from u,(select 5 as b, a from t "
+
"union select 10, a from u) z, t where t.b = z.b and z.a = u.a"
);
stat
.
execute
(
"DROP TABLE T"
);
stat
.
execute
(
"DROP TABLE T"
);
stat
.
execute
(
"DROP TABLE U"
);
stat
.
execute
(
"DROP TABLE U"
);
}
}
private
void
checkBatchedQueryResult
(
Statement
stat
,
int
size
,
String
sql
)
throws
SQLException
{
setBatchingEnabled
(
stat
,
false
);
List
<
List
<
Object
>>
expected
=
query
(
stat
,
sql
);
assertEquals
(
size
,
expected
.
size
());
setBatchingEnabled
(
stat
,
true
);
List
<
List
<
Object
>>
actual
=
query
(
stat
,
sql
);
if
(!
expected
.
equals
(
actual
))
{
fail
(
"\nexpected: "
+
expected
+
"\nactual: "
+
actual
);
}
}
private
void
doTestBatchedJoin
(
Statement
stat
,
int
...
batchSizes
)
throws
SQLException
{
private
void
doTestBatchedJoin
(
Statement
stat
,
int
...
batchSizes
)
throws
SQLException
{
ArrayList
<
TreeSetTable
>
tables
=
New
.
arrayList
(
batchSizes
.
length
);
ArrayList
<
TreeSetTable
>
tables
=
New
.
arrayList
(
batchSizes
.
length
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论