mysql 8 query regression coming from 5.7 (what's wrong?)

Viewed 287

A query in 5.7 no longer works in 8.0.23. Tested against a windows 8.0.23 x64 and a linux docker container 8.0.23.

Current sql mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

It's not the smartest sql, but that's not the point.

TL;DR: The point is that the 'bob' rows SHOULD show in the last query (as in 5.7) but no longer do in 8.

Details:

After the 4 tables setup and inserts, the query is built progressively with earlier queries to prove the bug. The inner most select should find nothing. The middle select merely repeats that. The last query joins the uu to that 'nothing' and, oh surprise, nothing becomes something! (which fails the outer most where clause.

Question:

what changed? what did we do wrong? what did we assume in 5.7 that is no longer true? Or is it a bug?

Data:

drop table if exists uu, ww, kk, aa;
CREATE TABLE uu (
  id int NOT NULL AUTO_INCREMENT,
  name varchar(30),
  PRIMARY KEY (`id`)
);
CREATE TABLE ww (
  id int NOT NULL,
  PRIMARY KEY (`id`)
);
CREATE TABLE kk (
  id int NOT NULL AUTO_INCREMENT,
  uid int,
  wid int,
  state int,
  PRIMARY KEY (`id`),
  CONSTRAINT `kk_uid` FOREIGN KEY (uid) REFERENCES uu (id),
  CONSTRAINT `kk_wid` FOREIGN KEY (wid) REFERENCES ww (id)
);
CREATE TABLE aa (
  id int NOT NULL AUTO_INCREMENT,
  uid int,
  wid int,
  PRIMARY KEY (`id`),
  CONSTRAINT `aa_uid` FOREIGN KEY (uid) REFERENCES uu (id),
  CONSTRAINT `aa_wid` FOREIGN KEY (wid) REFERENCES ww (id)
);
 
insert into uu (name) values ('alice'), ('bob'), ('chuck');
insert into ww (id) values (10),(11);
insert into kk (uid,wid,state) values (2,10,99);
insert into kk (uid,wid,state) values (2,11,99);
insert into aa (uid,wid) values (2,10), (2,11);
 
-- plain joins:
select u.*, "][", k.*, "][", a.*
     from uu u
    left join kk k on k.uid = u.id
    left join aa a on u.id = a.uid
    order by u.id,k.id;
 
select a2.*, '][', k3.* -- distinct a2.wid
                                     from aa a2
                                     left join kk k3 on a2.uid = k3.uid and a2.wid = k3.wid
                                     where k3.wid is null
;
SELECT a.*
                     FROM aa a
                     where a.wid in
                           (
                                select distinct a2.wid
                                     from aa a2
                                     left join kk k3 on a2.uid = k3.uid and a2.wid = k3.wid
                                     where k3.wid is null
                           )
;
 
select u.*, '][k', k.*, '][k1', k1.*,'][tmp', tmp.*
     FROM uu u
    LEFT JOIN kk k ON k.uid = u.id
    LEFT JOIN kk k1 ON k1.uid = u.id AND k1.state != 99
    LEFT JOIN
           (
                SELECT a.*
                     FROM aa a
                     where a.wid in
                           (
                                select distinct a2.wid
                                     from aa a2
                                     left join kk k3 on a2.uid = k3.uid and a2.wid = k3.wid
                                     where k3.wid is null
                           )
           ) tmp ON tmp.uid = u.id
-- ;
   WHERE tmp.wid IS NULL
           AND (
                k.uid IS NULL
                OR
            (k.state = 99 AND k1.id IS NULL)
           )
;

1 Answers

This is definitely a bug. It seems to have been introduced in 8.0.17.

Please report it on bugs.mysql.com or let me know and I will enter it.

A workaround would be the set those optimizer switches like this:

set optimizer_switch='materialization=off';
set optimizer_switch='derived_merge=on';

Thank you for using MySQL.

Related