-
Notifications
You must be signed in to change notification settings - Fork 6k
Closed
Labels
affects-5.4This bug affects the 5.4.x(LTS) versions.This bug affects the 5.4.x(LTS) versions.epic/plan-cachesig/plannerSIG: PlannerSIG: Plannertype/bugThe issue is confirmed as a bug.The issue is confirmed as a bug.type/enhancementThe issue or PR belongs to an enhancement.The issue or PR belongs to an enhancement.
Description
Enhancement
In the case below, the hint TIDB_INLJ
can work for general statements but is inapplicable for prepared statements.
MySQL> CREATE TABLE `item` (
`id` int,
`vid` varbinary(16),
`sid` int
);
MySQL> CREATE TABLE `lv` (
`item_id` int,
`sid` int,
KEY (`sid`,`item_id`)
);
MySQL> explain SELECT /*+ TIDB_INLJ(lv, item) */ *
FROM lv LEFT JOIN item ON lv.sid = item.sid AND lv.item_id = item.id
WHERE item.sid = 1 AND item.vid IN ("1", "3");
+------------------------------+----------+-----------+-----------------------------------+----------------------------------------------------------------------------------------------------------------------------------+
| id | estRows | task | access object | operator info |
+------------------------------+----------+-----------+-----------------------------------+----------------------------------------------------------------------------------------------------------------------------------+
| IndexJoin_10 | 0.02 | root | | inner join, inner:IndexReader_9, outer key:test.item.id, inner key:test.lv.item_id, equal cond:eq(test.item.id, test.lv.item_id) |
| ├─TableReader_19(Build) | 0.02 | root | | data:Selection_18 |
| │ └─Selection_18 | 0.02 | cop[tikv] | | eq(test.item.sid, 1), in(test.item.vid, "1", "3"), not(isnull(test.item.id)) |
| │ └─TableFullScan_17 | 10000.00 | cop[tikv] | table:item | keep order:false, stats:pseudo |
| └─IndexReader_9(Probe) | 1.25 | root | | index:Selection_8 |
| └─Selection_8 | 1.25 | cop[tikv] | | not(isnull(test.lv.item_id)) |
| └─IndexRangeScan_7 | 1.25 | cop[tikv] | table:lv, index:sid(sid, item_id) | range: decided by [eq(test.lv.item_id, test.item.id) eq(test.lv.sid, 1)], keep order:false, stats:pseudo |
+------------------------------+----------+-----------+-----------------------------------+----------------------------------------------------------------------------------------------------------------------------------+
MySQL> prepare stmt from 'SELECT /*+ TIDB_INLJ(lv, item) */ *
FROM lv LEFT JOIN item ON lv.sid = item.sid AND lv.item_id = item.id
WHERE item.sid = ? AND item.vid IN (?, ?)';
MySQL> set @a=1, @b='1', @c='3';
MySQL> execute stmt using @a, @b, @c;
MySQL> show warnings;
+---------+------+----------------------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------------------------------------------------------+
| Warning | 1815 | Optimizer Hint /*+ INL_JOIN(lv, item) */ or /*+ TIDB_INLJ(lv, item) */ is inapplicable |
+---------+------+----------------------------------------------------------------------------------------+
To use IndexJoin, the optimizer has to convert this outer-join
to an inner-join
.
But this conversion can fail since the validation check for prepared statements is too strict (it's for safety and introduced by #22349 to fix another bug), which finally makes the INLJ
hint inapplicable.
We should do this check more detailedly for prepared statements, for example, implement different check rules for different expressions (is null
, in
, eq
...).
Metadata
Metadata
Assignees
Labels
affects-5.4This bug affects the 5.4.x(LTS) versions.This bug affects the 5.4.x(LTS) versions.epic/plan-cachesig/plannerSIG: PlannerSIG: Plannertype/bugThe issue is confirmed as a bug.The issue is confirmed as a bug.type/enhancementThe issue or PR belongs to an enhancement.The issue or PR belongs to an enhancement.