Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
知世而放
oceanbase
提交
c84b7de5
O
oceanbase
项目概览
知世而放
/
oceanbase
与 Fork 源项目一致
Fork自
oceanbase / oceanbase
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
O
oceanbase
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c84b7de5
编写于
11月 11, 2021
作者:
Z
zs0
提交者:
LINGuanRen
11月 11, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
enhance plan expiration, optimize index prune for small row count
上级
f2f2aed9
变更
17
展开全部
隐藏空白更改
内联
并排
Showing
17 changed file
with
486 addition
and
257 deletion
+486
-257
src/sql/code_generator/ob_code_generator_impl.cpp
src/sql/code_generator/ob_code_generator_impl.cpp
+3
-0
src/sql/code_generator/ob_static_engine_cg.cpp
src/sql/code_generator/ob_static_engine_cg.cpp
+1
-0
src/sql/engine/ob_physical_plan.cpp
src/sql/engine/ob_physical_plan.cpp
+57
-35
src/sql/engine/ob_physical_plan.h
src/sql/engine/ob_physical_plan.h
+2
-1
src/sql/engine/table/ob_table_scan.cpp
src/sql/engine/table/ob_table_scan.cpp
+42
-0
src/sql/engine/table/ob_table_scan.h
src/sql/engine/table/ob_table_scan.h
+2
-0
src/sql/engine/table/ob_table_scan_op.cpp
src/sql/engine/table/ob_table_scan_op.cpp
+39
-1
src/sql/engine/table/ob_table_scan_op.h
src/sql/engine/table/ob_table_scan_op.h
+3
-0
src/sql/optimizer/ob_join_order.cpp
src/sql/optimizer/ob_join_order.cpp
+137
-45
src/sql/optimizer/ob_join_order.h
src/sql/optimizer/ob_join_order.h
+10
-4
src/sql/optimizer/ob_log_plan.cpp
src/sql/optimizer/ob_log_plan.cpp
+3
-16
src/sql/optimizer/ob_log_table_scan.cpp
src/sql/optimizer/ob_log_table_scan.cpp
+30
-0
src/sql/plan_cache/ob_plan_cache_util.h
src/sql/plan_cache/ob_plan_cache_util.h
+4
-0
unittest/sql/optimizer/test_filter_before_indexback.result
unittest/sql/optimizer/test_filter_before_indexback.result
+6
-5
unittest/sql/optimizer/test_optimizer_select.result
unittest/sql/optimizer/test_optimizer_select.result
+88
-88
unittest/sql/optimizer/test_optimizer_used_hint.result
unittest/sql/optimizer/test_optimizer_used_hint.result
+49
-49
unittest/sql/rewrite/result/test_transformer_plan_after_trans_aggr.result
...rite/result/test_transformer_plan_after_trans_aggr.result
+10
-13
未找到文件。
src/sql/code_generator/ob_code_generator_impl.cpp
浏览文件 @
c84b7de5
...
...
@@ -7526,6 +7526,9 @@ int ObCodeGeneratorImpl::set_optimization_info(ObLogTableScan& log_ts, ObTableSc
if
(
OB_FAIL
(
phy_ts
->
set_available_index_name
(
log_ts
.
get_table_opt_info
()
->
available_index_name_
,
phy_plan_
->
get_allocator
())))
{
LOG_WARN
(
"failed to set available index name"
,
K
(
ret
));
}
else
if
(
OB_FAIL
(
phy_ts
->
set_unstable_index_name
(
log_ts
.
get_table_opt_info
()
->
unstable_index_name_
,
phy_plan_
->
get_allocator
())))
{
LOG_WARN
(
"failedd to set unstable index name"
,
K
(
ret
));
}
else
if
(
OB_FAIL
(
phy_ts
->
set_pruned_index_name
(
log_ts
.
get_table_opt_info
()
->
pruned_index_name_
,
phy_plan_
->
get_allocator
())))
{
LOG_WARN
(
"failedd to set prunned index name"
,
K
(
ret
));
...
...
src/sql/code_generator/ob_static_engine_cg.cpp
浏览文件 @
c84b7de5
...
...
@@ -4856,6 +4856,7 @@ int ObStaticEngineCG::set_optimization_info(ObLogTableScan& op, ObTableScanSpec&
spec
.
optimization_method_
=
op
.
get_table_opt_info
()
->
optimization_method_
;
spec
.
available_index_count_
=
op
.
get_table_opt_info
()
->
available_index_id_
.
count
();
OZ
(
spec
.
set_available_index_name
(
op
.
get_table_opt_info
()
->
available_index_name_
,
phy_plan_
->
get_allocator
()));
OZ
(
spec
.
set_unstable_index_name
(
op
.
get_table_opt_info
()
->
unstable_index_name_
,
phy_plan_
->
get_allocator
()));
OZ
(
spec
.
set_pruned_index_name
(
op
.
get_table_opt_info
()
->
pruned_index_name_
,
phy_plan_
->
get_allocator
()));
}
return
ret
;
...
...
src/sql/engine/ob_physical_plan.cpp
浏览文件 @
c84b7de5
...
...
@@ -589,62 +589,84 @@ void ObPhysicalPlan::update_plan_stat(const ObAuditRecordData& record, const boo
record
.
get_elapsed_time
()
-
record
.
exec_record_
.
wait_time_end_
-
(
record
.
exec_timestamp_
.
run_ts_
-
record
.
exec_timestamp_
.
receive_ts_
));
}
if
(
stat_
.
is_bind_sensitive_
||
stat_
.
enable_plan_expiration_
)
{
if
(
stat_
.
is_bind_sensitive_
&&
execute_count
>
0
)
{
int64_t
pos
=
execute_count
%
ObPlanStat
::
MAX_SCAN_STAT_SIZE
;
ATOMIC_STORE
(
&
(
stat_
.
table_scan_stat_
[
pos
].
query_range_row_count_
),
record
.
table_scan_stat_
.
query_range_row_count_
);
ATOMIC_STORE
(
&
(
stat_
.
table_scan_stat_
[
pos
].
indexback_row_count_
),
record
.
table_scan_stat_
.
indexback_row_count_
);
ATOMIC_STORE
(
&
(
stat_
.
table_scan_stat_
[
pos
].
output_row_count_
),
record
.
table_scan_stat_
.
output_row_count_
);
if
(
is_first
)
{
ATOMIC_STORE
(
&
(
stat_
.
first_exec_row_count_
),
record
.
table_scan_stat_
.
query_range_row_count_
);
}
}
if
(
!
is_expired
()
&&
stat_
.
enable_plan_expiration_
)
{
// if the first request is timeout, the execute_count is zero, the avg cpu time should be the cpu time
if
(
record
.
is_timeout
()
||
record
.
status_
==
OB_SESSION_KILLED
)
{
set_is_expired
(
true
);
LOG_INFO
(
"query plan is expired due to execution timeout"
,
K
(
stat_
));
}
else
if
(
execute_count
==
0
||
(
execute_count
%
SLOW_QUERY_SAMPLE_SIZE
)
!=
0
)
{
// do nothing when query execution samples are not enough
}
else
if
(
stat_
.
cpu_time_
<=
SLOW_QUERY_TIME_FOR_PLAN_EXPIRE
*
stat_
.
execute_times_
)
{
// do nothing for fast query
}
else
if
(
is_plan_unstable
())
{
set_is_expired
(
true
);
}
else
if
(
is_first
)
{
ATOMIC_STORE
(
&
(
stat_
.
sample_times_
),
0
);
ATOMIC_STORE
(
&
(
stat_
.
first_exec_row_count_
),
record
.
exec_record_
.
get_memstore_read_row_count
()
+
record
.
exec_record_
.
get_ssstore_read_row_count
());
ATOMIC_STORE
(
&
(
stat_
.
first_elapsed_time_
),
record
.
get_elapsed_time
());
}
else
if
(
0
==
stat_
.
sample_times_
)
{
// first sample query
ATOMIC_INC
(
&
(
stat_
.
sample_times_
));
ATOMIC_STORE
(
&
(
stat_
.
sample_exec_row_count_
),
record
.
exec_record_
.
get_memstore_read_row_count
()
+
record
.
exec_record_
.
get_ssstore_read_row_count
());
ATOMIC_STORE
(
&
(
stat_
.
sample_exec_usec_
),
record
.
get_elapsed_time
()
-
record
.
exec_record_
.
wait_time_end_
-
(
record
.
exec_timestamp_
.
run_ts_
-
record
.
exec_timestamp_
.
receive_ts_
));
}
else
{
int64_t
sample_count
=
ATOMIC_AAF
(
&
(
stat_
.
sample_times_
),
1
);
int64_t
sample_exec_row_count
=
ATOMIC_AAF
(
&
(
stat_
.
sample_exec_row_count_
),
record
.
exec_record_
.
get_memstore_read_row_count
()
+
record
.
exec_record_
.
get_ssstore_read_row_count
());
int64_t
sample_exec_usec
=
ATOMIC_AAF
(
&
(
stat_
.
sample_exec_usec_
),
record
.
get_elapsed_time
()
-
record
.
exec_record_
.
wait_time_end_
-
(
record
.
exec_timestamp_
.
run_ts_
-
record
.
exec_timestamp_
.
receive_ts_
));
if
(
sample_count
<
SLOW_QUERY_SAMPLE_SIZE
)
{
// do nothing when query execution samples are not enough
}
else
{
if
(
stat_
.
cpu_time_
<=
SLOW_QUERY_TIME_FOR_PLAN_EXPIRE
*
stat_
.
execute_times_
)
{
// do nothing for fast query
}
else
if
(
is_plan_unstable
(
sample_count
,
sample_exec_row_count
,
sample_exec_usec
))
{
set_is_expired
(
true
);
}
ATOMIC_STORE
(
&
(
stat_
.
sample_times_
),
0
);
}
}
}
}
bool
ObPhysicalPlan
::
is_plan_unstable
()
bool
ObPhysicalPlan
::
is_plan_unstable
(
const
int64_t
sample_count
,
const
int64_t
sample_exec_row_count
,
const
int64_t
sample_exec_usec
)
{
bool
bret
=
false
;
int64_t
exec_count
=
0
;
int64_t
total_index_back_rows
=
0
;
int64_t
total_query_range_rows
=
0
;
int64_t
first_query_range_rows
=
ATOMIC_LOAD
(
&
stat_
.
first_exec_row_count_
);
if
(
first_query_range_rows
!=
-
1
)
{
for
(
int64_t
i
=
0
;
i
<
SLOW_QUERY_SAMPLE_SIZE
;
++
i
)
{
int64_t
query_range_rows
=
ATOMIC_LOAD
(
&
(
stat_
.
table_scan_stat_
[
i
].
query_range_row_count_
));
int64_t
index_back_rows
=
ATOMIC_LOAD
(
&
(
stat_
.
table_scan_stat_
[
i
].
indexback_row_count_
));
if
(
query_range_rows
!=
-
1
)
{
exec_count
++
;
total_query_range_rows
+=
query_range_rows
;
total_index_back_rows
+=
index_back_rows
;
}
}
int64_t
total_access_cost
=
(
total_query_range_rows
+
10
*
total_index_back_rows
);
if
(
total_access_cost
<=
SLOW_QUERY_ROW_COUNT_THRESOLD
*
exec_count
)
{
// the query plan does not accesses too many rows in the average
}
else
if
(
total_query_range_rows
/
exec_count
>
first_query_range_rows
*
10
)
{
// the average query range row count increases great
if
(
sample_exec_usec
<=
SLOW_QUERY_TIME_FOR_PLAN_EXPIRE
*
sample_count
)
{
// sample query is fast query in the average
}
else
if
(
OB_PHY_PLAN_LOCAL
==
plan_type_
)
{
int64_t
first_query_range_rows
=
ATOMIC_LOAD
(
&
stat_
.
first_exec_row_count_
);
if
(
sample_exec_row_count
<=
SLOW_QUERY_ROW_COUNT_THRESOLD
*
sample_count
)
{
// the sample query does not accesses too many rows in the average
}
else
if
(
sample_exec_row_count
/
sample_count
>
first_query_range_rows
*
10
)
{
// the average sample query range row count increases great
bret
=
true
;
LOG_INFO
(
"query plan is expired due to unstable performance"
,
LOG_INFO
(
"
local
query plan is expired due to unstable performance"
,
K
(
bret
),
K
(
stat_
.
execute_times_
),
K
(
exec_count
),
K
(
first_query_range_rows
),
K
(
total_query_range_rows
),
K
(
total_index_back_rows
));
K
(
sample_exec_row_count
),
K
(
sample_count
));
}
}
else
if
(
OB_PHY_PLAN_DISTRIBUTED
==
plan_type_
)
{
int64_t
first_elapsed_time
=
ATOMIC_LOAD
(
&
stat_
.
first_elapsed_time_
);
if
(
sample_exec_usec
/
sample_count
>
first_elapsed_time
*
2
)
{
// the average sample query execute time increases great
bret
=
true
;
LOG_INFO
(
"distribute query plan is expired due to unstable performance"
,
K
(
bret
),
K
(
stat_
.
execute_times_
),
K
(
first_elapsed_time
),
K
(
sample_exec_usec
),
K
(
sample_count
));
}
}
else
{
// do nothing
}
return
bret
;
}
...
...
src/sql/engine/ob_physical_plan.h
浏览文件 @
c84b7de5
...
...
@@ -149,7 +149,8 @@ public:
}
inline
bool
check_if_is_expired
(
const
int64_t
first_exec_row_count
,
const
int64_t
current_row_count
)
const
;
bool
is_plan_unstable
();
bool
is_plan_unstable
(
const
int64_t
sample_count
,
const
int64_t
sample_exec_row_count
,
const
int64_t
sample_exec_usec
);
bool
is_expired
()
const
{
return
stat_
.
is_expired_
;
...
...
src/sql/engine/table/ob_table_scan.cpp
浏览文件 @
c84b7de5
...
...
@@ -331,6 +331,7 @@ ObTableScan::ObTableScan(ObIAllocator& allocator)
est_records_
(
allocator
),
available_index_name_
(
allocator
),
pruned_index_name_
(
allocator
),
unstable_index_name_
(
allocator
),
gi_above_
(
false
),
is_vt_mapping_
(
false
),
use_real_tenant_id_
(
false
),
...
...
@@ -2046,6 +2047,23 @@ int ObTableScan::set_available_index_name(const common::ObIArray<common::ObStrin
return
ret
;
}
int
ObTableScan
::
set_unstable_index_name
(
const
common
::
ObIArray
<
common
::
ObString
>&
idx_name
,
ObIAllocator
&
phy_alloc
)
{
int
ret
=
OB_SUCCESS
;
if
(
OB_FAIL
(
init_array_size
<>
(
unstable_index_name_
,
idx_name
.
count
())))
{
LOG_WARN
(
"init unstable_index_name failed"
,
K
(
ret
));
}
for
(
int64_t
i
=
0
;
OB_SUCC
(
ret
)
&&
i
<
idx_name
.
count
();
++
i
)
{
ObString
name
;
if
(
OB_FAIL
(
ob_write_string
(
phy_alloc
,
idx_name
.
at
(
i
),
name
)))
{
LOG_WARN
(
"copy unstable index name failed"
,
K
(
ret
));
}
else
if
(
OB_FAIL
(
unstable_index_name_
.
push_back
(
name
)))
{
LOG_WARN
(
"push unstable index name failed"
,
K
(
ret
));
}
}
return
ret
;
}
int
ObTableScan
::
set_pruned_index_name
(
const
common
::
ObIArray
<
common
::
ObString
>&
idx_name
,
ObIAllocator
&
phy_alloc
)
{
int
ret
=
OB_SUCCESS
;
...
...
@@ -2129,6 +2147,30 @@ int ObTableScan::explain_index_selection_info(char* buf, int64_t buf_len, int64_
}
}
if
(
OB_SUCC
(
ret
)
&&
unstable_index_name_
.
count
()
>
0
)
{
if
(
OB_FAIL
(
BUF_PRINTF
(
", unstable_index_name["
)))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
for
(
int64_t
i
=
0
;
OB_SUCC
(
ret
)
&&
i
<
unstable_index_name_
.
count
();
++
i
)
{
if
(
OB_FAIL
(
BUF_PRINTF
(
"%.*s"
,
unstable_index_name_
.
at
(
i
).
length
(),
unstable_index_name_
.
at
(
i
).
ptr
())))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
if
(
i
!=
unstable_index_name_
.
count
()
-
1
)
{
if
(
OB_FAIL
(
BUF_PRINTF
(
","
)))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
{
/* do nothing*/
}
}
else
{
/* do nothing*/
}
}
if
(
OB_SUCC
(
ret
))
{
if
(
OB_FAIL
(
BUF_PRINTF
(
"]"
)))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
{
/* Do nothing */
}
}
else
{
/* Do nothing */
}
}
if
(
OB_SUCC
(
ret
)
&&
est_records_
.
count
()
>
0
)
{
// print est row count infos
if
(
OB_FAIL
(
BUF_PRINTF
(
", estimation info[table_id:%ld,"
,
est_records_
.
at
(
0
).
table_id_
)))
{
...
...
src/sql/engine/table/ob_table_scan.h
浏览文件 @
c84b7de5
...
...
@@ -329,6 +329,7 @@ public:
return
estimate_method_
;
}
int
set_pruned_index_name
(
const
common
::
ObIArray
<
common
::
ObString
>&
pruned_index_name
,
ObIAllocator
&
phy_alloc
);
int
set_unstable_index_name
(
const
common
::
ObIArray
<
common
::
ObString
>&
unstable_index_name
,
ObIAllocator
&
phy_alloc
);
int
set_available_index_name
(
const
common
::
ObIArray
<
common
::
ObString
>&
available_index_name
,
ObIAllocator
&
phy_alloc
);
int
set_est_row_count_record
(
const
common
::
ObIArray
<
common
::
ObEstRowCountRecord
>&
est_records
);
inline
const
common
::
ObIArray
<
common
::
ObEstRowCountRecord
>&
get_est_row_count_record
()
const
...
...
@@ -673,6 +674,7 @@ protected:
common
::
ObFixedArray
<
common
::
ObEstRowCountRecord
,
common
::
ObIAllocator
>
est_records_
;
common
::
ObFixedArray
<
common
::
ObString
,
common
::
ObIAllocator
>
available_index_name_
;
common
::
ObFixedArray
<
common
::
ObString
,
common
::
ObIAllocator
>
pruned_index_name_
;
common
::
ObFixedArray
<
common
::
ObString
,
common
::
ObIAllocator
>
unstable_index_name_
;
//***********************************
bool
gi_above_
;
...
...
src/sql/engine/table/ob_table_scan_op.cpp
浏览文件 @
c84b7de5
...
...
@@ -219,6 +219,7 @@ ObTableScanSpec::ObTableScanSpec(ObIAllocator& alloc, const ObPhyOperatorType ty
est_records_
(
alloc
),
available_index_name_
(
alloc
),
pruned_index_name_
(
alloc
),
unstable_index_name_
(
alloc
),
gi_above_
(
false
),
expected_part_id_
(
NULL
),
need_scn_
(
false
),
...
...
@@ -294,7 +295,20 @@ int ObTableScanSpec::set_available_index_name(const ObIArray<ObString>& idx_name
return
ret
;
}
int
ObTableScanSpec
::
set_pruned_index_name
(
const
ObIArray
<
ObString
>&
idx_name
,
ObIAllocator
&
phy_alloc
)
int
ObTableScanSpec
::
set_unstable_index_name
(
const
ObIArray
<
ObString
>
&
idx_name
,
ObIAllocator
&
phy_alloc
)
{
int
ret
=
OB_SUCCESS
;
OZ
(
unstable_index_name_
.
init
(
idx_name
.
count
()));
FOREACH_CNT_X
(
n
,
idx_name
,
OB_SUCC
(
ret
))
{
ObString
name
;
OZ
(
ob_write_string
(
phy_alloc
,
*
n
,
name
));
OZ
(
unstable_index_name_
.
push_back
(
name
));
}
return
ret
;
}
int
ObTableScanSpec
::
set_pruned_index_name
(
const
ObIArray
<
ObString
>
&
idx_name
,
ObIAllocator
&
phy_alloc
)
{
int
ret
=
OB_SUCCESS
;
OZ
(
pruned_index_name_
.
init
(
idx_name
.
count
()));
...
...
@@ -373,6 +387,30 @@ int ObTableScanSpec::explain_index_selection_info(char* buf, int64_t buf_len, in
}
}
if
(
OB_SUCC
(
ret
)
&&
unstable_index_name_
.
count
()
>
0
)
{
if
(
OB_FAIL
(
BUF_PRINTF
(
", unstable_index_name["
)))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
for
(
int64_t
i
=
0
;
OB_SUCC
(
ret
)
&&
i
<
unstable_index_name_
.
count
();
++
i
)
{
if
(
OB_FAIL
(
BUF_PRINTF
(
"%.*s"
,
unstable_index_name_
.
at
(
i
).
length
(),
unstable_index_name_
.
at
(
i
).
ptr
())))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
if
(
i
!=
unstable_index_name_
.
count
()
-
1
)
{
if
(
OB_FAIL
(
BUF_PRINTF
(
","
)))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
{
/* do nothing*/
}
}
else
{
/* do nothing*/
}
}
if
(
OB_SUCC
(
ret
))
{
if
(
OB_FAIL
(
BUF_PRINTF
(
"]"
)))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
{
/* Do nothing */
}
}
else
{
/* Do nothing */
}
}
if
(
OB_SUCC
(
ret
)
&&
est_records_
.
count
()
>
0
)
{
// print est row count infos
if
(
OB_FAIL
(
BUF_PRINTF
(
", estimation info[table_id:%ld,"
,
est_records_
.
at
(
0
).
table_id_
)))
{
...
...
src/sql/engine/table/ob_table_scan_op.h
浏览文件 @
c84b7de5
...
...
@@ -94,6 +94,8 @@ public:
int
set_pruned_index_name
(
const
common
::
ObIArray
<
common
::
ObString
>&
pruned_index_name
,
common
::
ObIAllocator
&
phy_alloc
);
int
set_unstable_index_name
(
const
common
::
ObIArray
<
common
::
ObString
>&
unstable_index_name
,
common
::
ObIAllocator
&
phy_alloc
);
int
set_available_index_name
(
const
common
::
ObIArray
<
common
::
ObString
>&
available_index_name
,
common
::
ObIAllocator
&
phy_alloc
);
int
set_est_row_count_record
(
const
common
::
ObIArray
<
common
::
ObEstRowCountRecord
>&
est_records
);
...
...
@@ -225,6 +227,7 @@ public:
common
::
ObFixedArray
<
common
::
ObEstRowCountRecord
,
common
::
ObIAllocator
>
est_records_
;
common
::
ObFixedArray
<
common
::
ObString
,
common
::
ObIAllocator
>
available_index_name_
;
common
::
ObFixedArray
<
common
::
ObString
,
common
::
ObIAllocator
>
pruned_index_name_
;
common
::
ObFixedArray
<
common
::
ObString
,
common
::
ObIAllocator
>
unstable_index_name_
;
bool
gi_above_
;
ObExpr
*
expected_part_id_
;
...
...
src/sql/optimizer/ob_join_order.cpp
浏览文件 @
c84b7de5
...
...
@@ -1418,9 +1418,9 @@ int ObJoinOrder::cal_dimension_info(const uint64_t table_id, // alias table id
return
ret
;
}
int
ObJoinOrder
::
prunning_index
(
const
uint64_t
table_id
,
const
uint64_t
base_table_id
,
const
ObDMLStmt
*
stmt
,
int
ObJoinOrder
::
skyline_
prunning_index
(
const
uint64_t
table_id
,
const
uint64_t
base_table_id
,
const
ObDMLStmt
*
stmt
,
const
bool
do_prunning
,
const
ObIndexInfoCache
&
index_info_cache
,
const
ObIArray
<
uint64_t
>&
valid_index_ids
,
ObIArray
<
uint64_t
>&
skyline_index_ids
,
ObIArray
<
ObRawExpr
*>&
restrict_infos
)
ObIArray
<
uint64_t
>&
skyline_index_ids
,
ObIArray
<
ObRawExpr
*>&
restrict_infos
)
{
int
ret
=
OB_SUCCESS
;
if
(
!
do_prunning
)
{
...
...
@@ -1610,7 +1610,7 @@ int ObJoinOrder::add_table(
LOG_WARN
(
"failed to add table by heuristics"
,
K
(
ret
));
}
else
if
(
heuristics_used
)
{
LOG_TRACE
(
"table added using heuristics"
,
K
(
table_id
));
}
else
if
(
OB_FAIL
(
prunning_index
(
table_id
,
}
else
if
(
OB_FAIL
(
skyline_
prunning_index
(
table_id
,
ref_table_id
,
stmt
,
true
,
...
...
@@ -1619,8 +1619,6 @@ int ObJoinOrder::add_table(
skyline_index_ids
,
helper
.
filters_
)))
{
LOG_WARN
(
"failed to pruning_index"
,
K
(
table_id
),
K
(
ref_table_id
),
K
(
ret
));
}
else
if
(
OB_FAIL
(
compute_pruned_index
(
table_id
,
ref_table_id
,
skyline_index_ids
,
helper
)))
{
LOG_WARN
(
"failed to compute pruned index"
,
K
(
table_id
),
K
(
ref_table_id
),
K
(
skyline_index_ids
),
K
(
ret
));
}
else
{
LOG_TRACE
(
"table added not using heuristics"
,
K
(
table_id
),
K
(
skyline_index_ids
));
helper
.
table_opt_info_
->
optimization_method_
=
OptimizationMethod
::
COST_BASED
;
...
...
@@ -2478,73 +2476,68 @@ int ObJoinOrder::revise_output_rows_after_creating_path(PathHelper& helper, ObIA
return
ret
;
}
int
ObJoinOrder
::
compute_pruned_index
(
const
uint64_t
table_id
,
const
uint64_t
base_table_id
,
ObIArray
<
uint64_t
>&
available_index_id
,
PathHelper
&
helper
)
int
ObJoinOrder
::
fill_opt_info_index_name
(
const
uint64_t
base_table_id
,
ObIArray
<
uint64_t
>
&
available_index_id
,
ObIArray
<
uint64_t
>
&
unstable_index_id
,
BaseTableOptInfo
*
table_opt_info
)
{
int
ret
=
OB_SUCCESS
;
const
ObTableSchema
*
table_schema
=
NULL
;
uint64_t
index_ids
[
OB_MAX_INDEX_PER_TABLE
+
1
];
int64_t
index_count
=
OB_MAX_INDEX_PER_TABLE
+
1
;
ObSqlSchemaGuard
*
schema_guard
=
NULL
;
if
(
OB_ISNULL
(
get_plan
())
||
OB_ISNULL
(
schema_guard
=
OPT_CTX
.
get_sql_schema_guard
())
||
OB_ISNULL
(
helper
.
table_opt_info_
))
{
const
ObTableSchema
*
table_schema
=
NULL
;
uint64_t
index_ids
[
OB_MAX_INDEX_PER_TABLE
+
3
];
int64_t
index_count
=
OB_MAX_INDEX_PER_TABLE
+
3
;
ObSqlSchemaGuard
*
schema_guard
=
NULL
;
if
(
OB_ISNULL
(
table_opt_info
)
||
OB_ISNULL
(
get_plan
())
||
OB_ISNULL
(
schema_guard
=
OPT_CTX
.
get_sql_schema_guard
()))
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"get unexpected null"
,
K
(
get_plan
()),
K
(
schema_guard
),
K
(
helper
.
table_opt_info_
),
K
(
ret
));
}
else
if
(
OB_UNLIKELY
(
OB_INVALID_ID
==
table_id
)
||
OB_UNLIKELY
(
OB_INVALID_ID
==
base_table_id
))
{
LOG_WARN
(
"get unexpected null"
,
K
(
get_plan
()),
K
(
schema_guard
),
K
(
table_opt_info
),
K
(
ret
));
}
else
if
(
OB_UNLIKELY
(
OB_INVALID_ID
==
base_table_id
))
{
ret
=
OB_INVALID_ARGUMENT
;
LOG_WARN
(
"Invalid table id"
,
K
(
table_id
),
K
(
base_table_id
),
K
(
ret
));
LOG_WARN
(
"Invalid table id"
,
K
(
base_table_id
),
K
(
ret
));
}
else
if
(
OB_FAIL
(
schema_guard
->
get_can_read_index_array
(
base_table_id
,
index_ids
,
index_count
,
false
,
true
/*global index*/
,
false
/*domain index*/
)))
{
LOG_WARN
(
"failed to get can read index"
,
K
(
base_table_id
),
K
(
ret
));
}
else
if
(
index_count
>
OB_MAX_INDEX_PER_TABLE
+
1
)
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"Invalid index count"
,
K
(
base_table_id
),
K
(
index_count
),
K
(
ret
));
}
else
if
(
OB_FAIL
(
helper
.
table_opt_info_
->
available_index_id_
.
assign
(
available_index_id
)))
{
}
else
if
(
OB_FAIL
(
table_opt_info
->
available_index_id_
.
assign
(
available_index_id
)))
{
LOG_WARN
(
"failed to assign available index id"
,
K
(
ret
));
}
else
{
const
uint64_t
rowid_index_id
=
ObSQLMockSchemaUtils
::
get_rowid_index_table_id
(
base_table_id
);
index_ids
[
index_count
++
]
=
base_table_id
;
index_ids
[
index_count
++
]
=
rowid_index_id
;
// i == -1 represents primary key, other value of i represent index
for
(
int64_t
i
=
-
1
;
OB_SUCC
(
ret
)
&&
i
<
index_count
;
i
++
)
{
for
(
int64_t
i
=
0
;
OB_SUCC
(
ret
)
&&
i
<
index_count
;
++
i
)
{
ObString
name
;
bool
is_find
=
false
;
uint64_t
index_id
=
(
i
==
-
1
)
?
base_table_id
:
index_ids
[
i
];
if
(
OB_FAIL
(
schema_guard
->
get_table_schema
(
index_id
,
table_schema
)))
{
uint64_t
index_id
=
index_ids
[
i
];
if
(
rowid_index_id
==
index_id
)
{
name
=
ObString
::
make_string
(
ObSQLMockSchemaUtils
::
get_rowid_index_name
());
}
else
if
(
OB_FAIL
(
schema_guard
->
get_table_schema
(
index_id
,
table_schema
)))
{
LOG_WARN
(
"fail to get table schema"
,
K
(
index_id
),
K
(
ret
));
}
else
if
(
OB_ISNULL
(
table_schema
))
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"index schema should not be null"
,
K
(
ret
),
K
(
index_id
));
}
else
if
(
i
==
-
1
)
{
}
else
if
(
base_table_id
==
index_id
)
{
name
=
table_schema
->
get_table_name_str
();
}
else
if
(
OB_FAIL
(
table_schema
->
get_index_name
(
name
)))
{
LOG_WARN
(
"failed to get index name"
,
K
(
ret
));
}
else
{
/*do nothing*/
}
for
(
int64_t
j
=
0
;
OB_SUCC
(
ret
)
&&
(
!
is_find
)
&&
j
<
available_index_id
.
count
();
j
++
)
{
if
(
index_id
==
available_index_id
.
at
(
j
))
{
is_find
=
true
;
if
(
OB_FAIL
(
ret
))
{
}
else
if
(
ObOptimizerUtil
::
find_item
(
available_index_id
,
index_id
))
{
if
(
OB_FAIL
(
table_opt_info
->
available_index_name_
.
push_back
(
name
)))
{
LOG_WARN
(
"failed to push back index name"
,
K
(
name
),
K
(
ret
));
}
else
{
/* do nothing */
}
}
if
(
OB_SUCC
(
ret
))
{
if
(
is_find
)
{
if
(
OB_FAIL
(
helper
.
table_opt_info_
->
available_index_name_
.
push_back
(
name
)))
{
LOG_WARN
(
"failed to push back index name"
,
K
(
name
),
K
(
ret
));
}
else
{
/* do nothing */
}
}
else
{
if
(
OB_FAIL
(
helper
.
table_opt_info_
->
pruned_index_name_
.
push_back
(
name
)))
{
LOG_WARN
(
"failed to push back index name"
,
K
(
name
),
K
(
ret
));
}
else
{
/* do nothing */
}
}
else
if
(
ObOptimizerUtil
::
find_item
(
unstable_index_id
,
index_id
))
{
if
(
OB_FAIL
(
table_opt_info
->
unstable_index_name_
.
push_back
(
name
)))
{
LOG_WARN
(
"failed to push back index name"
,
K
(
name
),
K
(
ret
));
}
else
{
/* do nothing */
}
}
else
if
(
rowid_index_id
==
index_id
)
{
/* do nothing */
}
else
if
(
OB_FAIL
(
table_opt_info
->
pruned_index_name_
.
push_back
(
name
)))
{
LOG_WARN
(
"failed to push back index name"
,
K
(
name
),
K
(
ret
));
}
else
{
/* do nothing */
}
}
if
(
OB_FAIL
(
ret
))
{
// do nothing
}
else
if
(
ObSQLMockSchemaUtils
::
contain_mock_index
(
base_table_id
)
&&
OB_FAIL
(
helper
.
table_opt_info_
->
available_index_name_
.
push_back
(
ObString
::
make_string
(
ObSQLMockSchemaUtils
::
get_rowid_index_name
()))))
{
LOG_WARN
(
"failed to push back rowid index name"
,
K
(
ret
));
}
}
return
ret
;
}
...
...
@@ -3005,6 +2998,83 @@ int ObJoinOrder::estimate_size_and_width_for_access(PathHelper& helper, ObIArray
return
ret
;
}
int
ObJoinOrder
::
pruning_unstable_access_path
(
BaseTableOptInfo
*
table_opt_info
,
ObIArray
<
AccessPath
*>
&
access_paths
)
{
int
ret
=
OB_SUCCESS
;
ObSQLSessionInfo
*
session_info
=
NULL
;
bool
use_acs
=
false
;
ObSEArray
<
uint64_t
,
4
>
unstable_index_id
;
if
(
OB_UNLIKELY
(
access_paths
.
empty
())
||
OB_ISNULL
(
get_plan
())
||
OB_ISNULL
(
session_info
=
get_plan
()
->
get_optimizer_context
().
get_session_info
()))
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"unexpected null"
,
K
(
ret
),
K
(
access_paths
.
count
()),
K
(
get_plan
()),
K
(
session_info
));
}
else
if
(
OB_FAIL
(
session_info
->
get_adaptive_cursor_sharing
(
use_acs
)))
{
LOG_WARN
(
"failed to check is acs enabled"
,
K
(
ret
));
}
else
if
(
use_acs
||
access_paths
.
count
()
<=
1
||
OB_DEFAULT_STAT_EST
==
table_meta_info_
.
cost_est_type_
)
{
/* do not pruning access path */
}
else
if
(
OB_FAIL
(
try_pruning_base_table_access_path
(
access_paths
,
unstable_index_id
)))
{
LOG_WARN
(
"failed to pruning base table access path"
,
K
(
ret
));
}
if
(
OB_SUCC
(
ret
))
{
ObSEArray
<
uint64_t
,
4
>
available_index_id
;
uint64_t
base_table_id
=
OB_INVALID_ID
;
AccessPath
*
ap
=
NULL
;
for
(
int64_t
i
=
0
;
OB_SUCC
(
ret
)
&&
i
<
access_paths
.
count
();
++
i
)
{
if
(
OB_ISNULL
(
ap
=
access_paths
.
at
(
i
)))
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"unexpected null"
,
K
(
ret
));
}
else
if
(
OB_FAIL
(
available_index_id
.
push_back
(
ap
->
index_id_
)))
{
LOG_WARN
(
"failed to push back index id"
,
K
(
ret
));
}
else
if
(
0
==
i
)
{
base_table_id
=
ap
->
ref_table_id_
;
}
}
if
(
OB_SUCC
(
ret
)
&&
OB_FAIL
(
fill_opt_info_index_name
(
base_table_id
,
available_index_id
,
unstable_index_id
,
table_opt_info
)))
{
LOG_WARN
(
"failed to fill opt info index name"
,
K
(
ret
),
K
(
base_table_id
),
K
(
available_index_id
),
K
(
unstable_index_id
));
}
}
return
ret
;
}
int
ObJoinOrder
::
try_pruning_base_table_access_path
(
ObIArray
<
AccessPath
*>
&
access_paths
,
ObIArray
<
uint64_t
>
&
unstable_index_id
)
{
int
ret
=
OB_SUCCESS
;
bool
need_prune
=
false
;
int64_t
base_path_pos
=
OB_INVALID_INDEX
;
AccessPath
*
ap
=
NULL
;
for
(
int64_t
i
=
0
;
OB_SUCC
(
ret
)
&&
i
<
access_paths
.
count
();
++
i
)
{
if
(
OB_ISNULL
(
ap
=
access_paths
.
at
(
i
)))
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"unexpected null"
,
K
(
ret
));
}
else
if
(
ap
->
ref_table_id_
==
ap
->
index_id_
)
{
base_path_pos
=
i
;
}
else
{
need_prune
|=
ap
->
range_prefix_count_
>
0
&&
ap
->
query_range_row_count_
<
PRUNING_ROW_COUNT_THRESHOLD
;
}
}
if
(
OB_SUCC
(
ret
)
&&
need_prune
&&
OB_INVALID_INDEX
!=
base_path_pos
)
{
if
(
OB_UNLIKELY
(
base_path_pos
<
0
||
base_path_pos
>
access_paths
.
count
())
||
OB_ISNULL
(
ap
=
access_paths
.
at
(
base_path_pos
)))
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"unexpected pos or access path"
,
K
(
ret
),
K
(
base_path_pos
),
K
(
access_paths
.
count
()),
K
(
ap
));
}
else
if
(
ap
->
range_prefix_count_
>
0
)
{
/* do nothing */
}
else
if
(
OB_FAIL
(
access_paths
.
remove
(
base_path_pos
)))
{
LOG_WARN
(
"failed to remove access path"
,
K
(
ret
),
K
(
base_path_pos
));
}
else
if
(
OB_FAIL
(
unstable_index_id
.
push_back
(
ap
->
index_id_
)))
{
LOG_WARN
(
"failed to push back index id"
,
K
(
ret
));
}
else
{
LOG_TRACE
(
"pruned base table access paths"
,
K
(
*
ap
));
}
}
return
ret
;
}
int
ObJoinOrder
::
estimate_join_width
(
const
ObJoinOrder
*
left_tree
,
const
ObJoinOrder
*
right_tree
,
const
ObJoinType
join_type
)
{
...
...
@@ -3493,6 +3563,25 @@ int ObJoinOrder::compute_path_relationship(const sql::Path* first_path, const sq
}
}
// relation is EQUAL now, check index column count when both not index back
// remove this if adjusted estimate cost for table scan
if
(
OB_SUCC
(
ret
)
&&
PathType
::
ACCESS
==
first_path
->
path_type_
&&
PathType
::
ACCESS
==
second_path
->
path_type_
&&
left_dominated_count
==
0
&&
right_dominated_count
==
0
&&
uncompareable_count
==
0
)
{
const
ObIndexMetaInfo
&
first_index_info
=
static_cast
<
const
AccessPath
*>
(
first_path
)
->
get_cost_table_scan_info
().
index_meta_info_
;
const
ObIndexMetaInfo
&
second_index_info
=
static_cast
<
const
AccessPath
*>
(
second_path
)
->
get_cost_table_scan_info
().
index_meta_info_
;
if
(
first_index_info
.
is_index_back_
||
second_index_info
.
is_index_back_
)
{
// do nothing for this, will return EQUAL final
}
else
if
(
first_index_info
.
index_column_count_
<
second_index_info
.
index_column_count_
)
{
++
left_dominated_count
;
}
else
if
(
first_index_info
.
index_column_count_
>
second_index_info
.
index_column_count_
)
{
++
right_dominated_count
;
}
else
{
// do nothing
}
}
// compute final result
if
(
OB_SUCC
(
ret
))
{
if
(
left_dominated_count
>
0
&&
right_dominated_count
==
0
&&
uncompareable_count
==
0
)
{
...
...
@@ -3996,6 +4085,9 @@ int ObJoinOrder::generate_access_paths(PathHelper& helper)
LOG_WARN
(
"failed to calc table location"
,
K
(
ret
));
}
else
if
(
OB_FAIL
(
estimate_size_and_width_for_access
(
helper
,
access_paths
)))
{
LOG_WARN
(
"failed to estimate_size"
,
K
(
ret
));
}
else
if
(
!
access_paths
.
empty
()
&&
// when generate inner path, access_paths may be empty
OB_FAIL
(
pruning_unstable_access_path
(
helper
.
table_opt_info_
,
access_paths
)))
{
LOG_WARN
(
"failed to pruning unstable access path"
,
K
(
ret
));
}
else
if
(
!
helper
.
is_inner_path_
)
{
if
(
OB_FAIL
(
compute_const_exprs
(
NULL
,
NULL
,
type_
,
UNKNOWN_JOIN
)))
{
LOG_WARN
(
"failed to compute const exprs"
,
K
(
ret
));
...
...
src/sql/optimizer/ob_join_order.h
浏览文件 @
c84b7de5
...
...
@@ -120,7 +120,8 @@ struct BaseTableOptInfo {
heuristic_rule_
(
HeuristicRule
::
MAX_RULE
),
available_index_id_
(),
available_index_name_
(),
pruned_index_name_
()
pruned_index_name_
(),
unstable_index_name_
()
{}
// this following variables are tracked to remember how base table access path are generated
...
...
@@ -129,6 +130,7 @@ struct BaseTableOptInfo {
common
::
ObSEArray
<
uint64_t
,
4
,
common
::
ModulePageAllocator
,
true
>
available_index_id_
;
common
::
ObSEArray
<
common
::
ObString
,
4
,
common
::
ModulePageAllocator
,
true
>
available_index_name_
;
common
::
ObSEArray
<
common
::
ObString
,
4
,
common
::
ModulePageAllocator
,
true
>
pruned_index_name_
;
common
::
ObSEArray
<
common
::
ObString
,
4
,
common
::
ModulePageAllocator
,
true
>
unstable_index_name_
;
};
class
Path
{
...
...
@@ -611,6 +613,7 @@ public:
static
const
int8_t
NEED_BNL
=
0x1
<<
3
;
// used for heuristic index selection
static
const
int64_t
TABLE_HEURISTIC_UNIQUE_KEY_RANGE_THRESHOLD
=
10000
;
static
const
int64_t
PRUNING_ROW_COUNT_THRESHOLD
=
1000
;
ObJoinOrder
(
common
::
ObIAllocator
*
allocator
,
ObLogPlan
*
plan
,
PathType
type
)
:
allocator_
(
allocator
),
...
...
@@ -643,11 +646,14 @@ public:
{}
virtual
~
ObJoinOrder
();
int
prunning_index
(
const
uint64_t
table_id
,
const
uint64_t
base_table_id
,
const
ObDMLStmt
*
stmt
,
int
skyline_
prunning_index
(
const
uint64_t
table_id
,
const
uint64_t
base_table_id
,
const
ObDMLStmt
*
stmt
,
const
bool
do_prunning
,
const
ObIndexInfoCache
&
index_info_cache
,
const
common
::
ObIArray
<
uint64_t
>&
valid_index_ids
,
common
::
ObIArray
<
uint64_t
>&
skyline_index_ids
,
ObIArray
<
ObRawExpr
*>&
restrict_infos
);
int
pruning_unstable_access_path
(
BaseTableOptInfo
*
table_opt_info
,
ObIArray
<
AccessPath
*>
&
access_paths
);
int
try_pruning_base_table_access_path
(
ObIArray
<
AccessPath
*>
&
access_paths
,
ObIArray
<
uint64_t
>
&
unstable_index_id
);
int
cal_dimension_info
(
const
uint64_t
table_id
,
const
uint64_t
data_table_id
,
const
uint64_t
index_table_id
,
const
ObDMLStmt
*
stmt
,
ObIndexSkylineDim
&
index_dim
,
const
ObIndexInfoCache
&
index_info_cache
,
ObIArray
<
ObRawExpr
*>&
restrict_infos
);
...
...
@@ -657,8 +663,8 @@ public:
int
fill_index_info_cache
(
const
uint64_t
table_id
,
const
uint64_t
base_table_id
,
const
common
::
ObIArray
<
uint64_t
>&
valid_index_ids
,
ObIndexInfoCache
&
index_info_cache
,
PathHelper
&
helper
);
int
compute_pruned_index
(
const
uint64_t
table_id
,
const
uint64_t
base_table
_id
,
common
::
ObIArray
<
uint64_t
>&
available_index
,
PathHelper
&
helper
);
int
fill_opt_info_index_name
(
const
uint64_t
base_table_id
,
ObIArray
<
uint64_t
>&
available_index
_id
,
ObIArray
<
uint64_t
>&
unstable_index_id
,
BaseTableOptInfo
*
table_opt_info
);
int
extract_used_column_ids
(
const
uint64_t
table_id
,
const
uint64_t
ref_table_id
,
ObEstSelInfo
&
est_sel_info
,
ObIArray
<
uint64_t
>&
column_ids
,
const
bool
eliminate_rowid_col
=
false
);
...
...
src/sql/optimizer/ob_log_plan.cpp
浏览文件 @
c84b7de5
...
...
@@ -7250,8 +7250,6 @@ int ObLogPlan::check_enable_plan_expiration(bool& enable) const
LOG_WARN
(
"stmt is null"
,
K
(
ret
));
}
else
if
(
!
get_stmt
()
->
is_select_stmt
())
{
// do nothing
}
else
if
(
get_phy_plan_type
()
!=
OB_PHY_PLAN_LOCAL
&&
get_phy_plan_type
()
!=
OB_PHY_PLAN_REMOTE
)
{
// do nothing
}
else
if
(
OB_FAIL
(
session
->
get_adaptive_cursor_sharing
(
use_acs
)))
{
LOG_WARN
(
"failed to check is acs enabled"
,
K
(
ret
));
}
else
if
(
use_acs
)
{
...
...
@@ -7260,21 +7258,10 @@ int ObLogPlan::check_enable_plan_expiration(bool& enable) const
LOG_WARN
(
"failed to check is spm enabled"
,
K
(
ret
));
}
else
if
(
use_spm
)
{
// do nothing
}
else
if
(
get_phy_plan_type
()
!=
OB_PHY_PLAN_LOCAL
&&
get_phy_plan_type
()
!=
OB_PHY_PLAN_DISTRIBUTED
)
{
// do nothing
}
else
{
const
ObLogicalOperator
*
node
=
root_
;
while
(
OB_SUCC
(
ret
))
{
if
(
OB_ISNULL
(
node
))
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"node is null"
,
K
(
ret
));
}
else
if
(
node
->
get_num_of_child
()
==
1
)
{
node
=
node
->
get_child
(
ObLogicalOperator
::
first_child
);
}
else
{
break
;
}
}
if
(
OB_SUCC
(
ret
)
&&
node
->
is_table_scan
())
{
enable
=
(
static_cast
<
const
ObLogTableScan
*>
(
node
)
->
get_diverse_path_count
()
>=
2
);
}
enable
=
true
;
}
return
ret
;
}
...
...
src/sql/optimizer/ob_log_table_scan.cpp
浏览文件 @
c84b7de5
...
...
@@ -1227,6 +1227,36 @@ int ObLogTableScan::explain_index_selection_info(char* buf, int64_t& buf_len, in
}
else
{
/* Do nothing */
}
}
// print unstable index name
if
(
OB_SUCC
(
ret
)
&&
table_opt_info_
->
unstable_index_name_
.
count
()
>
0
)
{
if
(
OB_FAIL
(
BUF_PRINTF
(
", "
)))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
if
(
OB_FAIL
(
BUF_PRINTF
(
"unstable_index_name["
)))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
{
for
(
int64_t
i
=
0
;
OB_SUCC
(
ret
)
&&
i
<
table_opt_info_
->
unstable_index_name_
.
count
();
++
i
)
{
if
(
OB_FAIL
(
BUF_PRINTF
(
"%.*s"
,
table_opt_info_
->
unstable_index_name_
.
at
(
i
).
length
(),
table_opt_info_
->
unstable_index_name_
.
at
(
i
).
ptr
())))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
if
(
i
!=
table_opt_info_
->
unstable_index_name_
.
count
()
-
1
)
{
if
(
OB_FAIL
(
BUF_PRINTF
(
","
)))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
{
/* do nothing*/
}
}
else
{
/* do nothing*/
}
}
}
if
(
OB_SUCC
(
ret
))
{
if
(
OB_FAIL
(
BUF_PRINTF
(
"]"
)))
{
LOG_WARN
(
"BUF_PRINTF fails"
,
K
(
ret
));
}
else
{
/* Do nothing */
}
}
else
{
/* Do nothing */
}
}
// print est row count infos
if
(
OB_SUCC
(
ret
)
&&
est_records_
.
count
()
>
0
)
{
if
(
OB_FAIL
(
BUF_PRINTF
(
", estimation info[table_id:%ld,"
,
est_records_
.
at
(
0
).
table_id_
)))
{
...
...
src/sql/plan_cache/ob_plan_cache_util.h
浏览文件 @
c84b7de5
...
...
@@ -729,6 +729,10 @@ struct ObPlanStat {
// check whether plan has stable performance
bool
enable_plan_expiration_
;
int64_t
first_exec_row_count_
;
int64_t
first_elapsed_time_
;
int64_t
sample_times_
;
int64_t
sample_exec_row_count_
;
int64_t
sample_exec_usec_
;
uint64_t
sessid_
;
char
plan_tmp_tbl_name_str_
[
STMT_MAX_LEN
];
...
...
unittest/sql/optimizer/test_filter_before_indexback.result
浏览文件 @
c84b7de5
...
...
@@ -178,8 +178,8 @@ SQL: select /*+leading(z1,z2),use_nl(z2)*/ * from z1,z2 where z1.b = z2.b and z2
=============================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
---------------------------------------------
|0 |NESTED-LOOP JOIN| |93 |9
00
8|
|1 | TABLE SCAN |z1
|100 |11
1 |
|0 |NESTED-LOOP JOIN| |93 |9
51
8|
|1 | TABLE SCAN |z1
(z1_b)|100 |62
1 |
|2 | TABLE SCAN |z2(z2_b)|1 |89 |
=============================================
...
...
@@ -187,10 +187,11 @@ Outputs & filters:
-------------------------------------
0 - output([z1.a], [z1.b], [z1.c], [z1.d], [z2.a], [z2.b], [z2.c], [z2.d]), filter(nil),
conds(nil), nl_params_([z1.b]), batch_join=true
1 - output([z1.b], [z1.a], [z1.c], [z1.d]), filter(
[z1.b > ?]
),
1 - output([z1.b], [z1.a], [z1.c], [z1.d]), filter(
nil
),
access([z1.b], [z1.a], [z1.c], [z1.d]), partitions(p0),
is_index_back=false, filter_before_indexback[false],
range_key([z1.a]), range(MIN ; MAX)always true
is_index_back=true,
range_key([z1.b], [z1.a]), range(1,MAX ; MAX,MAX),
range_cond([z1.b > ?])
2 - output([z2.b], [z2.a], [z2.c], [z2.d]), filter([z2.c > ?]),
access([z2.b], [z2.a], [z2.c], [z2.d]), partitions(p0),
is_index_back=true, filter_before_indexback[false],
...
...
unittest/sql/optimizer/test_optimizer_select.result
浏览文件 @
c84b7de5
...
...
@@ -13147,26 +13147,27 @@ Outputs & filters:
SQL: select * from t4 join t7 on t4.c1 = t7.c1 where t4.c2 = 1;
====================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
------------------------------------
|0 |
MERGE JOIN | |100 |286
|
|1 | TABLE SCAN|t
4 |100 |109
|
|2 | TABLE SCAN|t
7 |100 |90
|
====================================
====================================
============
|ID|OPERATOR |NAME
|EST. ROWS|COST|
------------------------------------
------------
|0 |
HASH JOIN | |100 |402
|
|1 | TABLE SCAN|t
7 |100 |90
|
|2 | TABLE SCAN|t
4(idx_t4_c2_c3)|100 |92
|
====================================
============
Outputs & filters:
-------------------------------------
0 - output([t4.c1], [t4.c2], [t4.c3], [t7.c1], [t7.c2]), filter(nil),
equal_conds([t4.c1 = t7.c1]), other_conds(nil)
1 - output([t4.c1], [t4.c2], [t4.c3]), filter([t4.c2 = ?]),
access([t4.c1], [t4.c2], [t4.c3]), partitions(p0),
is_index_back=false, filter_before_indexback[false],
range_key([t4.c1], [t4.c2]), range(MIN,MIN ; MAX,MAX)always true
2 - output([t7.c1], [t7.c2]), filter(nil),
1 - output([t7.c1], [t7.c2]), filter(nil),
access([t7.c1], [t7.c2]), partitions(p0),
is_index_back=false,
range_key([t7.c1]), range(MIN ; MAX)always true
2 - output([t4.c1], [t4.c2], [t4.c3]), filter(nil),
access([t4.c1], [t4.c2], [t4.c3]), partitions(p0),
is_index_back=false,
range_key([t4.c2], [t4.c3], [t4.c1]), range(1,MIN,MIN ; 1,MAX,MAX),
range_cond([t4.c2 = ?])
*************** Case 374(end) **************
...
...
@@ -13260,26 +13261,27 @@ Outputs & filters:
SQL: select * from t4 left join t7 on t4.c1 = t7.c1 where t4.c2 = 5;
=========================================
|ID|OPERATOR
|NAME
|EST. ROWS|COST|
-----------------------------------------
|0 |
MERGE OUTER JOIN| |100 |286
|
|1 | TABLE SCAN
|t4 |100 |109
|
|2 | TABLE SCAN
|t7 |100 |90
|
=========================================
=========================================
=================
|ID|OPERATOR
|NAME
|EST. ROWS|COST|
-----------------------------------------
-----------------
|0 |
HASH RIGHT OUTER JOIN| |100 |402
|
|1 | TABLE SCAN
|t7 |100 |90
|
|2 | TABLE SCAN
|t4(idx_t4_c2_c3)|100 |92
|
=========================================
=================
Outputs & filters:
-------------------------------------
0 - output([t4.c1], [t4.c2], [t4.c3], [t7.c1], [t7.c2]), filter(nil),
equal_conds([t4.c1 = t7.c1]), other_conds(nil)
1 - output([t4.c1], [t4.c2], [t4.c3]), filter([t4.c2 = ?]),
access([t4.c1], [t4.c2], [t4.c3]), partitions(p0),
is_index_back=false, filter_before_indexback[false],
range_key([t4.c1], [t4.c2]), range(MIN,MIN ; MAX,MAX)always true
2 - output([t7.c1], [t7.c2]), filter(nil),
1 - output([t7.c1], [t7.c2]), filter(nil),
access([t7.c1], [t7.c2]), partitions(p0),
is_index_back=false,
range_key([t7.c1]), range(MIN ; MAX)always true
2 - output([t4.c1], [t4.c2], [t4.c3]), filter(nil),
access([t4.c1], [t4.c2], [t4.c3]), partitions(p0),
is_index_back=false,
range_key([t4.c2], [t4.c3], [t4.c1]), range(5,MIN,MIN ; 5,MAX,MAX),
range_cond([t4.c2 = ?])
*************** Case 378(end) **************
...
...
@@ -23460,18 +23462,18 @@ Outputs & filters:
SQL: select c1 from t4 where c1 <=> null and c2 <=> null;
==================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
----------------------------------
|0 |TABLE GET|t4
|1 |52 |
==================================
==================================
=========
|ID|OPERATOR |NAME
|EST. ROWS|COST|
----------------------------------
---------
|0 |TABLE GET|t4
(idx_t4_c2)
|1 |52 |
==================================
=========
Outputs & filters:
-------------------------------------
0 - output([t4.c1]), filter(nil),
access([t4.c1]), partitions(p0),
is_index_back=false,
range_key([t4.c
1], [t4.c2
]), range[NULL,NULL ; NULL,NULL],
range_key([t4.c
2], [t4.c1
]), range[NULL,NULL ; NULL,NULL],
range_cond([t4.c1 <=> ?], [t4.c2 <=> ?])
*************** Case 714(end) **************
...
...
@@ -26418,23 +26420,22 @@ Outputs & filters:
SQL: select * from t1 join t5 on t1.c1 = t5.c3 where t5.c3 > 0 and t5.c3 < 100 order by t5.c3 limit 100;
=============================================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
-------------------------------------------------------------
|0 |LIMIT | |100 |1610|
|1 | PX COORDINATOR MERGE SORT | |100 |1596|
|2 | EXCHANGE OUT DISTR |:EX10001|100 |1573|
|3 | LIMIT | |100 |1573|
|4 | MERGE JOIN | |100 |1559|
|5 | SORT | |294 |608 |
|6 | PX PARTITION ITERATOR | |294 |197 |
|7 | TABLE SCAN |t1 |294 |197 |
|8 | SORT | |177 |827 |
|9 | EXCHANGE IN DISTR | |300 |348 |
|10| EXCHANGE OUT DISTR (PKEY)|:EX10000|300 |305 |
|11| PX PARTITION ITERATOR | |300 |305 |
|12| TABLE SCAN |t5 |300 |305 |
=============================================================
===================================================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
-------------------------------------------------------------------
|0 |LIMIT | |100 |1910|
|1 | PX COORDINATOR MERGE SORT | |100 |1896|
|2 | EXCHANGE OUT DISTR |:EX10001 |100 |1872|
|3 | LIMIT | |100 |1872|
|4 | MERGE JOIN | |100 |1859|
|5 | EXCHANGE IN MERGE SORT DISTR| |177 |1127|
|6 | EXCHANGE OUT DISTR (PKEY) |:EX10000 |177 |1102|
|7 | PX PARTITION ITERATOR | |177 |1102|
|8 | TABLE SCAN |t5(idx_t5_c3)|177 |1102|
|9 | SORT | |294 |608 |
|10| PX PARTITION ITERATOR | |294 |197 |
|11| TABLE SCAN |t1 |294 |197 |
===================================================================
Outputs & filters:
-------------------------------------
...
...
@@ -26444,23 +26445,23 @@ Outputs & filters:
3 - output([t1.c1], [t1.c2], [t5.c1], [t5.c2], [t5.c3]), filter(nil), limit(100), offset(nil)
4 - output([t1.c1], [t1.c2], [t5.c1], [t5.c2], [t5.c3]), filter(nil),
equal_conds([t1.c1 = t5.c3]), other_conds(nil)
5 - output([t1.c1], [t1.c2]), filter(nil), sort_keys([t1.c1, ASC]), local merge sort
6 - output([t1.c1], [t1.c2]), filter(nil),
5 - output([t5.c2], [t5.c3], [t5.c1]), filter(nil), sort_keys([t5.c3, ASC]), Local Order
6 - (#keys=1, [t5.c3]), output([t5.c2], [t5.c3], [t5.c1]), filter(nil), dop=1
7 - output([t5.c2], [t5.c3], [t5.c1]), filter(nil),
force partition granule, asc.
8 - output([t5.c2], [t5.c3], [t5.c1]), filter(nil),
access([t5.c2], [t5.c3], [t5.c1]), partitions(p[0-2]),
is_index_back=true,
range_key([t5.c3], [t5.c2]), range(0,MAX ; 100,MIN),
range_cond([t5.c3 > ?], [t5.c3 < ?])
9 - output([t1.c1], [t1.c2]), filter(nil), sort_keys([t1.c1, ASC]), local merge sort
10 - output([t1.c1], [t1.c2]), filter(nil),
affinitize, force partition granule, asc.
7
- output([t1.c1], [t1.c2]), filter(nil),
11
- output([t1.c1], [t1.c2]), filter(nil),
access([t1.c1], [t1.c2]), partitions(p[0-4]),
is_index_back=false,
range_key([t1.c1]), range(0 ; 100),
range_cond([t1.c1 < ?], [t1.c1 > ?])
8 - output([t5.c1], [t5.c2], [t5.c3]), filter(nil), sort_keys([t5.c3, ASC])
9 - output([t5.c2], [t5.c3], [t5.c1]), filter(nil)
10 - (#keys=1, [t5.c3]), output([t5.c2], [t5.c3], [t5.c1]), filter(nil), dop=1
11 - output([t5.c2], [t5.c3], [t5.c1]), filter(nil),
force partition granule, asc.
12 - output([t5.c2], [t5.c3], [t5.c1]), filter([t5.c3 > ?], [t5.c3 < ?]),
access([t5.c2], [t5.c3], [t5.c1]), partitions(p[0-2]),
is_index_back=false, filter_before_indexback[false,false],
range_key([t5.c2], [t5.c3]), range(MIN,MIN ; MAX,MAX)always true
*************** Case 810(end) **************
...
...
@@ -26468,23 +26469,22 @@ Outputs & filters:
SQL: select * from t1 join t5 on t1.c1 = t5.c3 where t5.c3 > 0 and t5.c3 < 100 order by t5.c3 limit 10000;
=============================================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
-------------------------------------------------------------
|0 |LIMIT | |290 |2332|
|1 | PX COORDINATOR MERGE SORT | |290 |2292|
|2 | EXCHANGE OUT DISTR |:EX10001|290 |2223|
|3 | LIMIT | |290 |2223|
|4 | MERGE JOIN | |290 |2183|
|5 | SORT | |500 |1074|
|6 | PX PARTITION ITERATOR | |500 |342 |
|7 | TABLE SCAN |t1 |500 |342 |
|8 | SORT | |300 |827 |
|9 | EXCHANGE IN DISTR | |300 |348 |
|10| EXCHANGE OUT DISTR (PKEY)|:EX10000|300 |305 |
|11| PX PARTITION ITERATOR | |300 |305 |
|12| TABLE SCAN |t5 |300 |305 |
=============================================================
===================================================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
-------------------------------------------------------------------
|0 |LIMIT | |290 |3390|
|1 | PX COORDINATOR MERGE SORT | |290 |3350|
|2 | EXCHANGE OUT DISTR |:EX10001 |290 |3281|
|3 | LIMIT | |290 |3281|
|4 | MERGE JOIN | |290 |3241|
|5 | EXCHANGE IN MERGE SORT DISTR| |300 |1885|
|6 | EXCHANGE OUT DISTR (PKEY) |:EX10000 |300 |1842|
|7 | PX PARTITION ITERATOR | |300 |1842|
|8 | TABLE SCAN |t5(idx_t5_c3)|300 |1842|
|9 | SORT | |500 |1074|
|10| PX PARTITION ITERATOR | |500 |342 |
|11| TABLE SCAN |t1 |500 |342 |
===================================================================
Outputs & filters:
-------------------------------------
...
...
@@ -26494,23 +26494,23 @@ Outputs & filters:
3 - output([t1.c1], [t1.c2], [t5.c1], [t5.c2], [t5.c3]), filter(nil), limit(10000), offset(nil)
4 - output([t1.c1], [t1.c2], [t5.c1], [t5.c2], [t5.c3]), filter(nil),
equal_conds([t1.c1 = t5.c3]), other_conds(nil)
5 - output([t1.c1], [t1.c2]), filter(nil), sort_keys([t1.c1, ASC]), local merge sort
6 - output([t1.c1], [t1.c2]), filter(nil),
5 - output([t5.c2], [t5.c3], [t5.c1]), filter(nil), sort_keys([t5.c3, ASC]), Local Order
6 - (#keys=1, [t5.c3]), output([t5.c2], [t5.c3], [t5.c1]), filter(nil), dop=1
7 - output([t5.c2], [t5.c3], [t5.c1]), filter(nil),
force partition granule, asc.
8 - output([t5.c2], [t5.c3], [t5.c1]), filter(nil),
access([t5.c2], [t5.c3], [t5.c1]), partitions(p[0-2]),
is_index_back=true,
range_key([t5.c3], [t5.c2]), range(0,MAX ; 100,MIN),
range_cond([t5.c3 > ?], [t5.c3 < ?])
9 - output([t1.c1], [t1.c2]), filter(nil), sort_keys([t1.c1, ASC]), local merge sort
10 - output([t1.c1], [t1.c2]), filter(nil),
affinitize, force partition granule, asc.
7
- output([t1.c1], [t1.c2]), filter(nil),
11
- output([t1.c1], [t1.c2]), filter(nil),
access([t1.c1], [t1.c2]), partitions(p[0-4]),
is_index_back=false,
range_key([t1.c1]), range(0 ; 100),
range_cond([t1.c1 < ?], [t1.c1 > ?])
8 - output([t5.c1], [t5.c2], [t5.c3]), filter(nil), sort_keys([t5.c3, ASC])
9 - output([t5.c2], [t5.c3], [t5.c1]), filter(nil)
10 - (#keys=1, [t5.c3]), output([t5.c2], [t5.c3], [t5.c1]), filter(nil), dop=1
11 - output([t5.c2], [t5.c3], [t5.c1]), filter(nil),
force partition granule, asc.
12 - output([t5.c2], [t5.c3], [t5.c1]), filter([t5.c3 > ?], [t5.c3 < ?]),
access([t5.c2], [t5.c3], [t5.c1]), partitions(p[0-2]),
is_index_back=false, filter_before_indexback[false,false],
range_key([t5.c2], [t5.c3]), range(MIN,MIN ; MAX,MAX)always true
*************** Case 811(end) **************
unittest/sql/optimizer/test_optimizer_used_hint.result
浏览文件 @
c84b7de5
此差异已折叠。
点击以展开。
unittest/sql/rewrite/result/test_transformer_plan_after_trans_aggr.result
浏览文件 @
c84b7de5
...
...
@@ -2041,15 +2041,13 @@ Outputs & filters:
*************** Case 85 ***************
SQL: select max(c3) from t9 where c2 = 1 and c1 = 1;
=========================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
-----------------------------------------
|0 |SCALAR GROUP BY| |1 |151 |
|1 | SUBPLAN SCAN |VIEW1|1 |150 |
|2 | LIMIT | |1 |150 |
|3 | TOP-N SORT | |1 |150 |
|4 | TABLE SCAN |t9 |1 |149 |
=========================================
======================================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
------------------------------------------------------
|0 |SCALAR GROUP BY| |1 |678 |
|1 | SUBPLAN SCAN |VIEW1 |1 |678 |
|2 | TABLE SCAN |t9(idx_t9,Reverse)|1 |677 |
======================================================
Outputs & filters:
-------------------------------------
...
...
@@ -2057,10 +2055,9 @@ Outputs & filters:
group(nil), agg_func([T_FUN_MAX(VIEW1.c3)])
1 - output([VIEW1.c3]), filter(nil),
access([VIEW1.c3])
2 - output([t9.c3]), filter(nil), limit(1), offset(nil)
3 - output([t9.c3]), filter(nil), sort_keys([t9.c3, DESC]), topn(1)
4 - output([t9.c3]), filter([t9.c2 = ?], [t9.c1 = ?], [(T_OP_IS_NOT, t9.c3, NULL, 0)]),
access([t9.c2], [t9.c1], [t9.c3]), partitions(p0)
2 - output([t9.c3]), filter([t9.c1 = ?], [(T_OP_IS_NOT, t9.c3, NULL, 0)]),
access([t9.c1], [t9.c3]), partitions(p0),
limit(1), offset(nil)
*************** Case 86 ***************
SQL: select max(c3) from t9 where c2 != 1;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录