[Optimize] optimize some session variable and profile (#6920)

1. optimize error message when using batch delete
2. rename session variable is_report_success to enable_profile
3. add table name to OlapScanner profile
This commit is contained in:
Zhengguo Yang
2021-10-27 18:03:12 +08:00
committed by GitHub
parent a4a7e642b4
commit 4170aabf83
22 changed files with 70 additions and 44 deletions

View File

@ -96,7 +96,11 @@ Status OlapScanNode::init(const TPlanNode& tnode, RuntimeState* state) {
}
void OlapScanNode::init_scan_profile() {
_scanner_profile.reset(new RuntimeProfile("OlapScanner"));
std::string scanner_profile_name = "OlapScanner";
if (_olap_scan_node.__isset.table_name) {
scanner_profile_name = fmt::format("OlapScanner({0})", _olap_scan_node.table_name);
}
_scanner_profile.reset(new RuntimeProfile(scanner_profile_name));
runtime_profile()->add_child(_scanner_profile.get(), true, NULL);
_segment_profile.reset(new RuntimeProfile("SegmentIterator"));

View File

@ -463,7 +463,7 @@ We will only discuss the case of a single BE. If the user cluster has more than
### Performance analysis
You can execute `set is_report_success=true` to open the load job profile before submitting the import job. After the import job is completed, you can view the profile of the import job in the `Queris` tab of the FE web page.
You can execute `set enable_profile=true` to open the load job profile before submitting the import job. After the import job is completed, you can view the profile of the import job in the `Queris` tab of the FE web page.
This profile can help analyze the running status of the import job.

View File

@ -44,10 +44,10 @@ FE splits the query plan into fragments and distributes them to BE for task exec
Turn on the report switch on FE through MySQL command
```
mysql> set is_report_success=true;
mysql> set enable_profile=true;
```
After executing the corresponding SQL statement, we can see the report information of the corresponding SQL statement on the FE web page like the picture below.
After executing the corresponding SQL statement(`is_report_success` in old versions), we can see the report information of the corresponding SQL statement on the FE web page like the picture below.
![image.png](/images/running_profile.png)
The latest **100 statements** executed will be listed here. We can view detailed statistics of RunningProfile.

View File

@ -251,7 +251,7 @@ EXPLAIN SELECT t1 FROM test JOIN test2 where test.t1 = test2.t2;
SELECT t1 FROM test JOIN test2 where test.t1 = test2.t2;
-- Return 2 rows of results [3, 4];
-- Through the query profile (set is_report_success=true;) you can view the detailed information of the internal work of the query,
-- Through the query profile (set enable_profile=true;) you can view the detailed information of the internal work of the query,
-- Including whether each Runtime Filter is pushed down, waiting time,
-- and the total time from prepare to receiving Runtime Filter for OLAP_SCAN_NODE.
RuntimeFilter:in:

View File

@ -67,7 +67,7 @@ Variables that support both session-level and global-level setting include:
* `time_zone`
* `wait_timeout`
* `sql_mode`
* `is_report_success`
* `enable_profile`
* `query_timeout`
* `exec_mem_limit`
* `batch_size`
@ -229,7 +229,7 @@ Note that the comment must start with /*+ and can only follow the SELECT.
Used for compatibility with MySQL clients. No practical effect.
* `is_report_success`
* `enable_profile`
Used to set whether you need to view the profile of the query. The default is false, which means no profile is required.
@ -239,7 +239,7 @@ Note that the comment must start with /*+ and can only follow the SELECT.
`fe_host:fe_http:port/query`
It will display the most recent 100 queries which `is_report_success` is set to true.
It will display the most recent 100 queries which `enable_profile` is set to true.
* `language`

View File

@ -472,7 +472,7 @@ LoadFinishTime: 2019-07-27 11:50:16
### 性能分析
可以在提交 LOAD 作业前,先执行 `set is_report_success=true` 打开会话变量。然后提交导入作业。待导入作业完成后,可以在 FE 的 web 页面的 `Queris` 标签中查看到导入作业的 Profile。
可以在提交 LOAD 作业前,先执行 `set enable_profile=true` 打开会话变量。然后提交导入作业。待导入作业完成后,可以在 FE 的 web 页面的 `Queris` 标签中查看到导入作业的 Profile。
这个 Profile 可以帮助分析导入作业的运行状态。

View File

@ -44,10 +44,10 @@ FE将查询计划拆分成为Fragment下发到BE进行任务执行。BE在执行
通过Mysql命令,将FE上的Report的开关打开
```
mysql> set is_report_success=true;
mysql> set enable_profile=true;
```
之后执行对应的SQL语句之后,在FE的Web页面就可以看到对应SQL语句执行的Report信息:
之后执行对应的SQL语句之后(旧版本为`is_report_success`,在FE的Web页面就可以看到对应SQL语句执行的Report信息:
![image.png](/images/running_profile.png)
这里会列出最新执行完成的**100条语句**,我们可以通过Profile查看详细的统计信息。

View File

@ -251,7 +251,7 @@ EXPLAIN SELECT t1 FROM test JOIN test2 where test.t1 = test2.t2;
SELECT t1 FROM test JOIN test2 where test.t1 = test2.t2;
-- 返回2行结果[3, 4];
-- 通过query的profile(set is_report_success=true;)可以查看查询内部工作的详细信息,
-- 通过query的profile(set enable_profile=true;)可以查看查询内部工作的详细信息,
-- 包括每个Runtime Filter是否下推、等待耗时、以及OLAP_SCAN_NODE从prepare到接收到Runtime Filter的总时长。
RuntimeFilter:in:
- HasPushDownToEngine: true

View File

@ -67,7 +67,7 @@ SET GLOBAL exec_mem_limit = 137438953472
* `time_zone`
* `wait_timeout`
* `sql_mode`
* `is_report_success`
* `enable_profile`
* `query_timeout`
* `exec_mem_limit`
* `batch_size`
@ -226,7 +226,7 @@ SELECT /*+ SET_VAR(query_timeout = 1, enable_partition_cache=true) */ sleep(3);
用于兼容 MySQL 客户端。无实际作用。
* `is_report_success`
* `enable_profile`
用于设置是否需要查看查询的 profile。默认为 false,即不需要 profile。
@ -235,7 +235,7 @@ SELECT /*+ SET_VAR(query_timeout = 1, enable_partition_cache=true) */ sleep(3);
`fe_host:fe_http_port/query`
其中会显示最近100条,开启 `is_report_success` 的查询的 profile。
其中会显示最近100条,开启 `enable_profile` 的查询的 profile。
* `language`

View File

@ -810,7 +810,13 @@ public class SchemaChangeHandler extends AlterHandler {
}
}
if (found) {
throw new DdlException("Can not add column which already exists in base table: " + newColName);
if (newColName.equalsIgnoreCase(Column.DELETE_SIGN)) {
throw new DdlException("Can not enable batch delete support, already supported batch delete.");
} else if (newColName.equalsIgnoreCase(Column.SEQUENCE_COL)) {
throw new DdlException("Can not enable sequence column support, already supported sequence column.");
} else {
throw new DdlException("Can not add column which already exists in base table: " + newColName);
}
}
/*

View File

@ -129,23 +129,26 @@ public class SetVar {
}
}
if (getVariable().toLowerCase().equals("prefer_join_method")) {
if (getVariable().equalsIgnoreCase(SessionVariable.PREFER_JOIN_METHOD)) {
String value = getValue().getStringValue();
if (!value.toLowerCase().equals("broadcast") && !value.toLowerCase().equals("shuffle")) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_VALUE_FOR_VAR, "prefer_join_method", value);
if (!value.equalsIgnoreCase("broadcast") && !value.equalsIgnoreCase("shuffle")) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_VALUE_FOR_VAR, SessionVariable.PREFER_JOIN_METHOD, value);
}
}
// Check variable time_zone value is valid
if (getVariable().toLowerCase().equals("time_zone")) {
if (getVariable().equalsIgnoreCase(SessionVariable.TIME_ZONE)) {
this.value = new StringLiteral(TimeUtils.checkTimeZoneValidAndStandardize(getValue().getStringValue()));
this.result = (LiteralExpr) this.value;
}
if (getVariable().toLowerCase().equals("exec_mem_limit")) {
if (getVariable().equalsIgnoreCase(SessionVariable.EXEC_MEM_LIMIT)) {
this.value = new StringLiteral(Long.toString(ParseUtil.analyzeDataVolumn(getValue().getStringValue())));
this.result = (LiteralExpr) this.value;
}
if (getVariable().equalsIgnoreCase("is_report_success")) {
variable = SessionVariable.ENABLE_PROFILE;
}
}
public String toSql() {

View File

@ -1065,8 +1065,14 @@ public class Load {
for (SlotRef slot : slots) {
SlotDescriptor slotDesc = slotDescByName.get(slot.getColumnName());
if (slotDesc == null) {
throw new UserException("unknown reference column, column=" + entry.getKey()
+ ", reference=" + slot.getColumnName());
if (entry.getKey().equalsIgnoreCase(Column.DELETE_SIGN)) {
throw new UserException("unknown reference column in DELETE ON clause:" + slot.getColumnName());
} else if (entry.getKey().equalsIgnoreCase(Column.SEQUENCE_COL)) {
throw new UserException("unknown reference column in ORDER BY clause:" + slot.getColumnName());
} else {
throw new UserException("unknown reference column, column=" + entry.getKey()
+ ", reference=" + slot.getColumnName());
}
}
smap.getLhs().add(slot);
smap.getRhs().add(new SlotRef(slotDesc));
@ -1099,8 +1105,14 @@ public class Load {
smap.getRhs().add(new CastExpr(tbl.getColumn(slot.getColumnName()).getType(),
exprsByName.get(slot.getColumnName())));
} else {
throw new UserException("unknown reference column, column=" + entry.getKey()
+ ", reference=" + slot.getColumnName());
if (entry.getKey().equalsIgnoreCase(Column.DELETE_SIGN)) {
throw new UserException("unknown reference column in DELETE ON clause:" + slot.getColumnName());
} else if (entry.getKey().equalsIgnoreCase(Column.SEQUENCE_COL)) {
throw new UserException("unknown reference column in ORDER BY clause:" + slot.getColumnName());
} else {
throw new UserException("unknown reference column, column=" + entry.getKey()
+ ", reference=" + slot.getColumnName());
}
}
}
Expr expr = entry.getValue().clone(smap);

View File

@ -75,7 +75,7 @@ public class BrokerLoadJob extends BulkLoadJob {
// Profile of this load job, including all tasks' profiles
private RuntimeProfile jobProfile;
// If set to true, the profile of load job with be pushed to ProfileManager
private boolean isReportSuccess = false;
private boolean enableProfile = false;
// for log replay and unit test
public BrokerLoadJob() {
@ -87,8 +87,8 @@ public class BrokerLoadJob extends BulkLoadJob {
throws MetaNotFoundException {
super(EtlJobType.BROKER, dbId, label, originStmt, userInfo);
this.brokerDesc = brokerDesc;
if (ConnectContext.get() != null && ConnectContext.get().getSessionVariable().isReportSucc()) {
isReportSuccess = true;
if (ConnectContext.get() != null && ConnectContext.get().getSessionVariable().enableProfile()) {
enableProfile = true;
}
}
@ -199,7 +199,7 @@ public class BrokerLoadJob extends BulkLoadJob {
LoadLoadingTask task = new LoadLoadingTask(db, table, brokerDesc,
brokerFileGroups, getDeadlineMs(), getExecMemLimit(),
isStrictMode(), transactionId, this, getTimeZone(), getTimeout(),
getLoadParallelism(), getSendBatchParallelism(), isReportSuccess ? jobProfile : null);
getLoadParallelism(), getSendBatchParallelism(), enableProfile ? jobProfile : null);
UUID uuid = UUID.randomUUID();
TUniqueId loadId = new TUniqueId(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
task.init(loadId, attachment.getFileStatusByTable(aggKey),
@ -306,7 +306,7 @@ public class BrokerLoadJob extends BulkLoadJob {
}
private void writeProfile() {
if (!isReportSuccess) {
if (!enableProfile) {
return;
}

View File

@ -759,6 +759,7 @@ public class OlapScanNode extends ScanNode {
msg.olap_scan_node.setSortColumn(sortColumn);
}
msg.olap_scan_node.setKeyType(olapTable.getKeysType().toThrift());
msg.olap_scan_node.setTableName(olapTable.getName());
}
// export some tablets

View File

@ -239,7 +239,7 @@ public class Coordinator {
}
this.tResourceInfo = new TResourceInfo(context.getQualifiedUser(),
context.getSessionVariable().getResourceGroup());
this.needReport = context.getSessionVariable().isReportSucc();
this.needReport = context.getSessionVariable().enableProfile();
this.nextInstanceId = new TUniqueId();
nextInstanceId.setHi(queryId.hi);
nextInstanceId.setLo(queryId.lo + 1);

View File

@ -82,7 +82,6 @@ public final class GlobalVariable {
// Don't allow create instance.
private GlobalVariable() {
}
public static List<String> getPersistentGlobalVarNames() {

View File

@ -162,7 +162,7 @@ public final class QeProcessorImpl implements QeProcessor {
.db(context.getDatabase())
.fragmentInstanceInfos(info.getCoord().getFragmentInstanceInfos())
.profile(info.getCoord().getQueryProfile())
.isReportSucc(context.getSessionVariable().isReportSucc()).build();
.isReportSucc(context.getSessionVariable().enableProfile()).build();
querySet.put(queryIdStr, item);
}
return querySet;

View File

@ -45,7 +45,7 @@ public class SessionVariable implements Serializable, Writable {
public static final String EXEC_MEM_LIMIT = "exec_mem_limit";
public static final String QUERY_TIMEOUT = "query_timeout";
public static final String IS_REPORT_SUCCESS = "is_report_success";
public static final String ENABLE_PROFILE = "enable_profile";
public static final String SQL_MODE = "sql_mode";
public static final String RESOURCE_VARIABLE = "resource_group";
public static final String AUTO_COMMIT = "autocommit";
@ -186,8 +186,8 @@ public class SessionVariable implements Serializable, Writable {
public int queryTimeoutS = 300;
// if true, need report to coordinator when plan fragment execute successfully.
@VariableMgr.VarAttr(name = IS_REPORT_SUCCESS, needForward = true)
public boolean isReportSucc = false;
@VariableMgr.VarAttr(name = ENABLE_PROFILE, needForward = true)
public boolean enableProfile = false;
// Set sqlMode to empty string
@VariableMgr.VarAttr(name = SQL_MODE, needForward = true)
@ -396,8 +396,8 @@ public class SessionVariable implements Serializable, Writable {
return queryTimeoutS;
}
public boolean isReportSucc() {
return isReportSucc;
public boolean enableProfile() {
return enableProfile;
}
public int getWaitTimeoutS() {
@ -813,7 +813,7 @@ public class SessionVariable implements Serializable, Writable {
tResult.setBufferPoolLimit(maxExecMemByte);
tResult.setQueryTimeout(queryTimeoutS);
tResult.setIsReportSuccess(isReportSucc);
tResult.setIsReportSuccess(enableProfile);
tResult.setCodegenLevel(codegenLevel);
tResult.setEnableVectorizedEngine(enableVectorizedEngine);
@ -913,7 +913,7 @@ public class SessionVariable implements Serializable, Writable {
Text.readString(in);
sqlMode = 0L;
}
isReportSucc = in.readBoolean();
enableProfile = in.readBoolean();
queryTimeoutS = in.readInt();
maxExecMemByte = in.readLong();
if (Catalog.getCurrentCatalogJournalVersion() >= FeMetaVersion.VERSION_37) {

View File

@ -465,7 +465,7 @@ public class StmtExecutor implements ProfileWriter {
@Override
public void writeProfile(boolean isLastWriteProfile) {
if (!context.getSessionVariable().isReportSucc()) {
if (!context.getSessionVariable().enableProfile()) {
return;
}
synchronized (writeProfileLock) {

View File

@ -51,9 +51,9 @@ public class SessionVariablesTest {
Assert.assertTrue(numOfForwardVars >= 6);
Assert.assertEquals(numOfForwardVars, vars.size());
vars.put(SessionVariable.IS_REPORT_SUCCESS, "true");
vars.put(SessionVariable.ENABLE_PROFILE, "true");
sessionVariable.setForwardedSessionVariables(vars);
Assert.assertEquals(true, sessionVariable.isReportSucc);
Assert.assertEquals(true, sessionVariable.enableProfile);
}
@Test

View File

@ -85,7 +85,7 @@ public class VariableMgrTest {
SessionVariable var = VariableMgr.newSessionVariable();
Assert.assertEquals(2147483648L, var.getMaxExecMemByte());
Assert.assertEquals(300, var.getQueryTimeoutS());
Assert.assertEquals(false, var.isReportSucc());
Assert.assertEquals(false, var.enableProfile());
Assert.assertEquals(0L, var.getSqlMode());
List<List<String>> rows = VariableMgr.dump(SetType.SESSION, var, null);

View File

@ -343,6 +343,7 @@ struct TOlapScanNode {
4: required bool is_preaggregation
5: optional string sort_column
6: optional Types.TKeysType keyType
7: optional string table_name
}
struct TEqJoinCondition {