经常使用数据库的朋友,我想你一定会有以下疑问:
1. 如何查看数据库当前正在执行哪些 SQL,以及这些 SQL 处于什么状态?
2. 如何终止异常的 SQL,比如一条查询大数据量表的 SELECT 语句没有携带查询条件,会拖垮整个数据库性能,这时候希望将这条异常的查询 SQL 终止掉。
Apache ShardingSphere 基于这样的需求,推出了 Show processlist 和 Kill <processID> 这样的功能。
一、功能介绍
Show processlist:此命令能展示出 ShardingSphere 当前正在执行的 SQL 列表,以及每条 SQL 的执行进度,如果用集群模式部署 ShardingSphere,Show processlist 功能会把集群中所有 Proxy 实例正在运行的 SQL 进行汇总,然后展示出来,因此总是能够看到这一时刻正在运行的全量 SQL。
mysql> show processlist \G;
*************************** 1. row ***************************
Id: 82a67f254959e0a0807a00f3cd695d87
User: root
Host: 10.200.79.156
db: root
Command: Execute
Time: 19
State: Executing 0/1
Info: update t_order set version = 456
1 row in set (0.24 sec)
Kill <processID>:此命令是基于 Show processlist 实现的功能,能够将 Show processlist 中列出的正在运行的 SQL 取消执行。
mysql> kill 82a67f254959e0a0807a00f3cd695d87;
Query OK, 0 rows affected (0.17 sec)
二、原理解析
了解了 Show processlist 和 Kill <processID> 的基本功能之后,让我们一起来探究 Show processlist 背后的原理。Kill <processID> 的原理和 Show processlist 类似,因此我们着重介绍 Show processlist 的实现原理。
2.1 SQL 是如何保存与销毁的
每一条 SQL 执行 ShardingSphere 会生成一个 ExecutionGroupContext 执行上下文对象,这个对象里会包含这条 SQL 的所有信息,其中有一个 executionID 字段来保证自己的唯一性。当 ShardingSphere 收到一条 SQL 指令(目前只对 MySQL 的 DML 和 DDL 语句做了处理,其它类型数据库会在后续版本进行支持,查询语句也被归类到了 DML 里)后,会调用 GovernanceExecuteProcessReporter#report来将 ExecutionGroupContext 信息缓存到 ConcurrentHashMap 中。
public final class GovernanceExecuteProcessReporter implements ExecuteProcessReporter {
@Override
public void report(final QueryContext queryContext, final ExecutionGroupContext<? extends SQLExecutionUnit> executionGroupContext,
final ExecuteProcessConstants constants, final EventBusContext eventBusContext) {
ExecuteProcessContext executeProcessContext = new ExecuteProcessContext(queryContext.getSql(), executionGroupContext, constants);
ShowProcessListManager.getInstance().putProcessContext(executeProcessContext.getExecutionID(), executeProcessContext);
ShowProcessListManager.getInstance().putProcessStatement(executeProcessContext.getExecutionID(), executeProcessContext.getProcessStatements());
}
}
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class ShowProcessListManager {
private static final ShowProcessListManager INSTANCE = new ShowProcessListManager();
@Getter
private final Map<String, ExecuteProcessContext> processContexts = new ConcurrentHashMap<>();
@Getter
private final Map<String, Collection<Statement>> processStatements = new ConcurrentHashMap<>();
public static ShowProcessListManager getInstance() {
return INSTANCE;
}
public void putProcessContext(final String executionId, final ExecuteProcessContext processContext) {
processContexts.put(executionId, processContext);
}
public void putProcessStatement(final String executionId, final Collection<Statement> statements) {
if (statements.isEmpty()) {
return;
}
processStatements.put(executionId, statements);
}
}
如上,ShowProcessListManager 类有两个缓存 Map,processContexts 和 processStatements。processContexts 里存放的是 executionID与 ExecuteProcessContext 的映射关系,