Skip to content

Commit 3818d14

Browse files
committed
MDEV-38045: Implement QB_NAME hint with path syntax for nested query blocks
Extended QB_NAME hint to support path-based addressing of query blocks nested within views, derived tables, and CTEs, following TiDB's syntax. New syntax: QB_NAME(name, query_block_path), where query_block_path ::= query_block_path_element [ {, query_block_path_element }... ] query_block_path_element ::= @ qb_path_element_select_num | qb_path_element_view_sel qb_path_element_view_sel ::= qb_path_element_view_name [ @ qb_path_element_select_num ] For example, `SELECT /*+ qb_name(qb_v1, v1) */* FROM v1` The name `qb_v1` is assigned to the inner query block of the view `v1`. `SELECT /*+ qb_name(qb_v1, v1@sel_1) */* FROM v1` Means the same but specifies that `v1` is present in SELECT#1 of the current query block. `SELECT /*+ qb_name(qb_v1, v1@sel_1 .@sel_2) */* FROM v1` This means SELECT#2 of view `v1`, which is present in SELECT#1 of the current query block, gets the name `qb_v1`. It is possible to specify not only view names but also derived tables and CTE's in the path. Views and derived tables may be nested on multiple levels, for example: `SELECT /*+ qb_name(dt2_dt1_v1_1, dt1 .dt2 .v2 .@SEL_2) no_index(t1@dt2_dt1_v1_1)*/ v1.* FROM v1 JOIN (SELECT v1.* FROM v1 JOIN (SELECT * FROM v2) dt2) dt1`
1 parent c1f3882 commit 3818d14

File tree

8 files changed

+1605
-19
lines changed

8 files changed

