Note:
This topic has been translated from a Chinese forum by GPT and might contain errors.
Original topic: 如何理解执行计划
From the execution plan, can we confirm how many milliseconds this SQL statement took? The final execution result shows 440 milliseconds, but this 440 milliseconds doesn’t seem to correspond to the times in the execution plan. How should we understand the times in this execution plan?
MySQL [xxxxxxxxx]> explain analyze select * FROM xxxxxxxxxxxx WHERE form_id = 1000968 AND form_user_id = 676601837 AND data_index_id > 0;
±-----------------------±--------±--------±----------±-------------------------------±-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------±---------------------------------------------------------------------±--------±-----+
| id | estRows | actRows | task | access object | execution info | operator info | memory | disk |
±-----------------------±--------±--------±----------±-------------------------------±-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------±---------------------------------------------------------------------±--------±-----+
| TableReader_7 | 0.02 | 170 | root | | time:87.7ms, loops:2, RU:18.324737, cop_task: {num: 1, max: 80.7ms, proc_keys: 170, tot_proc: 51ms, tot_wait: 77.9µs, rpc_num: 1, rpc_time: 80.7ms, copr_cache_hit_ratio: 0.00, build_task_duration: 7.13µs, max_distsql_concurrency: 1} | data:TableRangeScan_6 | 10.6 MB | N/A |
| └─TableRangeScan_6 | 0.02 | 170 | cop[tikv] | table:xxxxxxxxxx | tikv_task:{time:30ms, loops:3}, scan_detail: {total_process_keys: 170, total_process_keys_size: 47258, total_keys: 338, get_snapshot_time: 28µs, rocksdb: {key_skipped_count: 337, block: {cache_hit_count: 6, read_count: 3, read_byte: 95.4 KB, read_time: 55.1µs}}} | range:(1000968 676601837 0,1000968 676601837 +inf], keep order:false | N/A | N/A |
±-----------------------±--------±--------±----------±-------------------------------±-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------±---------------------------------------------------------------------±--------±-----+
2 rows in set (0.44 sec)
The calculation result is: 87.72+303=265.4 milliseconds, which is inconsistent with the output result of 440 milliseconds above. How can this be explained?
The image is not visible. Please provide the text you need translated.
0.44 seconds, which is 440 milliseconds, is the total execution time displayed by the client. It should include the network time from the TiDB server to your client and the time taken for the client to display the result. The execution plan shows the time for each step.
Is the time in the execution plan not the total time? Is it just a part of the total execution time?
It is the total time at the database level, plus the time to your client.
Your use of count not returning data should be similar.
The time in the first row of the execution plan indicates the total time the SQL statement took to execute in the database, which is 87.7ms.
The execution process of SQL
“time” represents the total wall time from entering the operator to leaving the operator, including the total execution time of all sub-operator operations. If the operator is called multiple times by the parent operator (loops), this time is the cumulative time. “loops” is the number of times the current operator is called by the parent operator.
The 440ms displayed by the client = 87.7ms in the execution plan + the time for the result to be transmitted from the db_server to the client over the network.
The execution plan cannot pre-fetch the time from the db_server to the client.
I have always had trouble understanding TiDB’s execution plan, especially the execution order.
The official documentation doesn’t seem to have much information about explain. From the execution plan, it looks like it goes from bottom to top.
The one with the same indentation level is executed first, and for different indentation levels, the rightmost one is executed first.
Got it! Please provide the Chinese text you need translated.
Do you mean that tasks at the same level are executed from top to bottom, while tasks at different levels are executed from bottom to top?
Although it can be understood this way, I do not recommend memorizing such formulas. Actually, TiDB’s execution plan is quite similar to Oracle’s. You can find a lot of articles online about Oracle’s execution plan sequence. MySQL’s execution plan sequence is not intuitive and not visually appealing (MySQL has Workbench, where the graphical execution plan is very nice). Of course, the simplest way is to look at TiDB’s official documentation or watch free videos. Teacher Dong has videos explaining the execution plan.
First, check the official documentation:
The execution order of operators:
The structure of operators is tree-like, but during query execution, it is not strictly required that child node tasks be completed before the parent node. TiDB supports parallel processing within the same query, meaning child nodes “flow into” parent nodes. Parent nodes, child nodes, and sibling nodes may execute parts of the query in parallel.
In the above example, the operator ├─IndexRangeScan_8(Build) matches rows in the index a(a) and looks up the internal RowID. The operator └─TableRowIDScan_9(Probe) then retrieves these rows from the table.
Build always executes before Probe, and Build always appears before Probe. That is, if an operator has multiple child nodes, the operator with the Build keyword after the child node ID always executes before the operator with the Probe keyword. When TiDB presents the execution plan, the Build side always appears first, followed by the Probe side.
Many execution plans are executed in loops. Although there is an order, they are actually dynamically executed in sequence. In TiDB, loops refer to the number of times a loop is called.
This SQL took 87.7ms to execute.
Execute the one with the same indentation first, and execute the one with more indentation if the indentation is different.