Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
suliangchun
dbeaver
提交
7b1679bd
D
dbeaver
项目概览
suliangchun
/
dbeaver
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dbeaver
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
7b1679bd
编写于
2月 19, 2019
作者:
S
Serge Rider
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
MySQL plan analyzer improvements
上级
e88a0d75
变更
5
显示空白变更内容
内联
并排
Showing
5 changed file
with
309 addition
and
144 deletion
+309
-144
plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/MySQLDataSource.java
...rc/org/jkiss/dbeaver/ext/mysql/model/MySQLDataSource.java
+1
-3
plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanAbstract.java
...jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanAbstract.java
+49
-0
plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanAnalyser.java
...jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanAnalyser.java
+10
-141
plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanClassic.java
.../jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanClassic.java
+164
-0
plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanJSON.java
...org/jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanJSON.java
+85
-0
未找到文件。
plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/MySQLDataSource.java
浏览文件 @
7b1679bd
...
...
@@ -612,9 +612,7 @@ public class MySQLDataSource extends JDBCDataSource implements DBSObjectSelector
@Override
public
DBCPlan
planQueryExecution
(
@NotNull
DBCSession
session
,
@NotNull
String
query
)
throws
DBCException
{
MySQLPlanAnalyser
plan
=
new
MySQLPlanAnalyser
(
this
,
query
);
plan
.
explain
(
session
);
return
plan
;
return
new
MySQLPlanAnalyser
(
this
).
explain
(
session
,
query
);
}
@NotNull
...
...
plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanAbstract.java
0 → 100644
浏览文件 @
7b1679bd
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2019 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.jkiss.dbeaver.ext.mysql.model.plan
;
import
org.jkiss.dbeaver.ext.mysql.model.MySQLDataSource
;
import
org.jkiss.dbeaver.model.exec.DBCException
;
import
org.jkiss.dbeaver.model.exec.DBCSession
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCSession
;
import
org.jkiss.dbeaver.model.exec.plan.DBCPlanCostNode
;
import
org.jkiss.dbeaver.model.exec.plan.DBCPlanNode
;
import
org.jkiss.dbeaver.model.impl.plan.AbstractExecutionPlan
;
import
org.jkiss.dbeaver.model.sql.SQLUtils
;
import
org.jkiss.utils.CommonUtils
;
import
java.sql.SQLException
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
/**
* MySQL execution plan analyser
*/
public
abstract
class
MySQLPlanAbstract
extends
AbstractExecutionPlan
{
protected
MySQLDataSource
dataSource
;
protected
String
query
;
public
MySQLPlanAbstract
(
MySQLDataSource
dataSource
,
String
query
)
{
this
.
dataSource
=
dataSource
;
this
.
query
=
query
;
}
}
plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanAnalyser.java
浏览文件 @
7b1679bd
...
...
@@ -19,163 +19,32 @@ package org.jkiss.dbeaver.ext.mysql.model.plan;
import
org.jkiss.dbeaver.ext.mysql.model.MySQLDataSource
;
import
org.jkiss.dbeaver.model.exec.DBCException
;
import
org.jkiss.dbeaver.model.exec.DBCSession
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCSession
;
import
org.jkiss.dbeaver.model.exec.plan.DBCPlanCostNode
;
import
org.jkiss.dbeaver.model.exec.plan.DBCPlanNode
;
import
org.jkiss.dbeaver.model.impl.plan.AbstractExecutionPlan
;
import
org.jkiss.dbeaver.model.sql.SQLUtils
;
import
org.jkiss.utils.CommonUtils
;
import
java.sql.SQLException
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
/**
* MySQL execution plan analyser
*/
public
class
MySQLPlanAnalyser
extends
AbstractExecutionPlan
{
public
class
MySQLPlanAnalyser
{
private
MySQLDataSource
dataSource
;
private
String
query
;
private
List
<
MySQLPlanNodePlain
>
rootNodes
;
public
MySQLPlanAnalyser
(
MySQLDataSource
dataSource
,
String
query
)
{
public
MySQLPlanAnalyser
(
MySQLDataSource
dataSource
)
{
this
.
dataSource
=
dataSource
;
this
.
query
=
query
;
}
@Override
public
Object
getPlanFeature
(
String
feature
)
{
if
(
DBCPlanCostNode
.
FEATURE_PLAN_ROWS
.
equals
(
feature
))
{
return
true
;
}
return
super
.
getPlanFeature
(
feature
);
}
@Override
public
String
getQueryString
()
{
return
query
;
}
@Override
public
String
getPlanQueryString
()
{
return
"EXPLAIN EXTENDED "
+
query
;
}
@Override
public
List
<?
extends
DBCPlanNode
>
getPlanNodes
(
Map
<
String
,
Object
>
options
)
{
if
(
CommonUtils
.
getOption
(
options
,
OPTION_KEEP_ORIGINAL
))
{
return
rootNodes
;
public
MySQLPlanAbstract
explain
(
DBCSession
session
,
String
query
)
throws
DBCException
{
if
(
supportsExplainJSON
())
{
return
new
MySQLPlanJSON
(
dataSource
,
query
);
}
else
{
List
<
MySQLPlanNodePlain
>
rootCopy
=
new
ArrayList
<>(
rootNodes
.
size
());
for
(
MySQLPlanNodePlain
r
:
rootNodes
)
{
rootCopy
.
add
(
r
.
copyNode
(
null
));
}
return
convertToPlanTree
(
rootCopy
);
}
}
public
void
explain
(
DBCSession
session
)
throws
DBCException
{
String
plainQuery
=
SQLUtils
.
stripComments
(
SQLUtils
.
getDialectFromObject
(
session
.
getDataSource
()),
query
).
toUpperCase
();
if
(!
plainQuery
.
startsWith
(
"SELECT"
))
{
throw
new
DBCException
(
"Only SELECT statements could produce execution plan"
);
}
JDBCSession
connection
=
(
JDBCSession
)
session
;
try
{
try
(
JDBCPreparedStatement
dbStat
=
connection
.
prepareStatement
(
getPlanQueryString
()))
{
try
(
JDBCResultSet
dbResult
=
dbStat
.
executeQuery
())
{
List
<
MySQLPlanNodePlain
>
nodes
=
new
ArrayList
<>();
while
(
dbResult
.
next
())
{
MySQLPlanNodePlain
node
=
new
MySQLPlanNodePlain
(
null
,
dbResult
);
nodes
.
add
(
node
);
}
rootNodes
=
nodes
;
return
new
MySQLPlanClassic
(
dataSource
,
query
);
}
}
}
catch
(
SQLException
e
)
{
throw
new
DBCException
(
e
,
session
.
getDataSource
());
}
}
private
List
<
MySQLPlanNodePlain
>
convertToPlanTree
(
List
<
MySQLPlanNodePlain
>
srcNodes
)
{
List
<
MySQLPlanNodePlain
>
roots
=
new
ArrayList
<>();
if
(
srcNodes
.
size
()
==
1
)
{
// Just one node
roots
.
add
(
srcNodes
.
get
(
0
));
}
else
{
List
<
MySQLPlanNodePlain
>
parsed
=
new
ArrayList
<>();
MySQLPlanNodePlain
lastCompositeNode
=
null
;
for
(
int
id
=
1
;
;
id
++)
{
List
<
MySQLPlanNodePlain
>
nodes
=
getQueriesById
(
srcNodes
,
id
);
if
(
nodes
.
isEmpty
())
{
break
;
}
if
(
nodes
.
size
()
==
1
)
{
MySQLPlanNodePlain
firstNode
=
nodes
.
get
(
0
);
if
(
lastCompositeNode
!=
null
)
{
firstNode
.
setParent
(
lastCompositeNode
);
private
boolean
supportsExplainJSON
()
{
if
(
dataSource
.
isMariaDB
())
{
return
dataSource
.
isServerVersionAtLeast
(
10
,
1
);
}
else
{
roots
.
add
(
firstNode
);
}
if
(
firstNode
.
isCompositeNode
())
{
lastCompositeNode
=
firstNode
;
}
}
else
{
MySQLPlanNodePlain
leftNode
=
lastCompositeNode
;
if
(
leftNode
==
null
)
{
leftNode
=
nodes
.
get
(
0
).
getParent
();
}
MySQLPlanNodePlain
joinNode
=
joinNodes
(
srcNodes
,
leftNode
,
nodes
);
if
(
leftNode
==
null
)
{
roots
.
add
(
joinNode
);
}
}
parsed
.
addAll
(
nodes
);
}
// Add the rest
for
(
MySQLPlanNodePlain
node
:
srcNodes
)
{
if
(
node
.
getId
()
!=
null
&&
!
parsed
.
contains
(
node
))
{
roots
.
add
(
node
);
}
}
}
for
(
MySQLPlanNodePlain
node
:
roots
)
{
node
.
computeStats
();
}
return
roots
;
}
private
List
<
MySQLPlanNodePlain
>
getQueriesById
(
List
<
MySQLPlanNodePlain
>
srcNodes
,
int
id
)
{
List
<
MySQLPlanNodePlain
>
subList
=
new
ArrayList
<>();
for
(
MySQLPlanNodePlain
node
:
srcNodes
)
{
if
(
node
.
getId
()
!=
null
&&
node
.
getId
()
==
id
)
{
subList
.
add
(
node
);
}
}
return
subList
;
}
private
MySQLPlanNodePlain
joinNodes
(
List
<
MySQLPlanNodePlain
>
srcNodes
,
MySQLPlanNodePlain
parent
,
List
<
MySQLPlanNodePlain
>
nodes
)
{
MySQLPlanNodePlain
leftNode
=
nodes
.
get
(
0
);
for
(
int
i
=
1
;
i
<
nodes
.
size
();
i
++)
{
MySQLPlanNodePlain
rightNode
=
nodes
.
get
(
i
);
MySQLPlanNodeJoin
nodeJoin
=
new
MySQLPlanNodeJoin
(
parent
,
leftNode
,
rightNode
);
leftNode
.
setParent
(
nodeJoin
);
rightNode
.
setParent
(
nodeJoin
);
if
(
parent
!=
null
)
{
nodeJoin
.
setParent
(
parent
);
}
leftNode
=
nodeJoin
;
return
dataSource
.
isServerVersionAtLeast
(
5
,
6
);
}
return
leftNode
;
}
}
plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanClassic.java
0 → 100644
浏览文件 @
7b1679bd
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2019 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.jkiss.dbeaver.ext.mysql.model.plan
;
import
org.jkiss.dbeaver.ext.mysql.model.MySQLDataSource
;
import
org.jkiss.dbeaver.model.exec.DBCException
;
import
org.jkiss.dbeaver.model.exec.DBCSession
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCSession
;
import
org.jkiss.dbeaver.model.exec.plan.DBCPlanCostNode
;
import
org.jkiss.dbeaver.model.exec.plan.DBCPlanNode
;
import
org.jkiss.dbeaver.model.impl.plan.AbstractExecutionPlan
;
import
org.jkiss.dbeaver.model.sql.SQLUtils
;
import
org.jkiss.utils.CommonUtils
;
import
java.sql.SQLException
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
/**
* MySQL execution plan analyser
*/
public
class
MySQLPlanClassic
extends
MySQLPlanAbstract
{
private
List
<
MySQLPlanNodePlain
>
rootNodes
;
public
MySQLPlanClassic
(
JDBCSession
session
,
String
query
)
throws
DBCException
{
super
((
MySQLDataSource
)
session
.
getDataSource
(),
query
);
String
plainQuery
=
SQLUtils
.
stripComments
(
SQLUtils
.
getDialectFromObject
(
dataSource
),
query
).
toUpperCase
();
if
(!
plainQuery
.
startsWith
(
"SELECT"
))
{
throw
new
DBCException
(
"Only SELECT statements could produce execution plan"
);
}
try
(
JDBCPreparedStatement
dbStat
=
session
.
prepareStatement
(
getPlanQueryString
()))
{
try
(
JDBCResultSet
dbResult
=
dbStat
.
executeQuery
())
{
List
<
MySQLPlanNodePlain
>
nodes
=
new
ArrayList
<>();
while
(
dbResult
.
next
())
{
MySQLPlanNodePlain
node
=
new
MySQLPlanNodePlain
(
null
,
dbResult
);
nodes
.
add
(
node
);
}
rootNodes
=
nodes
;
}
}
catch
(
SQLException
e
)
{
throw
new
DBCException
(
e
,
session
.
getDataSource
());
}
}
@Override
public
Object
getPlanFeature
(
String
feature
)
{
if
(
DBCPlanCostNode
.
FEATURE_PLAN_ROWS
.
equals
(
feature
))
{
return
true
;
}
return
super
.
getPlanFeature
(
feature
);
}
@Override
public
String
getQueryString
()
{
return
query
;
}
@Override
public
String
getPlanQueryString
()
{
return
"EXPLAIN EXTENDED "
+
query
;
}
@Override
public
List
<?
extends
DBCPlanNode
>
getPlanNodes
(
Map
<
String
,
Object
>
options
)
{
return
rootNodes
;
}
private
List
<
MySQLPlanNodePlain
>
convertToPlanTree
(
List
<
MySQLPlanNodePlain
>
srcNodes
)
{
List
<
MySQLPlanNodePlain
>
roots
=
new
ArrayList
<>();
if
(
srcNodes
.
size
()
==
1
)
{
// Just one node
roots
.
add
(
srcNodes
.
get
(
0
));
}
else
{
List
<
MySQLPlanNodePlain
>
parsed
=
new
ArrayList
<>();
MySQLPlanNodePlain
lastCompositeNode
=
null
;
for
(
int
id
=
1
;
;
id
++)
{
List
<
MySQLPlanNodePlain
>
nodes
=
getQueriesById
(
srcNodes
,
id
);
if
(
nodes
.
isEmpty
())
{
break
;
}
if
(
nodes
.
size
()
==
1
)
{
MySQLPlanNodePlain
firstNode
=
nodes
.
get
(
0
);
if
(
lastCompositeNode
!=
null
)
{
firstNode
.
setParent
(
lastCompositeNode
);
}
else
{
roots
.
add
(
firstNode
);
}
if
(
firstNode
.
isCompositeNode
())
{
lastCompositeNode
=
firstNode
;
}
}
else
{
MySQLPlanNodePlain
leftNode
=
lastCompositeNode
;
if
(
leftNode
==
null
)
{
leftNode
=
nodes
.
get
(
0
).
getParent
();
}
MySQLPlanNodePlain
joinNode
=
joinNodes
(
srcNodes
,
leftNode
,
nodes
);
if
(
leftNode
==
null
)
{
roots
.
add
(
joinNode
);
}
}
parsed
.
addAll
(
nodes
);
}
// Add the rest
for
(
MySQLPlanNodePlain
node
:
srcNodes
)
{
if
(
node
.
getId
()
!=
null
&&
!
parsed
.
contains
(
node
))
{
roots
.
add
(
node
);
}
}
}
for
(
MySQLPlanNodePlain
node
:
roots
)
{
node
.
computeStats
();
}
return
roots
;
}
private
List
<
MySQLPlanNodePlain
>
getQueriesById
(
List
<
MySQLPlanNodePlain
>
srcNodes
,
int
id
)
{
List
<
MySQLPlanNodePlain
>
subList
=
new
ArrayList
<>();
for
(
MySQLPlanNodePlain
node
:
srcNodes
)
{
if
(
node
.
getId
()
!=
null
&&
node
.
getId
()
==
id
)
{
subList
.
add
(
node
);
}
}
return
subList
;
}
private
MySQLPlanNodePlain
joinNodes
(
List
<
MySQLPlanNodePlain
>
srcNodes
,
MySQLPlanNodePlain
parent
,
List
<
MySQLPlanNodePlain
>
nodes
)
{
MySQLPlanNodePlain
leftNode
=
nodes
.
get
(
0
);
for
(
int
i
=
1
;
i
<
nodes
.
size
();
i
++)
{
MySQLPlanNodePlain
rightNode
=
nodes
.
get
(
i
);
MySQLPlanNodeJoin
nodeJoin
=
new
MySQLPlanNodeJoin
(
parent
,
leftNode
,
rightNode
);
leftNode
.
setParent
(
nodeJoin
);
rightNode
.
setParent
(
nodeJoin
);
if
(
parent
!=
null
)
{
nodeJoin
.
setParent
(
parent
);
}
leftNode
=
nodeJoin
;
}
return
leftNode
;
}
}
plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/plan/MySQLPlanJSON.java
0 → 100644
浏览文件 @
7b1679bd
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2019 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.jkiss.dbeaver.ext.mysql.model.plan
;
import
org.jkiss.dbeaver.ext.mysql.model.MySQLDataSource
;
import
org.jkiss.dbeaver.model.exec.DBCException
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet
;
import
org.jkiss.dbeaver.model.exec.jdbc.JDBCSession
;
import
org.jkiss.dbeaver.model.exec.plan.DBCPlanCostNode
;
import
org.jkiss.dbeaver.model.sql.SQLUtils
;
import
java.sql.SQLException
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
/**
* MySQL JSON plan
*/
public
class
MySQLPlanJSON
extends
MySQLPlanAbstract
{
private
List
<
MySQLPlanNodeJSON
>
rootNodes
;
public
MySQLPlanJSON
(
JDBCSession
session
,
String
query
)
throws
DBCException
{
super
((
MySQLDataSource
)
session
.
getDataSource
(),
query
);
String
plainQuery
=
SQLUtils
.
stripComments
(
SQLUtils
.
getDialectFromObject
(
dataSource
),
query
).
toUpperCase
();
if
(!
plainQuery
.
startsWith
(
"SELECT"
))
{
throw
new
DBCException
(
"Only SELECT statements could produce execution plan"
);
}
try
(
JDBCPreparedStatement
dbStat
=
session
.
prepareStatement
(
getPlanQueryString
()))
{
try
(
JDBCResultSet
dbResult
=
dbStat
.
executeQuery
())
{
List
<
MySQLPlanNodeJSON
>
nodes
=
new
ArrayList
<>();
while
(
dbResult
.
next
())
{
// MySQLPlanNodePlain node = new MySQLPlanNodePlain(null, dbResult);
// nodes.add(node);
}
rootNodes
=
nodes
;
}
}
catch
(
SQLException
e
)
{
throw
new
DBCException
(
e
,
session
.
getDataSource
());
}
}
@Override
public
Object
getPlanFeature
(
String
feature
)
{
if
(
DBCPlanCostNode
.
FEATURE_PLAN_ROWS
.
equals
(
feature
))
{
return
true
;
}
return
super
.
getPlanFeature
(
feature
);
}
@Override
public
String
getQueryString
()
{
return
query
;
}
@Override
public
String
getPlanQueryString
()
{
return
"EXPLAIN EXTENDED "
+
query
;
}
@Override
public
List
<
MySQLPlanNodeJSON
>
getPlanNodes
(
Map
<
String
,
Object
>
options
)
{
return
rootNodes
;
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录