Bug #112194 | Incorrect result when using INNER JOIN with SELECT FROM VIEW together with OR co | ||
---|---|---|---|
Submitted: | 28 Aug 2023 5:31 | Modified: | 6 Sep 2023 9:03 |
Reporter: | IVAN HO | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: DML | Severity: | S3 (Non-critical) |
Version: | 8.0.34 | OS: | Red Hat |
Assigned to: | CPU Architecture: | Any |
[28 Aug 2023 5:31]
IVAN HO
[28 Aug 2023 5:31]
IVAN HO
test case
Attachment: testcase.sql (application/octet-stream, text), 801 bytes.
[31 Aug 2023 11:38]
MySQL Verification Team
Hello IVAN HO, Thank you for the report and test case. I'm not seeing any issues on 8.0.34/5.7 builds, am I missing anything here? Please let us know. Thank you. bin/mysql -uroot -S /tmp/mysql.sock -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 10 Server version: 8.0.34 MySQL Community Server - GPL Copyright (c) 2000, 2023, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> mysql> drop database if exists testcase; mysql> create database testcase ; Query OK, 1 row affected (0.01 sec) mysql> use testcase ; Database changed mysql> mysql> mysql> drop table if exists emp; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> create table emp (emp_id int, emp_name varchar(100), salary int, dept_id int); Query OK, 0 rows affected (0.03 sec) mysql> insert into emp values -> (1, 'emp_A', 1000, 10), -> (2, 'emp_B', 2000, 20), -> (3, 'emp_C', 3000, 30), -> (4, 'emp_D', 2000, 10), -> (5, 'emp_E', 3000, 20); Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> mysql> mysql> # Create simple view by copying table "emp" mysql> drop view if exists vw_emp ; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> CREATE VIEW `vw_emp` AS -> select emp_id, emp_name, salary, dept_id from emp; Query OK, 0 rows affected (0.01 sec) mysql> mysql> mysql> drop table if exists dept; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> create table dept (dept_id int, dept_name varchar(100)); Query OK, 0 rows affected (0.02 sec) mysql> insert into dept values -> (10, 'dept_A'), -> (20, 'dept_B'), -> (30, 'dept_C'), -> (40, 'dept_D'), -> (50, 'dept_E'), -> (60, 'dept_F'); Query OK, 6 rows affected (0.00 sec) Records: 6 Duplicates: 0 Warnings: 0 mysql> mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select a.emp_id, a.emp_name, a.salary, b.dept_name -> from emp a -> inner join dept b on (b.dept_id in (select dept_id from vw_emp where a.dept_id=b.dept_id and a.salary > 2000)) -> where a.emp_id=3 -> order by emp_id -> ; +--------+----------+--------+-----------+ | emp_id | emp_name | salary | dept_name | +--------+----------+--------+-----------+ | 3 | emp_C | 3000 | dept_C | +--------+----------+--------+-----------+ 1 row in set (0.00 sec) mysql> select a.emp_id, a.emp_name, a.salary, b.dept_name -> from emp a -> inner join dept b on (b.dept_id in (select dept_id from vw_emp where a.dept_id=b.dept_id and a.salary > 2000) OR (FALSE)) -> where a.emp_id=3 -> order by emp_id -> ; +--------+----------+--------+-----------+ | emp_id | emp_name | salary | dept_name | +--------+----------+--------+-----------+ | 3 | emp_C | 3000 | dept_C | +--------+----------+--------+-----------+ 1 row in set (0.00 sec) mysql> select a.emp_id, a.emp_name, a.salary, b.dept_name -> from emp a -> inner join dept b on (b.dept_id in (select dept_id from emp where a.dept_id=b.dept_id and a.salary > 2000) OR (FALSE)) -> where a.emp_id=3 -> order by emp_id -> ; +--------+----------+--------+-----------+ | emp_id | emp_name | salary | dept_name | +--------+----------+--------+-----------+ | 3 | emp_C | 3000 | dept_C | +--------+----------+--------+-----------+ 1 row in set (0.00 sec) mysql> regards, Umesh
[4 Sep 2023 11:23]
IVAN HO
We have some new findings. The problem might be related to "optimizer_switch". In our environment, we use "optimizer_switch = derived_merge=off". [ Case 1 ] Add below parameter to my.cnf. optimizer_switch = derived_merge=off mysql> select @@global.optimizer_switch\G *************************** 1. row *************************** @@global.optimizer_switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=off,use_invisible_indexes=off,skip_scan=on,hash_join=on,subquery_to_derived=off,prefer_ordering_index=on,hypergraph_optimizer=off,derived_condition_pushdown=on 1 row in set (0.00 sec) Result : - All 3 SQL produce the same output, ie. return 1 row. [ Case 2 ] Use default optimizer_switch setting. mysql> select @@global.optimizer_switch\G *************************** 1. row *************************** @@global.optimizer_switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on,hash_join=on,subquery_to_derived=off,prefer_ordering_index=on,hypergraph_optimizer=off,derived_condition_pushdown=on 1 row in set (0.00 sec) Result : - The 1st & 3rd SQL produce the same output, ie. return 1 row. - The 2nd SQL produces WRONG output, ie. return 3 rows.
[4 Sep 2023 11:29]
MySQL Verification Team
Thank you for the feedback. Verified as described. regards, Umesh
[6 Sep 2023 9:03]
IVAN HO
Short Summary : # Case-1 MySQL 8.0.34 optimizer_switch = derived_merge=off SQL-1 return rows => 1 SQL-2 return rows => 3 SQL-3 return rows => 1 # Case-2 MySQL 8.0.34 Use default value of "optimizer_switch" SQL-1 return rows => 1 SQL-2 return rows => 1 SQL-3 return rows => 1 # Case-3 MySQL 8.0.33 optimizer_switch = derived_merge=off SQL-1 return rows => 1 SQL-2 return rows => 3 SQL-3 return rows => 1 # Case-4 MySQL 8.0.33 Use default value of "optimizer_switch" SQL-1 return rows => 1 SQL-2 return rows => 1 SQL-3 return rows => 1