mirror of
https://github.com/MariaDB/server.git
synced 2025-08-03 09:01:34 +02:00

If a table had a primary_key index, non_primary_key index, and an extended index with primary key in desc order, then the query with where clause predicates containing these index fields was picking an index_merge plan which was causing a wrong result. The plan shouldn't have contained index_merge in the first place, because the rows produced by one index have rows ordered by rowid in ascending order, and the rows coming from the other index were in a different order. The solution is to not produce index_merge plan in such scenarios. is_key_scan_ror() would now return false, for non_primary_key indexes if any primary key part with a reverse sort is present in them.
90 lines
3 KiB
Text
90 lines
3 KiB
Text
--source include/have_innodb.inc
|
|
--source include/have_sequence.inc
|
|
--source include/not_embedded.inc
|
|
|
|
--echo
|
|
--echo # MDEV-36410 wrong result with index_merge on indexes having descending primary key
|
|
--echo #
|
|
|
|
set optimizer_trace='enabled=on';
|
|
SET @save_sort_buffer_size=@@sort_buffer_size;
|
|
SET SESSION sort_buffer_size = 1024*16;
|
|
|
|
CREATE TABLE t1 (
|
|
id bigint(20) NOT NULL,
|
|
title varchar(255) NOT NULL,
|
|
status tinyint(4) DEFAULT 0,
|
|
country_code varchar(5) DEFAULT NULL,
|
|
PRIMARY KEY (id),
|
|
KEY idx_status (status),
|
|
KEY idx_country_code_status_id (country_code,status,id DESC)
|
|
) ENGINE=InnoDB;
|
|
|
|
INSERT INTO t1(id,title,status,country_code)
|
|
SELECT seq, CONCAT('abc', seq), seq%10, CONCAT('C', seq%5) FROM seq_1_to_500;
|
|
|
|
--echo # This must not use index_merge:
|
|
EXPLAIN
|
|
SELECT * FROM t1 WHERE country_code ='C1' and `status` =1;
|
|
set @trace= (select JSON_EXTRACT(trace, '$**.range_scan_alternatives[*]')
|
|
from INFORMATION_SCHEMA.OPTIMIZER_TRACE);
|
|
select json_detailed(json_extract(@trace, '$[*].index')) as INDEXES;
|
|
select json_detailed(json_extract(@trace, '$[*].rowid_ordered')) as ROR;
|
|
|
|
#select JSON_DETAILED(JSON_EXTRACT(trace, '$**.range_scan_alternatives[*].index')) AS JS from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
|
|
|
|
DROP table t1;
|
|
|
|
--echo # Now, try with indexes using ASC ordering and PK using DESC
|
|
CREATE TABLE t1 (
|
|
id bigint(20) NOT NULL,
|
|
title varchar(255) NOT NULL,
|
|
status tinyint(4) DEFAULT 0,
|
|
country_code varchar(5) DEFAULT NULL,
|
|
PRIMARY KEY (id DESC),
|
|
KEY idx_status (status),
|
|
KEY idx_country_code_status_id (country_code,status,id)
|
|
) ENGINE=InnoDB;
|
|
|
|
INSERT INTO t1(id,title,status,country_code)
|
|
SELECT seq, CONCAT('abc', seq), seq%10, CONCAT('C', seq%5) FROM seq_1_to_500;
|
|
|
|
--echo # Must not use index_merge:
|
|
EXPLAIN
|
|
SELECT * FROM t1 WHERE country_code ='C1' and status = 1;
|
|
|
|
set @trace= (select JSON_EXTRACT(trace, '$**.range_scan_alternatives[*]')
|
|
from INFORMATION_SCHEMA.OPTIMIZER_TRACE);
|
|
select json_detailed(json_extract(@trace, '$[*].index')) as INDEXES;
|
|
select json_detailed(json_extract(@trace, '$[*].rowid_ordered')) as ROR;
|
|
|
|
DROP TABLE t1;
|
|
|
|
--echo # Now, try with indexes using DESC ordering and PK using DESC
|
|
CREATE TABLE t1 (
|
|
id bigint(20) NOT NULL,
|
|
title varchar(255) NOT NULL,
|
|
status tinyint(4) DEFAULT 0,
|
|
country_code varchar(5) DEFAULT NULL,
|
|
PRIMARY KEY (id DESC),
|
|
KEY idx_status (status),
|
|
KEY idx_country_code_status_id (country_code,status,id DESC)
|
|
) ENGINE=InnoDB;
|
|
|
|
INSERT INTO t1(id,title,status,country_code)
|
|
SELECT seq, CONCAT('abc', seq), seq%10, CONCAT('C', seq%5) FROM seq_1_to_500;
|
|
|
|
--echo # Must not use index_merge:
|
|
EXPLAIN
|
|
SELECT * FROM t1 WHERE country_code ='C1' and status = 1;
|
|
|
|
set @trace= (select JSON_EXTRACT(trace, '$**.range_scan_alternatives[*]')
|
|
from INFORMATION_SCHEMA.OPTIMIZER_TRACE);
|
|
select json_detailed(json_extract(@trace, '$[*].index')) as INDEXES;
|
|
select json_detailed(json_extract(@trace, '$[*].rowid_ordered')) as ROR;
|
|
|
|
DROP TABLE t1;
|
|
|
|
SET sort_buffer_size= @save_sort_buffer_size;
|
|
|
|
|