From 10570bfbfcb5e328c37d18c9c7524d91ddc19af1 Mon Sep 17 00:00:00 2001 From: Zhi Qi Date: Mon, 25 May 2020 12:45:28 +0800 Subject: [PATCH 01/10] add md. --- reference/performance/topn-push-down.md | 108 ++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 reference/performance/topn-push-down.md diff --git a/reference/performance/topn-push-down.md b/reference/performance/topn-push-down.md new file mode 100644 index 000000000000..de59c05cca7a --- /dev/null +++ b/reference/performance/topn-push-down.md @@ -0,0 +1,108 @@ +--- +title: 执行计划缓存 +category: performance +--- + +# topn 与 limit 下推 + +sql 中的 limit 子句在 tidb 查询计划树中对应 limit 算子节点,order by 子句在查询计划树中对应 sort 算子节点,此外,我们会将相邻的 limit 和 sort 组合成 topn 算子节点,表示按某个排序规则提取记录的前 n 项。从另一方面来说,limit 节点等价于一个排序规则为空的 topn 节点。 + +和谓词下推类似,topn(及 limit,下同)下推将查询计划树中的 topn 计算尽可能下推到距离数据源最近的地方,以尽早完成数据的过滤,进而显著地减少数据传输或计算的开销。 + +## 示例 + +以下通过一些例子对 topn 下推进行说明。 + +### 示例1:下推到存储层 + +{{< copyable "sql" >}} + +```sql +create table t(id int primary key, a int not null); +explain select * from t order by a limit 10; ++----------------------------+----------+-----------+---------------+--------------------------------+ +| id | estRows | task | access object | operator info | ++----------------------------+----------+-----------+---------------+--------------------------------+ +| TopN_7 | 10.00 | root | | test.t.a, offset:0, count:10 | +| └─TableReader_15 | 10.00 | root | | data:TopN_14 | +| └─TopN_14 | 10.00 | cop[tikv] | | test.t.a, offset:0, count:10 | +| └─TableFullScan_13 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++----------------------------+----------+-----------+---------------+--------------------------------+ +4 rows in set (0.00 sec) +``` + +在该查询中,将 topn 算子节点下推到 tikv 上对数据进行过滤,每个 cop 只向 tidb 传输 10 条记录。在 tidb 将数据整合后,再进行最终的过滤。 + +### 示例2:topn 下推过 join 的情况(排序规则仅依赖于外表) + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t left join s on t.a = s.a order by t.a limit 10; ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| id | estRows | task | access object | operator info | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| TopN_12 | 10.00 | root | | test.t.a, offset:0, count:10 | +| └─HashJoin_17 | 12.50 | root | | left outer join, equal:[eq(test.t.a, test.s.a)] | +| ├─TopN_18(Build) | 10.00 | root | | test.t.a, offset:0, count:10 | +| │ └─TableReader_26 | 10.00 | root | | data:TopN_25 | +| │ └─TopN_25 | 10.00 | cop[tikv] | | test.t.a, offset:0, count:10 | +| │ └─TableFullScan_24 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | +| └─TableReader_30(Probe) | 10000.00 | root | | data:TableFullScan_29 | +| └─TableFullScan_29 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +8 rows in set (0.01 sec) +``` + +在该查询中,topn 算子的排序规则仅依赖于外表 t,可以将 topn 下推到了 join 之前进行一次计算,以减少 join 时的计算开销。除此之外,同样将 topn 下推到了存储层中。 + +### 示例3:topn 不能下推过 join 的情况 + +{{< copyable "sql" >}} + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t join s on t.a = s.a order by t.id limit 10; ++-------------------------------+----------+-----------+---------------+--------------------------------------------+ +| id | estRows | task | access object | operator info | ++-------------------------------+----------+-----------+---------------+--------------------------------------------+ +| TopN_12 | 10.00 | root | | test.t.id, offset:0, count:10 | +| └─HashJoin_16 | 12500.00 | root | | inner join, equal:[eq(test.t.a, test.s.a)] | +| ├─TableReader_21(Build) | 10000.00 | root | | data:TableFullScan_20 | +| │ └─TableFullScan_20 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | +| └─TableReader_19(Probe) | 10000.00 | root | | data:TableFullScan_18 | +| └─TableFullScan_18 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++-------------------------------+----------+-----------+---------------+--------------------------------------------+ +6 rows in set (0.00 sec) +``` + +topn 无法下推过 inner join。以上面的查询为例,如果先 join 得到 100 条记录,再做 topn 可以剩余 10 条记录。而如果在 topn 之前就过滤到剩余 10 条记录,做完 join 之后可能就剩下 5 条了,导致了结果的差异。 + +同理,topn 无法下推到 outer join 的内表上。在 topn 的排序规则涉及多张表上的列时,也无法下推,如 `t.a+s.a`。只有当 topn 的排序规则仅依赖于外表上的列时,才可以下推。 + +### 示例4:topn 转换成 limit 的情况 + +{{< copyable "sql" >}} + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t left join s on t.a = s.a order by t.id limit 10; ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| id | estRows | task | access object | operator info | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| TopN_12 | 10.00 | root | | test.t.id, offset:0, count:10 | +| └─HashJoin_17 | 12.50 | root | | left outer join, equal:[eq(test.t.a, test.s.a)] | +| ├─Limit_21(Build) | 10.00 | root | | offset:0, count:10 | +| │ └─TableReader_31 | 10.00 | root | | data:Limit_30 | +| │ └─Limit_30 | 10.00 | cop[tikv] | | offset:0, count:10 | +| │ └─TableFullScan_29 | 10.00 | cop[tikv] | table:t | keep order:true, stats:pseudo | +| └─TableReader_35(Probe) | 10000.00 | root | | data:TableFullScan_34 | +| └─TableFullScan_34 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +8 rows in set (0.00 sec) + +``` + +在上面的查询中,topn 首先推到了外表 t 上。然后因为它要对 t.id 进行排序,而 t.id 是表 t 的主键,可以直接按顺序读出(`keep order:true`),从而省略了 topn 中的排序,将其简化为 limit. \ No newline at end of file From 6f1bcc05929726b5b05454ca452f1035b52aef3d Mon Sep 17 00:00:00 2001 From: Zhi Qi Date: Mon, 25 May 2020 12:50:07 +0800 Subject: [PATCH 02/10] add copyable sql. --- reference/performance/topn-push-down.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/reference/performance/topn-push-down.md b/reference/performance/topn-push-down.md index de59c05cca7a..922fb6af1be2 100644 --- a/reference/performance/topn-push-down.md +++ b/reference/performance/topn-push-down.md @@ -35,6 +35,8 @@ explain select * from t order by a limit 10; ### 示例2:topn 下推过 join 的情况(排序规则仅依赖于外表) +{{< copyable "sql" >}} + ```sql create table t(id int primary key, a int not null); create table s(id int primary key, a int not null); From fc6c997fa3b700d50f6a55cf069e49a900f3ffcb Mon Sep 17 00:00:00 2001 From: Zhi Qi Date: Mon, 25 May 2020 14:10:34 +0800 Subject: [PATCH 03/10] modify title --- reference/performance/topn-push-down.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/performance/topn-push-down.md b/reference/performance/topn-push-down.md index 922fb6af1be2..2da133fe4ab0 100644 --- a/reference/performance/topn-push-down.md +++ b/reference/performance/topn-push-down.md @@ -1,5 +1,5 @@ --- -title: 执行计划缓存 +title: topn 与 limit 下推 category: performance --- From 3a771a01f5ac5d5131a41535d008d1747a1c2674 Mon Sep 17 00:00:00 2001 From: Zhi Qi Date: Mon, 25 May 2020 20:22:33 +0800 Subject: [PATCH 04/10] correct structure. --- reference/performance/topn-push-down.md => topn-push-down.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename reference/performance/topn-push-down.md => topn-push-down.md (100%) diff --git a/reference/performance/topn-push-down.md b/topn-push-down.md similarity index 100% rename from reference/performance/topn-push-down.md rename to topn-push-down.md From a28130c778e9a87957f41e3f5d8516fa2bbd3a42 Mon Sep 17 00:00:00 2001 From: Zhi Qi Date: Mon, 25 May 2020 20:29:39 +0800 Subject: [PATCH 05/10] add blacklist refer. --- topn-limit-push-down.md | 108 ++++++++++++++++++++++++++++++++++++++- topn-push-down.md | 110 ---------------------------------------- 2 files changed, 107 insertions(+), 111 deletions(-) delete mode 100644 topn-push-down.md diff --git a/topn-limit-push-down.md b/topn-limit-push-down.md index b6a688654ecb..48f811e4d82e 100644 --- a/topn-limit-push-down.md +++ b/topn-limit-push-down.md @@ -3,4 +3,110 @@ title: TopN 和 Limit 下推 category: performance --- -# TopN 和 Limit 下推 \ No newline at end of file +# TopN 和 Limit 下推 + +sql 中的 limit 子句在 tidb 查询计划树中对应 limit 算子节点,order by 子句在查询计划树中对应 sort 算子节点,此外,我们会将相邻的 limit 和 sort 组合成 topn 算子节点,表示按某个排序规则提取记录的前 n 项。从另一方面来说,limit 节点等价于一个排序规则为空的 topn 节点。 + +和谓词下推类似,topn(及 limit,下同)下推将查询计划树中的 topn 计算尽可能下推到距离数据源最近的地方,以尽早完成数据的过滤,进而显著地减少数据传输或计算的开销。 + +如果要关闭这个规则,可以在参照[优化规则及表达式下推的黑名单](/blacklist-control-plan.md)中的关闭方法。 + +## 示例 + +以下通过一些例子对 topn 下推进行说明。 + +### 示例1:下推到存储层 + +{{< copyable "sql" >}} + +```sql +create table t(id int primary key, a int not null); +explain select * from t order by a limit 10; ++----------------------------+----------+-----------+---------------+--------------------------------+ +| id | estRows | task | access object | operator info | ++----------------------------+----------+-----------+---------------+--------------------------------+ +| TopN_7 | 10.00 | root | | test.t.a, offset:0, count:10 | +| └─TableReader_15 | 10.00 | root | | data:TopN_14 | +| └─TopN_14 | 10.00 | cop[tikv] | | test.t.a, offset:0, count:10 | +| └─TableFullScan_13 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++----------------------------+----------+-----------+---------------+--------------------------------+ +4 rows in set (0.00 sec) +``` + +在该查询中,将 topn 算子节点下推到 tikv 上对数据进行过滤,每个 cop 只向 tidb 传输 10 条记录。在 tidb 将数据整合后,再进行最终的过滤。 + +### 示例2:topn 下推过 join 的情况(排序规则仅依赖于外表) + +{{< copyable "sql" >}} + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t left join s on t.a = s.a order by t.a limit 10; ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| id | estRows | task | access object | operator info | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| TopN_12 | 10.00 | root | | test.t.a, offset:0, count:10 | +| └─HashJoin_17 | 12.50 | root | | left outer join, equal:[eq(test.t.a, test.s.a)] | +| ├─TopN_18(Build) | 10.00 | root | | test.t.a, offset:0, count:10 | +| │ └─TableReader_26 | 10.00 | root | | data:TopN_25 | +| │ └─TopN_25 | 10.00 | cop[tikv] | | test.t.a, offset:0, count:10 | +| │ └─TableFullScan_24 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | +| └─TableReader_30(Probe) | 10000.00 | root | | data:TableFullScan_29 | +| └─TableFullScan_29 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +8 rows in set (0.01 sec) +``` + +在该查询中,topn 算子的排序规则仅依赖于外表 t,可以将 topn 下推到了 join 之前进行一次计算,以减少 join 时的计算开销。除此之外,同样将 topn 下推到了存储层中。 + +### 示例3:topn 不能下推过 join 的情况 + +{{< copyable "sql" >}} + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t join s on t.a = s.a order by t.id limit 10; ++-------------------------------+----------+-----------+---------------+--------------------------------------------+ +| id | estRows | task | access object | operator info | ++-------------------------------+----------+-----------+---------------+--------------------------------------------+ +| TopN_12 | 10.00 | root | | test.t.id, offset:0, count:10 | +| └─HashJoin_16 | 12500.00 | root | | inner join, equal:[eq(test.t.a, test.s.a)] | +| ├─TableReader_21(Build) | 10000.00 | root | | data:TableFullScan_20 | +| │ └─TableFullScan_20 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | +| └─TableReader_19(Probe) | 10000.00 | root | | data:TableFullScan_18 | +| └─TableFullScan_18 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++-------------------------------+----------+-----------+---------------+--------------------------------------------+ +6 rows in set (0.00 sec) +``` + +topn 无法下推过 inner join。以上面的查询为例,如果先 join 得到 100 条记录,再做 topn 可以剩余 10 条记录。而如果在 topn 之前就过滤到剩余 10 条记录,做完 join 之后可能就剩下 5 条了,导致了结果的差异。 + +同理,topn 无法下推到 outer join 的内表上。在 topn 的排序规则涉及多张表上的列时,也无法下推,如 `t.a+s.a`。只有当 topn 的排序规则仅依赖于外表上的列时,才可以下推。 + +### 示例4:topn 转换成 limit 的情况 + +{{< copyable "sql" >}} + +```sql +create table t(id int primary key, a int not null); +create table s(id int primary key, a int not null); +explain select * from t left join s on t.a = s.a order by t.id limit 10; ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| id | estRows | task | access object | operator info | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +| TopN_12 | 10.00 | root | | test.t.id, offset:0, count:10 | +| └─HashJoin_17 | 12.50 | root | | left outer join, equal:[eq(test.t.a, test.s.a)] | +| ├─Limit_21(Build) | 10.00 | root | | offset:0, count:10 | +| │ └─TableReader_31 | 10.00 | root | | data:Limit_30 | +| │ └─Limit_30 | 10.00 | cop[tikv] | | offset:0, count:10 | +| │ └─TableFullScan_29 | 10.00 | cop[tikv] | table:t | keep order:true, stats:pseudo | +| └─TableReader_35(Probe) | 10000.00 | root | | data:TableFullScan_34 | +| └─TableFullScan_34 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | ++----------------------------------+----------+-----------+---------------+-------------------------------------------------+ +8 rows in set (0.00 sec) + +``` + +在上面的查询中,topn 首先推到了外表 t 上。然后因为它要对 t.id 进行排序,而 t.id 是表 t 的主键,可以直接按顺序读出(`keep order:true`),从而省略了 topn 中的排序,将其简化为 limit. \ No newline at end of file diff --git a/topn-push-down.md b/topn-push-down.md deleted file mode 100644 index 2da133fe4ab0..000000000000 --- a/topn-push-down.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: topn 与 limit 下推 -category: performance ---- - -# topn 与 limit 下推 - -sql 中的 limit 子句在 tidb 查询计划树中对应 limit 算子节点,order by 子句在查询计划树中对应 sort 算子节点,此外,我们会将相邻的 limit 和 sort 组合成 topn 算子节点,表示按某个排序规则提取记录的前 n 项。从另一方面来说,limit 节点等价于一个排序规则为空的 topn 节点。 - -和谓词下推类似,topn(及 limit,下同)下推将查询计划树中的 topn 计算尽可能下推到距离数据源最近的地方,以尽早完成数据的过滤,进而显著地减少数据传输或计算的开销。 - -## 示例 - -以下通过一些例子对 topn 下推进行说明。 - -### 示例1:下推到存储层 - -{{< copyable "sql" >}} - -```sql -create table t(id int primary key, a int not null); -explain select * from t order by a limit 10; -+----------------------------+----------+-----------+---------------+--------------------------------+ -| id | estRows | task | access object | operator info | -+----------------------------+----------+-----------+---------------+--------------------------------+ -| TopN_7 | 10.00 | root | | test.t.a, offset:0, count:10 | -| └─TableReader_15 | 10.00 | root | | data:TopN_14 | -| └─TopN_14 | 10.00 | cop[tikv] | | test.t.a, offset:0, count:10 | -| └─TableFullScan_13 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | -+----------------------------+----------+-----------+---------------+--------------------------------+ -4 rows in set (0.00 sec) -``` - -在该查询中,将 topn 算子节点下推到 tikv 上对数据进行过滤,每个 cop 只向 tidb 传输 10 条记录。在 tidb 将数据整合后,再进行最终的过滤。 - -### 示例2:topn 下推过 join 的情况(排序规则仅依赖于外表) - -{{< copyable "sql" >}} - -```sql -create table t(id int primary key, a int not null); -create table s(id int primary key, a int not null); -explain select * from t left join s on t.a = s.a order by t.a limit 10; -+----------------------------------+----------+-----------+---------------+-------------------------------------------------+ -| id | estRows | task | access object | operator info | -+----------------------------------+----------+-----------+---------------+-------------------------------------------------+ -| TopN_12 | 10.00 | root | | test.t.a, offset:0, count:10 | -| └─HashJoin_17 | 12.50 | root | | left outer join, equal:[eq(test.t.a, test.s.a)] | -| ├─TopN_18(Build) | 10.00 | root | | test.t.a, offset:0, count:10 | -| │ └─TableReader_26 | 10.00 | root | | data:TopN_25 | -| │ └─TopN_25 | 10.00 | cop[tikv] | | test.t.a, offset:0, count:10 | -| │ └─TableFullScan_24 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | -| └─TableReader_30(Probe) | 10000.00 | root | | data:TableFullScan_29 | -| └─TableFullScan_29 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | -+----------------------------------+----------+-----------+---------------+-------------------------------------------------+ -8 rows in set (0.01 sec) -``` - -在该查询中,topn 算子的排序规则仅依赖于外表 t,可以将 topn 下推到了 join 之前进行一次计算,以减少 join 时的计算开销。除此之外,同样将 topn 下推到了存储层中。 - -### 示例3:topn 不能下推过 join 的情况 - -{{< copyable "sql" >}} - -```sql -create table t(id int primary key, a int not null); -create table s(id int primary key, a int not null); -explain select * from t join s on t.a = s.a order by t.id limit 10; -+-------------------------------+----------+-----------+---------------+--------------------------------------------+ -| id | estRows | task | access object | operator info | -+-------------------------------+----------+-----------+---------------+--------------------------------------------+ -| TopN_12 | 10.00 | root | | test.t.id, offset:0, count:10 | -| └─HashJoin_16 | 12500.00 | root | | inner join, equal:[eq(test.t.a, test.s.a)] | -| ├─TableReader_21(Build) | 10000.00 | root | | data:TableFullScan_20 | -| │ └─TableFullScan_20 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | -| └─TableReader_19(Probe) | 10000.00 | root | | data:TableFullScan_18 | -| └─TableFullScan_18 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | -+-------------------------------+----------+-----------+---------------+--------------------------------------------+ -6 rows in set (0.00 sec) -``` - -topn 无法下推过 inner join。以上面的查询为例,如果先 join 得到 100 条记录,再做 topn 可以剩余 10 条记录。而如果在 topn 之前就过滤到剩余 10 条记录,做完 join 之后可能就剩下 5 条了,导致了结果的差异。 - -同理,topn 无法下推到 outer join 的内表上。在 topn 的排序规则涉及多张表上的列时,也无法下推,如 `t.a+s.a`。只有当 topn 的排序规则仅依赖于外表上的列时,才可以下推。 - -### 示例4:topn 转换成 limit 的情况 - -{{< copyable "sql" >}} - -```sql -create table t(id int primary key, a int not null); -create table s(id int primary key, a int not null); -explain select * from t left join s on t.a = s.a order by t.id limit 10; -+----------------------------------+----------+-----------+---------------+-------------------------------------------------+ -| id | estRows | task | access object | operator info | -+----------------------------------+----------+-----------+---------------+-------------------------------------------------+ -| TopN_12 | 10.00 | root | | test.t.id, offset:0, count:10 | -| └─HashJoin_17 | 12.50 | root | | left outer join, equal:[eq(test.t.a, test.s.a)] | -| ├─Limit_21(Build) | 10.00 | root | | offset:0, count:10 | -| │ └─TableReader_31 | 10.00 | root | | data:Limit_30 | -| │ └─Limit_30 | 10.00 | cop[tikv] | | offset:0, count:10 | -| │ └─TableFullScan_29 | 10.00 | cop[tikv] | table:t | keep order:true, stats:pseudo | -| └─TableReader_35(Probe) | 10000.00 | root | | data:TableFullScan_34 | -| └─TableFullScan_34 | 10000.00 | cop[tikv] | table:s | keep order:false, stats:pseudo | -+----------------------------------+----------+-----------+---------------+-------------------------------------------------+ -8 rows in set (0.00 sec) - -``` - -在上面的查询中,topn 首先推到了外表 t 上。然后因为它要对 t.id 进行排序,而 t.id 是表 t 的主键,可以直接按顺序读出(`keep order:true`),从而省略了 topn 中的排序,将其简化为 limit. \ No newline at end of file From 66e9f91f61c689bfc8557ec61f7ff91a966860a2 Mon Sep 17 00:00:00 2001 From: Zhi Qi <30543181+LittleFall@users.noreply.github.com> Date: Mon, 25 May 2020 21:53:25 +0800 Subject: [PATCH 06/10] Update topn-limit-push-down.md Co-authored-by: Zhang Jian --- topn-limit-push-down.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/topn-limit-push-down.md b/topn-limit-push-down.md index 48f811e4d82e..468644f4c6e5 100644 --- a/topn-limit-push-down.md +++ b/topn-limit-push-down.md @@ -5,7 +5,7 @@ category: performance # TopN 和 Limit 下推 -sql 中的 limit 子句在 tidb 查询计划树中对应 limit 算子节点,order by 子句在查询计划树中对应 sort 算子节点,此外,我们会将相邻的 limit 和 sort 组合成 topn 算子节点,表示按某个排序规则提取记录的前 n 项。从另一方面来说,limit 节点等价于一个排序规则为空的 topn 节点。 +SQL 中的 LIMIT 子句在 TiDB 查询计划树中对应 Limit 算子节点,ORDER BY 子句在查询计划树中对应 Sort 算子节点,此外,我们会将相邻的 Limit 和 Sort 算子组合成 TopN 算子节点,表示按某个排序规则提取记录的前 N 项。从另一方面来说,Limit 节点等价于一个排序规则为空的 TopN 节点。 和谓词下推类似,topn(及 limit,下同)下推将查询计划树中的 topn 计算尽可能下推到距离数据源最近的地方,以尽早完成数据的过滤,进而显著地减少数据传输或计算的开销。 @@ -109,4 +109,4 @@ explain select * from t left join s on t.a = s.a order by t.id limit 10; ``` -在上面的查询中,topn 首先推到了外表 t 上。然后因为它要对 t.id 进行排序,而 t.id 是表 t 的主键,可以直接按顺序读出(`keep order:true`),从而省略了 topn 中的排序,将其简化为 limit. \ No newline at end of file +在上面的查询中,topn 首先推到了外表 t 上。然后因为它要对 t.id 进行排序,而 t.id 是表 t 的主键,可以直接按顺序读出(`keep order:true`),从而省略了 topn 中的排序,将其简化为 limit. From 00406fea1e2b936a49fbe6d6dcc3b52810bc1ea2 Mon Sep 17 00:00:00 2001 From: Zhi Qi Date: Mon, 25 May 2020 22:24:00 +0800 Subject: [PATCH 07/10] Canonical writing --- topn-limit-push-down.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/topn-limit-push-down.md b/topn-limit-push-down.md index 468644f4c6e5..f8a6d1ecbd0d 100644 --- a/topn-limit-push-down.md +++ b/topn-limit-push-down.md @@ -7,15 +7,15 @@ category: performance SQL 中的 LIMIT 子句在 TiDB 查询计划树中对应 Limit 算子节点,ORDER BY 子句在查询计划树中对应 Sort 算子节点,此外,我们会将相邻的 Limit 和 Sort 算子组合成 TopN 算子节点,表示按某个排序规则提取记录的前 N 项。从另一方面来说,Limit 节点等价于一个排序规则为空的 TopN 节点。 -和谓词下推类似,topn(及 limit,下同)下推将查询计划树中的 topn 计算尽可能下推到距离数据源最近的地方,以尽早完成数据的过滤,进而显著地减少数据传输或计算的开销。 +和谓词下推类似,TopN(及 Limit,下同)下推将查询计划树中的 TopN 计算尽可能下推到距离数据源最近的地方,以尽早完成数据的过滤,进而显著地减少数据传输或计算的开销。 如果要关闭这个规则,可以在参照[优化规则及表达式下推的黑名单](/blacklist-control-plan.md)中的关闭方法。 ## 示例 -以下通过一些例子对 topn 下推进行说明。 +以下通过一些例子对 TopN 下推进行说明。 -### 示例1:下推到存储层 +### 示例 1:下推到存储层 Coprocessor {{< copyable "sql" >}} @@ -33,9 +33,9 @@ explain select * from t order by a limit 10; 4 rows in set (0.00 sec) ``` -在该查询中,将 topn 算子节点下推到 tikv 上对数据进行过滤,每个 cop 只向 tidb 传输 10 条记录。在 tidb 将数据整合后,再进行最终的过滤。 +在该查询中,将 TopN 算子节点下推到 tikv 上对数据进行过滤,每个 coprocessor 只向 tidb 传输 10 条记录。在 tidb 将数据整合后,再进行最终的过滤。 -### 示例2:topn 下推过 join 的情况(排序规则仅依赖于外表) +### 示例 2:TopN 下推过 Join 的情况(排序规则仅依赖于外表中的列) {{< copyable "sql" >}} @@ -58,9 +58,9 @@ explain select * from t left join s on t.a = s.a order by t.a limit 10; 8 rows in set (0.01 sec) ``` -在该查询中,topn 算子的排序规则仅依赖于外表 t,可以将 topn 下推到了 join 之前进行一次计算,以减少 join 时的计算开销。除此之外,同样将 topn 下推到了存储层中。 +在该查询中,TopN 算子的排序规则仅依赖于外表 t 中的列,可以将 TopN 下推到了 Join 之前进行一次计算,以减少 Join 时的计算开销。除此之外,同样将 TopN 下推到了存储层中。 -### 示例3:topn 不能下推过 join 的情况 +### 示例 3:TopN 不能下推过 Join 的情况 {{< copyable "sql" >}} @@ -81,11 +81,11 @@ explain select * from t join s on t.a = s.a order by t.id limit 10; 6 rows in set (0.00 sec) ``` -topn 无法下推过 inner join。以上面的查询为例,如果先 join 得到 100 条记录,再做 topn 可以剩余 10 条记录。而如果在 topn 之前就过滤到剩余 10 条记录,做完 join 之后可能就剩下 5 条了,导致了结果的差异。 +TopN 无法下推过 Inner Join。以上面的查询为例,如果先 Join 得到 100 条记录,再做 TopN 可以剩余 10 条记录。而如果在 TopN 之前就过滤到剩余 10 条记录,做完 Join 之后可能就剩下 5 条了,导致了结果的差异。 -同理,topn 无法下推到 outer join 的内表上。在 topn 的排序规则涉及多张表上的列时,也无法下推,如 `t.a+s.a`。只有当 topn 的排序规则仅依赖于外表上的列时,才可以下推。 +同理,TopN 无法下推到 Outer Join 的内表上。在 TopN 的排序规则涉及多张表上的列时,也无法下推,如 `t.a+s.a`。只有当 TopN 的排序规则仅依赖于外表上的列时,才可以下推。 -### 示例4:topn 转换成 limit 的情况 +### 示例 4:TopN 转换成 Limit 的情况 {{< copyable "sql" >}} @@ -109,4 +109,4 @@ explain select * from t left join s on t.a = s.a order by t.id limit 10; ``` -在上面的查询中,topn 首先推到了外表 t 上。然后因为它要对 t.id 进行排序,而 t.id 是表 t 的主键,可以直接按顺序读出(`keep order:true`),从而省略了 topn 中的排序,将其简化为 limit. +在上面的查询中,TopN 首先推到了外表 t 上。然后因为它要对 t.id 进行排序,而 t.id 是表 t 的主键,可以直接按顺序读出(`keep order:true`),从而省略了 TopN 中的排序,将其简化为 Limit. From 64c1926a2aaab23d24f88fc456f5c62201713be3 Mon Sep 17 00:00:00 2001 From: yikeke Date: Tue, 26 May 2020 15:48:00 +0800 Subject: [PATCH 08/10] fix code blocks --- topn-limit-push-down.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/topn-limit-push-down.md b/topn-limit-push-down.md index f8a6d1ecbd0d..0ed5ba3d31e1 100644 --- a/topn-limit-push-down.md +++ b/topn-limit-push-down.md @@ -22,6 +22,9 @@ SQL 中的 LIMIT 子句在 TiDB 查询计划树中对应 Limit 算子节点,OR ```sql create table t(id int primary key, a int not null); explain select * from t order by a limit 10; +``` + +``` +----------------------------+----------+-----------+---------------+--------------------------------+ | id | estRows | task | access object | operator info | +----------------------------+----------+-----------+---------------+--------------------------------+ @@ -43,6 +46,9 @@ explain select * from t order by a limit 10; create table t(id int primary key, a int not null); create table s(id int primary key, a int not null); explain select * from t left join s on t.a = s.a order by t.a limit 10; +``` + +``` +----------------------------------+----------+-----------+---------------+-------------------------------------------------+ | id | estRows | task | access object | operator info | +----------------------------------+----------+-----------+---------------+-------------------------------------------------+ @@ -68,6 +74,9 @@ explain select * from t left join s on t.a = s.a order by t.a limit 10; create table t(id int primary key, a int not null); create table s(id int primary key, a int not null); explain select * from t join s on t.a = s.a order by t.id limit 10; +``` + +``` +-------------------------------+----------+-----------+---------------+--------------------------------------------+ | id | estRows | task | access object | operator info | +-------------------------------+----------+-----------+---------------+--------------------------------------------+ @@ -93,6 +102,9 @@ TopN 无法下推过 Inner Join。以上面的查询为例,如果先 Join 得 create table t(id int primary key, a int not null); create table s(id int primary key, a int not null); explain select * from t left join s on t.a = s.a order by t.id limit 10; +``` + +``` +----------------------------------+----------+-----------+---------------+-------------------------------------------------+ | id | estRows | task | access object | operator info | +----------------------------------+----------+-----------+---------------+-------------------------------------------------+ From a857cacffde9a7721c086328bf3d52b48717dbb4 Mon Sep 17 00:00:00 2001 From: yikeke Date: Tue, 26 May 2020 16:00:52 +0800 Subject: [PATCH 09/10] fix format --- topn-limit-push-down.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/topn-limit-push-down.md b/topn-limit-push-down.md index 0ed5ba3d31e1..c22fb3165578 100644 --- a/topn-limit-push-down.md +++ b/topn-limit-push-down.md @@ -9,7 +9,7 @@ SQL 中的 LIMIT 子句在 TiDB 查询计划树中对应 Limit 算子节点,OR 和谓词下推类似,TopN(及 Limit,下同)下推将查询计划树中的 TopN 计算尽可能下推到距离数据源最近的地方,以尽早完成数据的过滤,进而显著地减少数据传输或计算的开销。 -如果要关闭这个规则,可以在参照[优化规则及表达式下推的黑名单](/blacklist-control-plan.md)中的关闭方法。 +如果要关闭这个规则,可参照[优化规则及表达式下推的黑名单](/blacklist-control-plan.md)中的关闭方法。 ## 示例 @@ -36,7 +36,7 @@ explain select * from t order by a limit 10; 4 rows in set (0.00 sec) ``` -在该查询中,将 TopN 算子节点下推到 tikv 上对数据进行过滤,每个 coprocessor 只向 tidb 传输 10 条记录。在 tidb 将数据整合后,再进行最终的过滤。 +在该查询中,将 TopN 算子节点下推到 TiKV 上对数据进行过滤,每个 Coprocessor 只向 TiDB 传输 10 条记录。在 TiDB 将数据整合后,再进行最终的过滤。 ### 示例 2:TopN 下推过 Join 的情况(排序规则仅依赖于外表中的列) @@ -121,4 +121,4 @@ explain select * from t left join s on t.a = s.a order by t.id limit 10; ``` -在上面的查询中,TopN 首先推到了外表 t 上。然后因为它要对 t.id 进行排序,而 t.id 是表 t 的主键,可以直接按顺序读出(`keep order:true`),从而省略了 TopN 中的排序,将其简化为 Limit. +在上面的查询中,TopN 首先推到了外表 t 上。然后因为它要对 `t.id` 进行排序,而 `t.id` 是表 t 的主键,可以直接按顺序读出 (`keep order:true`),从而省略了 TopN 中的排序,将其简化为 Limit。 From d6d237fd5010f91bc81802a06c66e6c3017d7e50 Mon Sep 17 00:00:00 2001 From: Zhi Qi <30543181+LittleFall@users.noreply.github.com> Date: Tue, 26 May 2020 16:04:27 +0800 Subject: [PATCH 10/10] Update topn-limit-push-down.md Co-authored-by: Keke Yi <40977455+yikeke@users.noreply.github.com> --- topn-limit-push-down.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topn-limit-push-down.md b/topn-limit-push-down.md index c22fb3165578..c320ddad0ea2 100644 --- a/topn-limit-push-down.md +++ b/topn-limit-push-down.md @@ -64,7 +64,7 @@ explain select * from t left join s on t.a = s.a order by t.a limit 10; 8 rows in set (0.01 sec) ``` -在该查询中,TopN 算子的排序规则仅依赖于外表 t 中的列,可以将 TopN 下推到了 Join 之前进行一次计算,以减少 Join 时的计算开销。除此之外,同样将 TopN 下推到了存储层中。 +在该查询中,TopN 算子的排序规则仅依赖于外表 t 中的列,可以将 TopN 下推到 Join 之前进行一次计算,以减少 Join 时的计算开销。除此之外,TiDB 同样将 TopN 下推到了存储层中。 ### 示例 3:TopN 不能下推过 Join 的情况