mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 19:06:14 +01:00 
			
		
		
		
	 6af171f3bf
			
		
	
	
	6af171f3bf
	
	
	
		
			
			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;
 | |
| 
 | |
| 
 |