Bug #115661 | Query results are incorrect after semijoin is turned on | ||
---|---|---|---|
Submitted: | 22 Jul 2024 5:48 | Modified: | 22 Jul 2024 8:17 |
Reporter: | jiu chu | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S2 (Serious) |
Version: | mysql 8.4.1, 8.0.38, 9.0.0 | OS: | Linux |
Assigned to: | CPU Architecture: | Any |
[22 Jul 2024 5:48]
jiu chu
[22 Jul 2024 8:17]
MySQL Verification Team
Hello jiu chu, Thank you for the report and test case. Verified as described. regards, Umesh
[15 Aug 2024 9:44]
huahua xu
Hi jiu chu: I think that the singularity phenomenon is related to FTS(full-text search) and has nothing to do with semijoin. For the test case(from https://bugs.mysql.com/bug.php?id=47930): mysql> CREATE TABLE t1 (a int) ENGINE = InnoDB; mysql> INSERT INTO t1 VALUES (1), (2); mysql> CREATE TABLE t2 (a int, b2 char(10), FULLTEXT KEY b2 (b2)) ENGINE = InnoDB; mysql> INSERT INTO t2 VALUES (1,'Scargill'); mysql> CREATE TABLE t3 (a int, b int) ENGINE = InnoDB; mysql> INSERT INTO t3 VALUES (1,1), (2,1); -- semijoin is turned off, the result is incorrect. mysql> SELECT count(*) FROM t1 WHERE not exists( SELECT /*+ NO_SEMIJOIN() */ 1 FROM t2, t3 WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE) ); +----------+ | count(*) | +----------+ | 1 | +----------+ -- semijoin is turned on, the result is correct. mysql> SELECT count(*) FROM t1 WHERE not exists( SELECT 1 FROM t2, t3 WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE) ); +----------+ | count(*) | +----------+ | 0 | +----------+
[15 Aug 2024 14:22]
huahua xu
During initializing FT index scan, the innodb should make a flag to resort the FTS Query result, which returned by fts_query() on fts_ranking_t::rank. Suggested fix: diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index db5fb9b..819804d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -10877,6 +10877,9 @@ int ha_innobase::ft_init() { ++trx->will_lock; } + fts_result_t *result = reinterpret_cast<NEW_FT_INFO *>(ft_handler)->ft_result; + result->current = nullptr; + return rnd_init(false); } After applying the patch: mysql> set optimizer_switch='semijoin=off'; Query OK, 0 rows affected (0.01 sec) mysql> SELECT * FROM `users` WHERE directly_department_id IN (59) AND id IN ( SELECT user_id FROM `users_roles` WHERE role_id IN ( SELECT id FROM `roles` WHERE match(`roles`.`permissions_list`) against ('+print:print' IN BOOLEAN MODE ) ) UNION SELECT user_id FROM `departments_roles` WHERE false ) ; +-----+------------------------+----------+ | id | directly_department_id | admin_id | +-----+------------------------+----------+ | 205 | 59 | 0 | | 206 | 59 | 0 | | 426 | 59 | 0 | | 764 | 59 | 0 | | 811 | 59 | 0 | | 866 | 59 | 0 | +-----+------------------------+----------+ 6 rows in set (0.04 sec) mysql> set optimizer_switch='semijoin=on'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM `users` WHERE directly_department_id IN (59) AND id IN ( SELECT user_id FROM `users_roles` WHERE role_id IN ( SELECT id FROM `roles` WHERE match(`roles`.`permissions_list`) against ('+print:print' IN BOOLEAN MODE ) ) UNION SELECT user_id FROM `departments_roles` WHERE false ) ; +-----+------------------------+----------+ | id | directly_department_id | admin_id | +-----+------------------------+----------+ | 205 | 59 | 0 | | 206 | 59 | 0 | | 426 | 59 | 0 | | 764 | 59 | 0 | | 811 | 59 | 0 | | 866 | 59 | 0 | +-----+------------------------+----------+ 6 rows in set (0.00 sec) mysql> SELECT count(*) FROM t1 WHERE not exists( SELECT /*+ NO_SEMIJOIN() */ 1 FROM t2, t3 WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE) ); +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.03 sec) mysql> SELECT count(*) FROM t1 WHERE not exists( SELECT 1 FROM t2, t3 WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE) ); +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec)