Skip to content

Commit 93c7c3a

Browse files
authored
planner: add the doc for the SEMI_JOIN_REWRITE hint (#9734)
1 parent 20b375f commit 93c7c3a

2 files changed

Lines changed: 60 additions & 0 deletions

File tree

optimizer-hints.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,58 @@ select /*+ HASH_JOIN(t1, t2) */ * from t1, t2 where t1.id = t2.id;
133133
>
134134
> `TIDB_HJ` is the alias for `HASH_JOIN` in TiDB 3.0.x and earlier versions. If you are using any of these versions, you must apply the `TIDB_HJ(t1_name [, tl_name ...])` syntax for the hint. For the later versions of TiDB, `TIDB_HJ` and `HASH_JOIN` are both valid names for the hint, but `HASH_JOIN` is recommended.
135135
136+
### SEMI_JOIN_REWRITE()
137+
138+
The `SEMI_JOIN_REWRITE()` hint tells the optimizer to rewrite the semi-join query to an ordinary join query. Currently, this hint only works for `EXISTS` subqueries.
139+
140+
If this hint is not used to rewrite the query, when the hash join is selected in the execution plan, the semi-join query can only use the subquery to build a hash table. In this case, when the result of the subquery is bigger than that of the outer query, the execution speed might be slower than expected.
141+
142+
Similarly, when the index join is selected in the execution plan, the semi-join query can only use the outer query as the driving table. In this case, when the result of the subquery is smaller than that of the outer query, the execution speed might be slower than expected.
143+
144+
When `SEMI_JOIN_REWRITE()` is used to rewrite the query, the optimizer can extend the selection range to select a better execution plan.
145+
146+
{{< copyable "sql" >}}
147+
148+
```sql
149+
-- Does not use SEMI_JOIN_REWRITE() to rewrite the query.
150+
EXPLAIN SELECT * FROM t WHERE EXISTS (SELECT 1 FROM t1 WHERE t1.a = t.a);
151+
```
152+
153+
```sql
154+
+-----------------------------+---------+-----------+------------------------+---------------------------------------------------+
155+
| id | estRows | task | access object | operator info |
156+
+-----------------------------+---------+-----------+------------------------+---------------------------------------------------+
157+
| MergeJoin_9 | 7992.00 | root | | semi join, left key:test.t.a, right key:test.t1.a |
158+
| ├─IndexReader_25(Build) | 9990.00 | root | | index:IndexFullScan_24 |
159+
| │ └─IndexFullScan_24 | 9990.00 | cop[tikv] | table:t1, index:idx(a) | keep order:true, stats:pseudo |
160+
| └─IndexReader_23(Probe) | 9990.00 | root | | index:IndexFullScan_22 |
161+
| └─IndexFullScan_22 | 9990.00 | cop[tikv] | table:t, index:idx(a) | keep order:true, stats:pseudo |
162+
+-----------------------------+---------+-----------+------------------------+---------------------------------------------------+
163+
```
164+
165+
{{< copyable "sql" >}}
166+
167+
```sql
168+
-- Uses SEMI_JOIN_REWRITE() to rewrite the query.
169+
EXPLAIN SELECT * FROM t WHERE EXISTS (SELECT /*+ SEMI_JOIN_REWRITE() */ 1 FROM t1 WHERE t1.a = t.a);
170+
```
171+
172+
```sql
173+
+------------------------------+---------+-----------+------------------------+---------------------------------------------------------------------------------------------------------------+
174+
| id | estRows | task | access object | operator info |
175+
+------------------------------+---------+-----------+------------------------+---------------------------------------------------------------------------------------------------------------+
176+
| IndexJoin_16 | 1.25 | root | | inner join, inner:IndexReader_15, outer key:test.t1.a, inner key:test.t.a, equal cond:eq(test.t1.a, test.t.a) |
177+
| ├─StreamAgg_39(Build) | 1.00 | root | | group by:test.t1.a, funcs:firstrow(test.t1.a)->test.t1.a |
178+
| │ └─IndexReader_34 | 1.00 | root | | index:IndexFullScan_33 |
179+
| │ └─IndexFullScan_33 | 1.00 | cop[tikv] | table:t1, index:idx(a) | keep order:true |
180+
| └─IndexReader_15(Probe) | 1.25 | root | | index:Selection_14 |
181+
| └─Selection_14 | 1.25 | cop[tikv] | | not(isnull(test.t.a)) |
182+
| └─IndexRangeScan_13 | 1.25 | cop[tikv] | table:t, index:idx(a) | range: decided by [eq(test.t.a, test.t1.a)], keep order:false, stats:pseudo |
183+
+------------------------------+---------+-----------+------------------------+---------------------------------------------------------------------------------------------------------------+
184+
```
185+
186+
From the preceding example, you can see that when using the `SEMI_JOIN_REWRITE()` hint, TiDB can select the execution method of IndexJoin based on the driving table `t1`.
187+
136188
### HASH_AGG()
137189

138190
The `HASH_AGG()` hint tells the optimizer to use the hash aggregation algorithm in all the aggregate functions in the specified query block. This algorithm allows the query to be executed concurrently with multiple threads, which achieves a higher processing speed but consumes more memory. For example:

subquery-optimization.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,11 @@ explain select * from t where exists (select * from t2);
8686
| └─TableFullScan_11 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo |
8787
+------------------------+----------+-----------+---------------+--------------------------------+
8888
```
89+
90+
In the preceding optimization, the optimizer automatically optimizes the statement execution. In addition, you can also add the [`SEMI_JOIN_REWRITE`](/optimizer-hints.md#semi_join_rewrite) hint to further rewrite the statement.
91+
92+
If this hint is not used to rewrite the query, when the hash join is selected in the execution plan, the semi-join query can only use the subquery to build a hash table. In this case, when the result of the subquery is bigger than that of the outer query, the execution speed might be slower than expected.
93+
94+
Similarly, when the index join is selected in the execution plan, the semi-join query can only use the outer query as the driving table. In this case, when the result of the subquery is smaller than that of the outer query, the execution speed might be slower than expected.
95+
96+
When `SEMI_JOIN_REWRITE()` is used to rewrite the query, the optimizer can extend the selection range to select a better execution plan.

0 commit comments

Comments
 (0)