提交 3763a40a 编写于 作者: S serge-rider

MySQL execution plan serialize/deserialize

上级 d553a066
......@@ -16,21 +16,33 @@
*/
package org.jkiss.dbeaver.ext.mysql.model.plan;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.ext.mysql.model.MySQLDataSource;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCSession;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.exec.plan.DBCPlan;
import org.jkiss.dbeaver.model.exec.plan.DBCPlanStyle;
import org.jkiss.dbeaver.model.exec.plan.DBCQueryPlanner;
import org.jkiss.dbeaver.model.exec.plan.*;
import org.jkiss.dbeaver.model.impl.plan.AbstractExecutionPlanSerializer;
import org.jkiss.dbeaver.model.impl.plan.ExecutionPlanDeserializer;
import org.jkiss.utils.CommonUtils;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* MySQL execution plan analyser
*/
public class MySQLPlanAnalyser implements DBCQueryPlanner {
public class MySQLPlanAnalyser extends AbstractExecutionPlanSerializer implements DBCQueryPlanner {
private MySQLDataSource dataSource;
......@@ -71,4 +83,83 @@ public class MySQLPlanAnalyser implements DBCQueryPlanner {
return DBCPlanStyle.PLAN;
}
@Override
public void serialize(@NotNull Writer writer, @NotNull DBCPlan plan) throws IOException, InvocationTargetException {
serializeJson(writer, plan, dataSource.getInfo().getDriverName(), new DBCQueryPlannerSerialInfo() {
@Override
public String version() {
return plan instanceof MySQLPlanClassic ? "classic" : "json";
}
@Override
public void addNodeProperties(DBCPlanNode node, JsonObject nodeJson) {
JsonObject attributes = new JsonObject();
if (node instanceof MySQLPlanNodePlain) {
MySQLPlanNodePlain plainNode = (MySQLPlanNodePlain) node;
attributes.add("id", new JsonPrimitive(plainNode.getId()));
attributes.add("select_type", new JsonPrimitive(plainNode.getSelectType()));
attributes.add("table", new JsonPrimitive(plainNode.getTable()));
attributes.add("type", new JsonPrimitive(plainNode.getNodeType()));
attributes.add("possible_keys", new JsonPrimitive(plainNode.getPossibleKeys()));
attributes.add("key", new JsonPrimitive(plainNode.getKey()));
attributes.add("key_len", new JsonPrimitive(plainNode.getKeyLength()));
attributes.add("ref", new JsonPrimitive(plainNode.getRef()));
attributes.add("rows", new JsonPrimitive(plainNode.getRowCount()));
attributes.add("filtered", new JsonPrimitive(plainNode.getFiltered()));
attributes.add("extra", new JsonPrimitive(plainNode.getExtra()));
} else if (node instanceof MySQLPlanNodeJSON) {
MySQLPlanNodeJSON jsNode = (MySQLPlanNodeJSON) node;
for(Map.Entry<String, String> e : jsNode.getNodeProps().entrySet()) {
attributes.add(e.getKey(), new JsonPrimitive(CommonUtils.notEmpty(e.getValue())));
}
}
nodeJson.add(PROP_ATTRIBUTES, attributes);
}
});
/*
if (plan instanceof MySQLPlanClassic) {
serializeJson(planData, plan,dataSource.getInfo().getDriverName(),(MySQLPlanClassic) plan);
} else if (plan instanceof MySQLPlanJSON) {
serializeJson(planData, plan,dataSource.getInfo().getDriverName(),(MySQLPlanJSON) plan);
}
*/
}
private static Map<String, String> getNodeAttributes(JsonObject nodeObject){
Map<String,String> attributes = new HashMap<>();
JsonObject attrs = nodeObject.getAsJsonObject(PROP_ATTRIBUTES);
for(Map.Entry<String, JsonElement> attr : attrs.entrySet()) {
attributes.put(attr.getKey(), attr.getValue().getAsString());
}
return attributes;
}
@Override
public DBCPlan deserialize(@NotNull Reader planData) throws IOException, InvocationTargetException {
JsonObject jo = new JsonParser().parse(planData).getAsJsonObject();
String savedVersion = jo.get(AbstractExecutionPlanSerializer.PROP_VERSION).getAsString();
String query = jo.get(AbstractExecutionPlanSerializer.PROP_SQL).getAsString();
if (savedVersion.equals("classic")) {
ExecutionPlanDeserializer<MySQLPlanNodePlain> loader = new ExecutionPlanDeserializer<>();
List<MySQLPlanNodePlain> rootNodes = loader.loadRoot(dataSource, jo,
(datasource, node, parent) -> new MySQLPlanNodePlain(parent, getNodeAttributes(node)));
return new MySQLPlanClassic(dataSource, query, rootNodes);
} else {
ExecutionPlanDeserializer<MySQLPlanNodeJSON> loader = new ExecutionPlanDeserializer<>();
List<MySQLPlanNodeJSON> rootNodes = loader.loadRoot(dataSource, jo,
(datasource, node, parent) -> new MySQLPlanNodeJSON(parent, getNodeAttributes(node)));
return new MySQLPlanJSON(dataSource,query,rootNodes);
}
}
}
......@@ -62,6 +62,11 @@ public class MySQLPlanClassic extends MySQLPlanAbstract {
}
}
public MySQLPlanClassic(MySQLDataSource dataSource, String query, List<MySQLPlanNodePlain> rootNodes) {
super(dataSource, query);
this.rootNodes = rootNodes;
}
@Override
public Object getPlanFeature(String feature) {
if (DBCPlanCostNode.FEATURE_PLAN_ROWS.equals(feature)) {
......
......@@ -98,6 +98,11 @@ public class MySQLPlanJSON extends MySQLPlanAbstract {
}
}
public MySQLPlanJSON(MySQLDataSource dataSource, String query, List<MySQLPlanNodeJSON> rootNodes) {
super(dataSource, query);
this.rootNodes = rootNodes;
}
@Override
public Object getPlanFeature(String feature) {
if (dataSource.isMariaDB()) {
......
......@@ -37,8 +37,8 @@ public class MySQLPlanNodeJSON extends MySQLPlanNode implements DBPPropertySourc
private MySQLPlanNodeJSON parent;
private String name;
private JsonObject object;
private Map<String, Object> nodeProps = new LinkedHashMap<>();
private List<MySQLPlanNodeJSON> nested;
private Map<String, String> nodeProps = new LinkedHashMap<>();
private List<MySQLPlanNodeJSON> nested = new ArrayList<>();
public MySQLPlanNodeJSON(MySQLPlanNodeJSON parent, String name, JsonObject object) {
this.parent = parent;
......@@ -48,6 +48,15 @@ public class MySQLPlanNodeJSON extends MySQLPlanNode implements DBPPropertySourc
parseObject(name, object);
}
public MySQLPlanNodeJSON(MySQLPlanNodeJSON parent, Map<String, String> attributes) {
this.parent = parent;
this.nodeProps.putAll(attributes);
}
public Map<String, String> getNodeProps() {
return nodeProps;
}
private void parseObject(String objName, JsonObject object) {
for (Map.Entry<String, JsonElement> prop : object.entrySet()) {
String propName = prop.getKey();
......@@ -186,7 +195,7 @@ public class MySQLPlanNodeJSON extends MySQLPlanNode implements DBPPropertySourc
@Override
public String toString() {
return object.toString();
return object == null ? nodeProps.toString() : object.toString();
}
//////////////////////////////////////////////////////////
......@@ -201,7 +210,7 @@ public class MySQLPlanNodeJSON extends MySQLPlanNode implements DBPPropertySourc
public DBPPropertyDescriptor[] getPropertyDescriptors2() {
DBPPropertyDescriptor[] props = new DBPPropertyDescriptor[nodeProps.size()];
int index = 0;
for (Map.Entry<String, Object> attr : nodeProps.entrySet()) {
for (Map.Entry<String, String> attr : nodeProps.entrySet()) {
props[index++] = new PropertyDescriptor(
"Details",
attr.getKey(),
......
......@@ -26,6 +26,7 @@ import org.jkiss.utils.CommonUtils;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* MySQL execution plan node.
......@@ -84,6 +85,21 @@ public class MySQLPlanNodePlain extends MySQLPlanNode {
this.extra = JDBCUtils.safeGetString(dbResult, "extra");
}
public MySQLPlanNodePlain(MySQLPlanNodePlain parent, Map<String, String> props) {
this.parent = parent;
this.id = props.containsKey("id") ? CommonUtils.toInt(props.get("id")) : null;
this.selectType = props.get("select_type");
this.table = props.get("table");
this.type = props.get("type");
this.possibleKeys = props.get("possible_keys");
this.key = props.get("key");
this.keyLength = props.get("key_len");
this.ref = props.get("ref");
this.rowCount = props.containsKey("rows") ? CommonUtils.toLong(props.get("rows")) : null;
this.filtered = props.containsKey("filtered") ? CommonUtils.toLong(props.get("filtered")) : null;
this.extra = props.get("extra");
}
public MySQLPlanNodePlain(MySQLPlanNodePlain parent, String type) {
this.parent = parent;
this.selectType = type;
......
......@@ -101,9 +101,7 @@ public class PostgreQueryPlaner extends AbstractExecutionPlanSerializer implemen
@Override
public DBCPlan deserialize(@NotNull Reader planData) throws IOException, InvocationTargetException {
try {
JsonObject jo = new JsonParser().parse(planData).getAsJsonObject();
String query = jo.get(AbstractExecutionPlanSerializer.PROP_SQL).getAsString();
......
......@@ -22,9 +22,9 @@ import com.google.gson.JsonObject;
public interface DBCQueryPlannerSerialInfo {
public String version();
String version();
public void addNodeProperties(DBCPlanNode node,JsonObject nodeJson);
void addNodeProperties(DBCPlanNode node,JsonObject nodeJson);
}
......@@ -64,16 +64,15 @@ public abstract class AbstractExecutionPlanSerializer implements DBCQueryPlanne
info.addNodeProperties(node,nodeJson);
JsonArray nodes = new JsonArray();
if (node.getNested() != null) {
if (!CommonUtils.isEmpty(node.getNested())) {
JsonArray nodes = new JsonArray();
for(DBCPlanNode childNode : node.getNested()) {
nodes.add(serializeNode(childNode,info));
}
nodeJson.add(PROP_CHILD, nodes);
}
nodeJson.add(PROP_CHILD, nodes);
return nodeJson;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册