Bug #112055 Contribution by Tentent: index merge intersect causes wrong query results
Submitted: 13 Aug 2023 10:18 Modified: 14 Aug 2023 4:34
Reporter: Steven Duan (OCA) Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version:any, 8.0 OS:Any
Assigned to: CPU Architecture:Any
Tags: Contribution

[13 Aug 2023 10:18] Steven Duan
Description:
  INDEX_MERGE_INTERSECTION causes wrong query results, when PK is in descending order. Due to the default PK order being in ascending order, the rowid is also sorted in ascending order of same prefix of key in the secondary index. While PK is sorted in descending order, when comparing rowids of the RowIDIntersectionIterator, there may be directional errors during recursive comparison.

  For example, the intersect operator is responsible for merging RowIterator child#1 and RowIterator child#2. When the rowid of child#1 is 6 and the rowid of child#2 is 5.
  If the PK is arranged in ascending order: it is necessary to continue iterating on child#2 to find a rowid greater than 5 to match child#1's rowid=6.
  If the PK is arranged in descending order: it is necessary to continue iterating on child#1 to find a rowid less than 6 to match child#2's rowid=5.

How to repeat:
TEST_CASE:

CREATE TABLE t1 (
  pk INT NOT NULL AUTO_INCREMENT,
  a INT NOT NULL,
  b INT NOT NULL,
  c INT NOT NULL,
  d INT NOT NULL,
  PRIMARY KEY pk (pk desc),
  KEY idx_a (a),
  KEY idx_b (b),
  KEY idx_c (c),
  KEY idx_d (d)
);

--disable_query_log

# Inserting a lot of rows in order to enable index_merge intersect

INSERT INTO t1(a,b,c,d) VALUES
               ( RAND()*5, RAND()*5, RAND()*5, RAND()*5 );
 
let $cnt=4;
while ($cnt)
{
  INSERT INTO t1(a,b,c,d) SELECT 6,6,6,6 FROM t1;
  dec $cnt;
}

INSERT INTO t1(a,b,c,d) SELECT 6, RAND()*5, RAND()*5, 
                                 RAND()*5 FROM t1 LIMIT 3;
INSERT INTO t1(a,b,c,d) SELECT RAND()*5, 6, RAND()*5, 
                                 RAND()*5 FROM t1 LIMIT 3;
INSERT INTO t1(a,b,c,d) SELECT RAND()*5, RAND()*5, 6, 
                                 RAND()*5 FROM t1 LIMIT 3;
INSERT INTO t1(a,b,c,d) SELECT RAND()*5, RAND()*5, 
                              RAND()*5, 6 FROM t1 LIMIT 3;

let $cnt=7;
while ($cnt)
{
  INSERT INTO t1(a,b,c,d) SELECT RAND()*5, RAND()*5, 
                              RAND()*5, RAND()*5 FROM t1;
  dec $cnt;
}

--enable_query_log    

ANALYZE TABLE t1;

EXPLAIN SELECT COUNT(*), SUM(a) FROM t1 WHERE b=6 AND c=6;

# RESULT ERROR
SELECT COUNT(*), SUM(a) FROM t1 WHERE b=6 AND c=6;

DROP TABLE t1;

Suggested fix:
  Identify the sorting order of the PK. When creating the RowIDIntersectionIterator, we identify the PK sorting order. If sorting in descending order, RowIDIntersectionIterator needs to reverse the iteration direction during READ execution.
[13 Aug 2023 10:25] Steven Duan
bugfix based on version 8.0.30

Attachment: 0001-bugfix-index-merge-intersect-causes-wrong-query-resu.patch (application/octet-stream, text), 9.15 KiB.

[13 Aug 2023 10:26] Steven Duan
bugfix based on version 8.0.30

(*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

Contribution: 0001-bugfix-index-merge-intersect-causes-wrong-query-resu.patch (application/octet-stream, text), 9.15 KiB.

[14 Aug 2023 4:34] MySQL Verification Team
Hello duan hc,

Thank you for the report and contribution.

regards,
Umesh