+1605
-19
lines changed
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
--echo # ======================================
2+
--echo # Views
3+
--echo #
4+
--echo # select /* The name of the current query block is @SEL_1 */ * from v1;
5+
--echo #
6+
--echo # Addressing a view having one query block.
7+
--echo # QB_NAME(qb_v1, v1) means: inner query block of the view `v1`,
8+
--echo # which is present in the same query block as the hint, gets the name `qb_v1`.
9+
--echo # This name can be used in other hints.
10+
explain extended
11+
select /*+ qb_name(qb_v1, v1) no_index(t1@qb_v1)*/* from v1;
12+
13+
--echo # Equivalent to the above but specifying @SEL_1 explicitly.
14+
--echo # QB_NAME(qb_v1, v1@sel_1) means: inner query block of view `v1`,
15+
--echo # which is present in SELECT#1 of the current query block, gets the name `qb_v1`.
16+
explain extended
17+
select /*+ qb_name(qb_v1, v1@sel_1) no_index(t1@qb_v1 idx_a)*/* from v1;
18+
19+
--echo # Equivalent to the above but also specifying @SEL_1 of the view.
20+
--echo # QB_NAME(qb_v1, v1@sel_1 .@sel_1) means: SELECT#1 of view `v1`,
21+
--echo # which is present in SELECT#1 of the current query block, gets the name `qb_v1`.
22+
explain extended
23+
select /*+ qb_name(qb_v1, v1@sel_1 .@sel_1) no_index(t1@qb_v1 idx_ab)*/* from v1;
24+
25+
--echo #
26+
--echo # The case when a particular view is used in more than one query block.
27+
--echo # select /* Name of current query block is @SEL_1 */ * from v1
28+
--echo # join
29+
--echo # (select /* Name of current query block is @SEL_2 */ * from v1) vvv1;
30+
--echo # The first query block of view v1 can be declared as
31+
--echo # QB_NAME(v1_1, v1@SEL_1 .@SEL_1),
32+
--echo # and the second query block of the view v1 can be declared as
33+
--echo # QB_NAME(v1_2, v1@SEL_1 .@SEL_2).
34+
--echo #
35+
--echo # By default, range access is used for both `t1`'s in the statement below.
36+
explain extended
37+
select * from v1 join (select * from v1) vvv1;
38+
39+
--echo # Disable index access for t1 from the second occurence of view v1:
40+
explain extended
41+
select /*+ qb_name(v1_2, v1@SEL_2 .@SEL_1) no_index(t1@v1_2)*/ *
42+
from v1 join (select * from v1) vvv1;
43+
44+
--echo # Disable index access for t1 from both occurences of view v1:
45+
explain extended
46+
select /*+ qb_name(v1_1, v1@SEL_1) qb_name(v1_2, v1@SEL_2 .@SEL_1)
47+
no_index(t1@v1_1) no_index(t1@v1_2)*/ *
48+
from v1 join (select * from v1) vvv1;
49+
50+
--echo #
51+
--echo # The case when a particular view has more than one query block.
52+
--echo # create view v2 as
53+
--echo # select * from t1 join /* Name of this query block is @SEL_1 */
54+
--echo # (
55+
--echo # select count(*) from t1 join v1 /* Name of this query block is @SEL_2 */
56+
--echo # ) tt;
57+
--echo # The first query block of view v2 can be declared as
58+
--echo # QB_NAME(v2_1, v2@SEL_1 .@SEL_1), and the second query block can be
59+
--echo # declared as QB_NAME(v2_2, v2@SEL_1 .@SEL_2).
60+
--echo #
61+
--echo # See the default execution plan:
62+
explain extended select * from v2;
63+
64+
--echo # Disable index access for t1 from the second query block of view v2:
65+
explain extended
66+
select /*+ qb_name(v2_2, v2@SEL_1 .@SEL_2) no_index(t1@v2_2)*/* from v2;
67+
68+
--echo # Disable index access for `t1` from view `v1` used in
69+
--echo # the first query block of view `v2`:
70+
explain extended
71+
select /*+ qb_name(v2_v1, v2@SEL_1 .v1@SEL_2) no_index(t1@v2_v1)*/* from v2;
72+
73+
--echo # Equivalent to the above but specifying @SEL_1 explicitly:
74+
explain extended
75+
select /*+ qb_name(v2_v1_sel1, v2@SEL_1 .v1@SEL_2 .@SEL_1)
76+
no_index(t1@v2_v1_sel1)*/ * from v2;
77+
78+
--echo # Disable index access for `t1` tables from views `v1` and `v2`
79+
explain extended
80+
select /*+ qb_name(v2_v1, v2@SEL_1 .v1@SEL_2) no_index(t1@v2_v1)
81+
qb_name(v2_2, v2@SEL_1 .@SEL_2) no_index(t1@v2_2) */ * from v2;
82+
83+
--echo # ======================================
84+
--echo # Views with UNION
85+
--echo #
86+
--echo # Default execution plan:
87+
explain extended select * from v3;
88+
89+
--echo # `v3` in QB path corresponds to @SEL_1:
90+
explain extended select /*+ qb_name(qb_v3, v3) no_index(t1@qb_v3)*/* from v3;
91+
92+
--echo # Addressing @SEL_1 of `v3` explicitly:
93+
explain extended
94+
select /*+ qb_name(qb_v3_sel1, v3.@sel_1) no_index(t1@qb_v3_sel1)*/* from v3;
95+
96+
--echo # Addressing @SEL_2 of `v3` explicitly:
97+
explain extended
98+
select /*+ qb_name(qb_v3_sel2, v3.@sel_2) no_index(t1@qb_v3_sel2)*/* from v3;
99+
100+
101+
--echo # ======================================
102+
--echo # Derived tables
103+
--echo #
104+
--echo # QB_NAME(qb_dt, dt) means: inner query block of derived table `dt`,
105+
--echo # which is present in the same query block as the hint, gets the name `qb_dt`.
106+
--echo # This name can be used in other hints.
107+
explain extended select /*+ qb_name(qb_dt, dt) no_index(t1@qb_dt)*/* from
108+
(select * from t1 where a < 10) dt;
109+
110+
--echo # QB_NAME(qb_dt, dt@sel_1) means: inner query block of derived table `dt`,
111+
--echo # which is present in SELECT#1 of the current query block, gets the name `qb_dt`.
112+
explain extended select /*+ qb_name(qb_dt, dt@sel_1) no_index(t1@qb_dt)*/* from
113+
(select * from t1 where a < 10) dt;
114+
115+
--echo # QB_NAME(qb_dt, dt@sel_1 .@sel_1) means: SELECT#1 of derived table `dt`,
116+
--echo # which is present in SELECT#1 of the current query block, gets the name `qb_dt`.
117+
explain extended select /*+ qb_name(qb_dt, dt@sel_1 .@sel_1) no_index(t1@qb_dt)*/* from
118+
(select * from t1 where a < 10) dt;
119+
120+
--echo # ======================================
121+
--echo # Derived tables with UNION
122+
--echo #
123+
--echo # Default execution plan:
124+
explain extended
125+
select * from (select * from t1 where a < 10 union select * from t1 where a > 90) dt;
126+
127+
--echo # `dt` in QB path corresponds to @SEL_1:
128+
explain extended
129+
select /*+ qb_name(qb_dt, dt) no_index(t1@qb_dt)*/* from
130+
(select * from t1 where a < 10 union select * from t1 where a > 90) dt;
131+
132+
--echo # Addressing @SEL_1 of `dt` explicitly:
133+
explain extended
134+
select /*+ qb_name(qb_dt_sel1, dt.@sel_1) no_index(t1@qb_dt_sel1)*/* from
135+
(select * from t1 where a < 10 union select * from t1 where a > 90) dt;
136+
137+
--echo # Addressing @SEL_2 of `dt` explicitly:
138+
explain extended
139+
select /*+ qb_name(qb_dt_sel2, dt.@sel_2) no_index(t1@qb_dt_sel2)*/* from
140+
(select * from t1 where a < 10 union select * from t1 where a > 90) dt;
141+
142+
--echo # ======================================
143+
--echo # Mix of views and derived tables
144+
--echo #
145+
explain extended
146+
select /*+ qb_name(dt1_v1_1, dt1 .v1 .@SEL_1) no_index(t1@dt1_v1_1)*/ *
147+
from v1 join (select * from v1) dt1;
148+
149+
--echo # More complicated query. Default execution plan:
150+
explain extended
151+
select v1.* from v1 join (select v1.* from v1 join (select * from v2) dt2) dt1;
152+
153+
explain extended
154+
select /*+ qb_name(dt1_v1_1, dt1 .v1 .@SEL_1) no_index(t1@dt1_v1_1)*/ v1.*
155+
from v1 join (select v1.* from v1 join (select * from v2) dt2) dt1;
156+
157+
explain extended
158+
select /*+ qb_name(dt2_dt1_v1_1, dt1 .dt2 .v2 .@SEL_2)
159+
no_index(t1@dt2_dt1_v1_1)*/ v1.*
160+
from v1 join (select v1.* from v1 join (select * from v2) dt2) dt1;
161+
162+
--echo # ======================================
163+
--echo # CTEs
164+
--echo #
165+
--echo # Default execution plan:
166+
explain extended
167+
with cte as (select count(*) from t1, (select * from t1 where a < 5) dt1)
168+
select * from cte;
169+
170+
--echo # Disable index access for t1 in CTE
171+
explain extended
172+
with cte as (select count(*) from t1, (select * from t1 where a < 5) dt1)
173+
select /*+ qb_name(qb_cte, cte) no_index(t1@qb_cte)*/ * from cte;
174+
175+
--echo # Disable index access for t1 in dt1 of CTE
176+
explain extended
177+
with cte as (select count(*) from t1, (select * from t1 where a < 5) dt1)
178+
select /*+ qb_name(qb_cte_dt1, cte .dt1) no_index(t1@qb_cte_dt1)*/ * from cte;
179+
180+
--echo # Disable index access for both t1's
181+
explain extended
182+
with cte as (select count(*) from t1, (select * from t1 where a < 5) dt1)
183+
select /*+ qb_name(qb_cte, cte) no_index(t1@qb_cte)
184+
qb_name(qb_cte_dt1, cte .dt1) no_index(t1@qb_cte_dt1)*/ * from cte;
185+
186+
--echo # Multiple references to a CTE in a query.
187+
--echo # Default execution plan:
188+
explain extended
189+
with cte as (select count(*) from t1, (select * from t1 where a < 5) dt1)
190+
select * from cte join cte cte1;
191+
192+
--echo # Disable index access for t1 in `cte`
193+
explain extended
194+
with cte as (select count(*) from t1, (select * from t1 where a < 5) dt1)
195+
select /*+ qb_name(qb_cte, cte) no_index(t1@qb_cte)*/ * from cte join cte as cte1;
196+
197+
--echo # Disable index access for t1 in `cte1`
198+
explain extended
199+
with cte as (select count(*) from t1, (select * from t1 where a < 5) dt1)
200+
select /*+ qb_name(qb_cte1, cte1) no_index(t1@qb_cte1)*/ * from cte join cte as cte1;
201+
202+
203+
--echo # ======================================
204+
--echo # Wrong paths generate warnings
205+
--echo #
206+
--disable_ps_protocol
207+
# PS protocol is disabled because the warning is genererated only during
208+
# PREPARE step of a statement. When the QB name cannot be resolved the hint
209+
# is discarded, so it is not present during EXECUTE step.
210+
211+
explain extended
212+
select /*+ qb_name(`qb_v1`, `v2`)*/* from v1;
213+
214+
--echo # Wrong select number:
215+
explain extended
216+
select /*+ qb_name(qb_v1, `v2`@`sel_2`)*/* from v1;
217+
218+
explain extended
219+
select /*+ qb_name(qb_v1, v2@sel_1 .@sel_2)*/* from v1;
220+
221+
--echo # Attempting to reference a regular table as a query block:
222+
explain extended
223+
select /*+ qb_name(qb_v1, dt .t1)*/* from (select t1.* from t1 join v1) dt;
224+
225+
--echo # Wrong view name inside a derived table:
226+
explain extended
227+
select /*+ qb_name(qb_v1, dt .v2)*/* from (select t1.* from t1 join v1) dt;
228+
229+
--echo # Wrong select number:
230+
explain extended
231+
select /*+ qb_name(qb_v1, dt .v1@sel_2)*/* from (select t1.* from t1 join v1) dt;
232+
233+
explain extended
234+
select /*+ qb_name(qb_v1, dt .v1@sel_1 .@sel_2)*/* from
235+
(select t1.* from t1 join v1) dt;
236+
237+
--echo # Wrong select number syntax:
238+
explain extended
239+
select /*+ qb_name(qb_v1, `v1`@`lex_2`)*/* from v1;
240+
241+
explain extended
242+
select /*+ qb_name(qb_v1, v1 .lex_2)*/* from v1;
243+
244+
--enable_ps_protocol

0 commit comments

Comments
 (0)