1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Added rowid_filter support to Aria

This includes:
- cleanup and optimization of filtering and pushdown engine code.
- Adjusted costs for rowid filters (based on extensive testing
  and profiling).

This made a small two changes to the handler_rowid_filter_is_active()
API:
- One should not call it with a zero pointer!
- One does not need to call handler_rowid_filter_is_active() for every
  row anymore. It is enough to check if filter is active by calling it
  call it during index_init() or when handler::rowid_filter_changed()
  is called

The changes was to avoid unnecessary function calls and checks if
pushdown conditions and rowid_filter is not used.

Updated costs for rowid_filter_lookup() to be closer to reality.
The old cost was based only on rowid_compare_cost. This is now
changed to take into account the overhead in checking the rowid.

Changed the Range_rowid_filter class to use DYNAMIC_ARRAY directly
instead of Dynamic_array<>. This was done to be able to use the new
append_dynamic() functions which gives a notable speed improvment
compared to the old code.  Removing the abstraction also makes
the code easier to understand.

The cost of filtering is now slightly lower than before, which
is reflected in some test cases that is now using rowid filters.
This commit is contained in:
Monty
2022-11-16 14:52:47 +02:00
committed by Sergei Petrunia
parent 6418c24c94
commit 66dde8a54e
36 changed files with 3614 additions and 1997 deletions

View File

@ -154,6 +154,5 @@ typedef enum check_result {
typedef check_result_t (*index_cond_func_t)(void *param); typedef check_result_t (*index_cond_func_t)(void *param);
typedef check_result_t (*rowid_filter_func_t)(void *param); typedef check_result_t (*rowid_filter_func_t)(void *param);
typedef int (*rowid_filter_is_active_func_t)(void *param);
#endif /* _my_compare_h */ #endif /* _my_compare_h */

View File

@ -353,6 +353,14 @@ typedef struct st_dynamic_array
myf malloc_flags; myf malloc_flags;
} DYNAMIC_ARRAY; } DYNAMIC_ARRAY;
typedef struct st_dynamic_array_append
{
DYNAMIC_ARRAY *array;
uchar *pos, *end;
} DYNAMIC_ARRAY_APPEND;
typedef struct st_my_tmpdir typedef struct st_my_tmpdir
{ {
DYNAMIC_ARRAY full_list; DYNAMIC_ARRAY full_list;
@ -856,6 +864,10 @@ extern void freeze_size(DYNAMIC_ARRAY *array);
#define push_dynamic(A,B) insert_dynamic((A),(B)) #define push_dynamic(A,B) insert_dynamic((A),(B))
#define reset_dynamic(array) ((array)->elements= 0) #define reset_dynamic(array) ((array)->elements= 0)
#define sort_dynamic(A,cmp) my_qsort((A)->buffer, (A)->elements, (A)->size_of_element, (cmp)) #define sort_dynamic(A,cmp) my_qsort((A)->buffer, (A)->elements, (A)->size_of_element, (cmp))
extern void init_append_dynamic(DYNAMIC_ARRAY_APPEND *append,
DYNAMIC_ARRAY *array);
extern my_bool append_dynamic(DYNAMIC_ARRAY_APPEND *append,
const void * element);
extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
size_t init_alloc,size_t alloc_increment); size_t init_alloc,size_t alloc_increment);

View File

@ -12239,16 +12239,16 @@ explain select * from t1 where a<10 and b between 10 and 50 and c < 10 {
"rowid_filter_index": "b", "rowid_filter_index": "b",
"index_only_cost": 0.001515222, "index_only_cost": 0.001515222,
"filter_startup_cost": 3.004222e-4, "filter_startup_cost": 3.004222e-4,
"find_key_and_filter_lookup_cost": 6.445451e-4, "find_key_and_filter_lookup_cost": 7.827422e-4,
"filter_selectivity": 0.021, "filter_selectivity": 0.021,
"original_rows": 9, "original_rows": 9,
"new_rows": 0.189, "new_rows": 0.189,
"original_access_cost": 0.011516778, "original_access_cost": 0.011516778,
"with_filter_access_cost": 0.0023698, "with_filter_access_cost": 0.002507997,
"original_found_rows_cost": 0.010001556, "original_found_rows_cost": 0.010001556,
"with_filter_found_rows_cost": 2.100327e-4, "with_filter_found_rows_cost": 2.100327e-4,
"org_cost": 0.011804778, "org_cost": 0.011804778,
"filter_cost": 0.00267627, "filter_cost": 0.002814467,
"filter_used": true "filter_used": true
}, },
"access_type": "range", "access_type": "range",
@ -12256,7 +12256,7 @@ explain select * from t1 where a<10 and b between 10 and 50 and c < 10 {
"rows": 9, "rows": 9,
"rows_after_filter": 0.189, "rows_after_filter": 0.189,
"rows_out": 0.017766, "rows_out": 0.017766,
"cost": 0.00267627, "cost": 0.002814467,
"chosen": true "chosen": true
} }
], ],
@ -12264,7 +12264,7 @@ explain select * from t1 where a<10 and b between 10 and 50 and c < 10 {
"type": "range", "type": "range",
"rows_read": 0.189, "rows_read": 0.189,
"rows_out": 0.017766, "rows_out": 0.017766,
"cost": 0.00267627, "cost": 0.002814467,
"uses_join_buffering": false, "uses_join_buffering": false,
"rowid_filter_index": "b" "rowid_filter_index": "b"
} }
@ -12276,7 +12276,7 @@ explain select * from t1 where a<10 and b between 10 and 50 and c < 10 {
"plan_prefix": "", "plan_prefix": "",
"table": "t1", "table": "t1",
"rows_for_plan": 0.017766, "rows_for_plan": 0.017766,
"cost_for_plan": 0.00267627, "cost_for_plan": 0.002814467,
"pushdown_cond_selectivity": 0.094, "pushdown_cond_selectivity": 0.094,
"filtered": 0.1974, "filtered": 0.1974,
"rows_out": 0.017766 "rows_out": 0.017766
@ -12286,7 +12286,7 @@ explain select * from t1 where a<10 and b between 10 and 50 and c < 10 {
{ {
"best_join_order": ["t1"], "best_join_order": ["t1"],
"rows": 0.017766, "rows": 0.017766,
"cost": 0.00267627 "cost": 0.002814467
}, },
{ {
"table": "t1", "table": "t1",
@ -12674,20 +12674,20 @@ explain format=json select * from three, t1 where t1.a=three.a and t1.b<5000 and
"rowid_filter_index": "b", "rowid_filter_index": "b",
"index_only_cost": 0.092006157, "index_only_cost": 0.092006157,
"filter_startup_cost": 0.149564727, "filter_startup_cost": 0.149564727,
"find_key_and_filter_lookup_cost": 0.085742374, "find_key_and_filter_lookup_cost": 0.129350121,
"filter_selectivity": 0.4312, "filter_selectivity": 0.4312,
"original_rows": 1000, "original_rows": 1000,
"new_rows": 431.2, "new_rows": 431.2,
"original_access_cost": 1.203290157, "original_access_cost": 1.203290157,
"with_filter_access_cost": 0.656934192, "with_filter_access_cost": 0.700541939,
"original_found_rows_cost": 1.111284, "original_found_rows_cost": 1.111284,
"with_filter_found_rows_cost": 0.479185661, "with_filter_found_rows_cost": 0.479185661,
"org_cost": 3.705870471, "org_cost": 3.705870471,
"filter_cost": 2.161762502, "filter_cost": 2.292585745,
"filter_used": true "filter_used": true
}, },
"rows": 431.2, "rows": 431.2,
"cost": 2.161762502, "cost": 2.292585745,
"chosen": true "chosen": true
}, },
{ {

View File

@ -329,7 +329,7 @@ set optimizer_trace='enabled=on';
# 3-way ROR-intersection # 3-way ROR-intersection
explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref|filter key1,key2,key3 key1|key2 5|5 const 2243 (3%) Using where; Using rowid filter 1 SIMPLE t1 index_merge key1,key2,key3 key1,key2 5,5 NULL 77 Using intersect(key1,key2); Using where
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE; select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
[ [
@ -423,22 +423,6 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
}, },
"analyzing_index_merge_union": "analyzing_index_merge_union":
[] []
},
{
"range_scan_alternatives":
[
{
"index": "key2",
"ranges":
["(100) <= (key2) <= (100)"],
"rowid_ordered": true,
"using_mrr": false,
"index_only": true,
"rows": 2243,
"cost": 0.312832109,
"chosen": true
}
]
} }
] ]
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.chosen_range_access_summary')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE; select JSON_DETAILED(JSON_EXTRACT(trace, '$**.chosen_range_access_summary')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
@ -473,19 +457,6 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.chosen_range_access_summary'))
"rows_for_plan": 77, "rows_for_plan": 77,
"cost_for_plan": 0.572490756, "cost_for_plan": 0.572490756,
"chosen": true "chosen": true
},
{
"range_access_plan":
{
"type": "range_scan",
"index": "key2",
"rows": 2243,
"ranges":
["(100) <= (key2) <= (100)"]
},
"rows_for_plan": 2243,
"cost_for_plan": 0.312832109,
"chosen": true
} }
] ]
# ROR-union(ROR-intersection, ROR-range) # ROR-union(ROR-intersection, ROR-range)

View File

@ -31,8 +31,8 @@ OPTIMIZER_DISK_READ_RATIO 0.020000
OPTIMIZER_ROW_COPY_COST 0.060866 OPTIMIZER_ROW_COPY_COST 0.060866
OPTIMIZER_ROW_LOOKUP_COST 0.130839 OPTIMIZER_ROW_LOOKUP_COST 0.130839
OPTIMIZER_ROW_NEXT_FIND_COST 0.045916 OPTIMIZER_ROW_NEXT_FIND_COST 0.045916
OPTIMIZER_ROWID_COMPARE_COST 0.001000 OPTIMIZER_ROWID_COMPARE_COST 0.002653
OPTIMIZER_ROWID_COPY_COST 0.001000 OPTIMIZER_ROWID_COPY_COST 0.002653
ENGINE default ENGINE default
OPTIMIZER_DISK_READ_COST 10.240000 OPTIMIZER_DISK_READ_COST 10.240000
OPTIMIZER_INDEX_BLOCK_COPY_COST 0.035600 OPTIMIZER_INDEX_BLOCK_COPY_COST 0.035600

View File

@ -1967,7 +1967,7 @@ select count(*) from t2 left join t1
on (t1.key1 < 3 or t1.key1 between 920 and 930) and t1.key2 < 1000; on (t1.key1 < 3 or t1.key1 between 920 and 930) and t1.key2 < 1000;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 64 1 SIMPLE t2 ALL NULL NULL NULL NULL 64
1 SIMPLE t1 range|filter i1,i2 i1|i2 4|4 NULL 12 (89%) Using where; Using join buffer (flat, BNL join); Using rowid filter 1 SIMPLE t1 range i1,i2 i1 4 NULL 12 Using where; Using join buffer (flat, BNL join)
select count(*) from t2 left join t1 select count(*) from t2 left join t1
on (t1.key1 < 3 or t1.key1 between 920 and 930) and t1.key2 < 1000; on (t1.key1 < 3 or t1.key1 between 920 and 930) and t1.key2 < 1000;
count(*) count(*)

View File

@ -2214,695 +2214,3 @@ ALTER TABLE orders DROP COLUMN o_totaldiscount;
DROP VIEW v1; DROP VIEW v1;
DROP DATABASE dbt3_s001; DROP DATABASE dbt3_s001;
use test; use test;
#
# MDEV-18816: potential range filter for one join table with
# impossible WHERE for another
#
create table t1 (
pk int not null primary key, c2 varchar(10) , i1 int,key (c2)
) engine=myisam;
insert into t1 values (1,'a',-5),(2,'a',null);
create table t2 (
pk int, i1 int, c1 varchar(30) , key c1 (c1(30)), key i1 (i1)
) engine=myisam;
insert into t2 values
(1,-5,'a'),(2,null,'a'),(3,null,'a'),(4,null,'a'),(5,5,'a'),(6,null,'a'),
(7,4,'a'),(8,55,'a'),(9,null,'a'),(10,null,'a'),(11,null,'a'),(12,-5,'a'),
(13,-5,'a'),(14,null,'a'),(15,null,'a'),(16,-5,'a'),(17,-5,'a');
select 1
from t1
left join
t2 join t1 as t1_a on t2.i1 = t1_a.pk
on t1.c2 = t2.c1
where t1_a.pk is null and t1_a.i1 != 3;
1
explain extended select 1
from t1
left join
t2 join t1 as t1_a on t2.i1 = t1_a.pk
on t1.c2 = t2.c1
where t1_a.pk is null and t1_a.i1 != 3;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
Note 1003 select 1 AS `1` from `test`.`t1` join `test`.`t2` join `test`.`t1` `t1_a` where 0
drop table t1,t2;
#
# MDEV-18640: TABLE::prune_range_rowid_filters: Conditional jump or
# move depends on uninitialized value
#
CREATE TABLE t1 (
pk INT, i INT, PRIMARY KEY (pk), KEY (pk,i)
) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,10), (7,70), (2,20);
SELECT * FROM t1 WHERE pk < 5;
pk i
1 10
2 20
DROP TABLE t1;
#
# MDEV-18956: Possible rowid filter for subquery for which
# in_to_exists strategy has been chosen
#
CREATE TABLE t1 (pk int) engine=myisam ;
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (
pk int auto_increment PRIMARY KEY,
i1 int, i2 int, c2 varchar(1),
KEY (i1), KEY (i2)
) engine=myisam;
INSERT INTO t2 VALUES
(1,8,6,'t'),(2,5,7,'i'),(3,4,4,'h'),(4,207,38,'d'),(5,183,206,'b'),
(6,7,null,'o'),(7,1,2,'j'),(8,17,36,'s'),(9,4,5,'q'),(10,0,6,'l'),
(11,1,9,'j'),(12,5,6,'y'),(13,null,0,'i'),(14,7,7,'x'),(15,5,2,'u');
SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3);
pk
EXPLAIN EXTENDED
SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible HAVING
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL no matching row in const table
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`pk` AS `pk` from `test`.`t1` having 0
DROP TABLE t1,t2;
#
# MDEV-19255: rowid range filter built for range condition
# that uses in expensive subquery
#
CREATE TABLE t1 (
pk1 INT PRIMARY KEY, a1 INT, b1 VARCHAR(1), KEY(a1), KEY(b1)
) ENGINE=MyISAM;
INSERT INTO t1 VALUES
(10,0,'z'),(11,3,'j'),(12,8,'f'),(13,8,'p'),(14,6,'w'),(15,0,'c'),(16,1,'j'),
(17,1,'f'),(18,5,'v'),(19,3,'f'),(20,2,'q'),(21,8,'y'),(22,0,'a'),(23,9,'w'),
(24,3,'e'),(25,1,'b'),(26,9,'r'),(27,2,'k'),(28,5,'c'),(29,3,'k'),(30,9,'b'),
(31,8,'j'),(32,1,'t'),(33,8,'n'),(34,3,'z'),(35,0,'u'),(36,3,'a'),(37,3,'g'),
(38,1,'f'),(39,6,'p'),(40,6,'m'),(41,6,'t'),(42,7,'i'),(43,4,'h'),(44,3,'d'),
(45,2,'b'),(46,1,'o'),(47,2,'j'),(48,6,'s'),(49,5,'q'),(50,6,'l'),(51,9,'j'),
(52,6,'y'),(53,0,'i'),(54,7,'x'),(55,2,'u'),(56,6,'t'),(57,4,'b'),(58,5,'m'),
(59,4,'x'),(60,8,'x'),(61,6,'v'),(62,8,'m'),(63,4,'j'),(64,8,'z'),(65,2,'a'),
(66,9,'i'),(67,4,'g'),(68,8,'h'),(69,1,'p'),(70,8,'a'),(71,0,'x'),(72,2,'s'),
(73,6,'k'),(74,0,'m'),(75,6,'e'),(76,9,'y'),(77,7,'d'),(78,7,'w'),(79,6,'y'),
(80,9,'s'),(81,9,'x'),(82,6,'l'),(83,9,'f'),(84,8,'x'),(85,1,'p'),(86,7,'y'),
(87,6,'p'),(88,1,'g'),(89,3,'c'),(90,5,'h'),(91,3,'p'),(92,2,'b'),(93,1,NULL),
(94,3,NULL),(95,2,'y'),(96,7,'s'),(97,7,'x'),(98,6,'i'),(99,9,'t'),(100,5,'j'),
(101,0,'u'),(102,7,'r'),(103,2,'x'),(104,8,'e'),(105,8,'i'),(106,5,'q'),
(107,8,'z'),(108,3,'k'),(109,65,NULL);
CREATE TABLE t2 (pk2 INT PRIMARY KEY, a2 INT, b2 VARCHAR(1)) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1,1,'i');
INSERT INTO t2 SELECT * FROM t1;
INSERT INTO t1 SELECT pk1+200, a1, b1 FROM t1;
INSERT INTO t1 SELECT pk1+400, a1, b1 FROM t1;
ANALYZE TABLE t1,t2 PERSISTENT FOR ALL;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
test.t2 analyze status Engine-independent statistics collected
test.t2 analyze status OK
SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
pk1 a1 b1 pk2 a2 b2
17 1 f 16 1 j
37 3 g 36 3 a
105 8 i 104 8 e
EXPLAIN EXTENDED SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 101 100.00
1 PRIMARY t1 ALL a1,b1 NULL NULL NULL 400 2.61 Using where; Using join buffer (flat, BNL join)
2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 100.00 Using index condition
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`pk1` AS `pk1`,`test`.`t1`.`a1` AS `a1`,`test`.`t1`.`b1` AS `b1`,`test`.`t2`.`pk2` AS `pk2`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`b2` AS `b2` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`a1` = `test`.`t2`.`a2` and `test`.`t1`.`b1` <= (/* select#2 */ select max(`test`.`t2`.`b2`) from `test`.`t2` where `test`.`t2`.`pk2` <= 1) and `test`.`t1`.`pk1` + 1 = `test`.`t2`.`pk2` + 2
set @@optimizer_where_cost=0.0356*4;
EXPLAIN EXTENDED SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 101 100.00 Using where
1 PRIMARY t1 ref|filter a1,b1 a1|b1 5|4 test.t2.a2 36 (29%) 28.75 Using where; Using rowid filter
2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 100.00 Using index condition
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`pk1` AS `pk1`,`test`.`t1`.`a1` AS `a1`,`test`.`t1`.`b1` AS `b1`,`test`.`t2`.`pk2` AS `pk2`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`b2` AS `b2` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`a1` = `test`.`t2`.`a2` and `test`.`t1`.`b1` <= (/* select#2 */ select max(`test`.`t2`.`b2`) from `test`.`t2` where `test`.`t2`.`pk2` <= 1) and `test`.`t1`.`pk1` + 1 = `test`.`t2`.`pk2` + 2
EXPLAIN FORMAT=JSON SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
EXPLAIN
{
"query_block": {
"select_id": 1,
"nested_loop": [
{
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 101,
"filtered": 100,
"attached_condition": "t2.a2 is not null"
}
},
{
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["a1", "b1"],
"key": "a1",
"key_length": "5",
"used_key_parts": ["a1"],
"ref": ["test.t2.a2"],
"rowid_filter": {
"range": {
"key": "b1",
"used_key_parts": ["b1"]
},
"rows": 115,
"selectivity_pct": 28.75
},
"rows": 36,
"filtered": 28.75,
"attached_condition": "t1.b1 <= (subquery#2) and t1.pk1 + 1 = t2.pk2 + 2"
}
}
],
"subqueries": [
{
"query_block": {
"select_id": 2,
"nested_loop": [
{
"table": {
"table_name": "t2",
"access_type": "range",
"possible_keys": ["PRIMARY"],
"key": "PRIMARY",
"key_length": "4",
"used_key_parts": ["pk2"],
"rows": 1,
"filtered": 100,
"index_condition": "t2.pk2 <= 1"
}
}
]
}
}
]
}
}
set @@optimizer_where_cost=default;
DROP TABLE t1,t2;
#
# MDEV-21794: Optimizer flag rowid_filter leads to long query
#
create table t10(a int);
insert into t10 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t11(a int);
insert into t11 select A.a + B.a* 10 + C.a * 100 from t10 A, t10 B, t10 C;
CREATE TABLE t1 (
el_id int(10) unsigned NOT NULL ,
el_index blob NOT NULL,
el_index_60 varbinary(60) NOT NULL,
filler blob,
PRIMARY KEY (el_id),
KEY el_index (el_index(60)),
KEY el_index_60 (el_index_60,el_id)
);
insert into t1
select
A.a+1000*B.a,
A.a+1000*B.a + 10000,
A.a+1000*B.a + 10000,
'filler-data-filler-data'
from
t11 A, t10 B;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'el_index'
test.t1 analyze Warning Engine-independent statistics are not collected for column 'filler'
test.t1 analyze status Table is already up to date
# This must not use rowid_filter with key=el_index|el_index_60:
explain
select * from t1
where el_index like '10%' and (el_index_60 like '10%' or el_index_60 like '20%');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range el_index,el_index_60 el_index 62 NULL 645 Using where
drop table t10, t11, t1;
#
# MDEV-22160: SIGSEGV in st_join_table::save_explain_data on SELECT
#
set @save_optimizer_switch= @@optimizer_switch;
SET @@optimizer_switch="index_merge_sort_union=OFF";
CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b));
INSERT INTO t1 VALUES (0,0),(0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4),(3,3),(3,4),(3,5),(8,8),(8,9),(1,0),(2,0),(0,0),(0,0);
explain
SELECT * FROM t1 WHERE a > 0 AND b=0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref|filter a,b b|a 5|5 const 7 (47%) Using where; Using rowid filter
SELECT * FROM t1 WHERE a > 0 AND b=0;
a b
1 0
1 0
2 0
drop table t1;
SET @@optimizer_switch=@save_optimizer_switch;
#
# MDEV-28846: Poor performance when rowid filter contains no elements
#
create table t1 (
pk int primary key auto_increment,
nm varchar(32),
fl1 tinyint default 0,
fl2 tinyint default 0,
index idx1(nm, fl1),
index idx2(fl2)
) engine=myisam;
create table name (
pk int primary key auto_increment,
nm bigint
) engine=myisam;
create table flag2 (
pk int primary key auto_increment,
fl2 tinyint
) engine=myisam;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 2 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select '500%' as a;
a
500%
set optimizer_switch='rowid_filter=on';
explain
select * from t1 where nm like '500%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx1,idx2 idx1 35 NULL 1 Using index condition; Using where
analyze format=json
select * from t1 where nm like '500%' AND fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "35",
"used_key_parts": ["nm"],
"r_loops": 1,
"rows": 1,
"r_rows": 1,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 49.20000076,
"r_filtered": 100,
"index_condition": "t1.nm like '500%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
select * from t1 where nm like '500%' AND fl2 = 0;
pk nm fl1 fl2
517 500 0 0
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 2 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
set optimizer_switch='rowid_filter=off';
explain
select * from t1 where nm like '500%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx1,idx2 idx1 35 NULL 1 Using index condition; Using where
analyze format=json
select * from t1 where nm like '500%' AND fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "35",
"used_key_parts": ["nm"],
"r_loops": 1,
"rows": 1,
"r_rows": 1,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 49.20000076,
"r_filtered": 100,
"index_condition": "t1.nm like '500%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
select * from t1 where nm like '500%' AND fl2 = 0;
pk nm fl1 fl2
517 500 0 0
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 10 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select '607%' as a;
a
607%
set optimizer_switch='rowid_filter=on';
explain
select * from t1 where nm like '607%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx1,idx2 idx1 35 NULL 1 Using index condition; Using where
select * from t1 where nm like '607%' AND fl2 = 0;
pk nm fl1 fl2
721 607 0 0
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_10000 order by rand(17);
insert into flag2(fl2) select seq mod 100 from seq_1_to_10000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select '75%' as a;
a
75%
set optimizer_switch='rowid_filter=on';
explain
select * from t1 where nm like '75%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref|filter idx1,idx2 idx2|idx1 2|35 const 55 (1%) Using where; Using rowid filter
analyze format=json
select * from t1 where nm like '75%' AND fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["idx1", "idx2"],
"key": "idx2",
"key_length": "2",
"used_key_parts": ["fl2"],
"ref": ["const"],
"rowid_filter": {
"range": {
"key": "idx1",
"used_key_parts": ["nm"]
},
"rows": 115,
"selectivity_pct": 1.15,
"r_rows": 111,
"r_lookups": 100,
"r_selectivity_pct": 2,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"r_loops": 1,
"rows": 55,
"r_rows": 2,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 1.149999976,
"r_filtered": 100,
"attached_condition": "t1.nm like '75%'"
}
}
]
}
}
select * from t1 where nm like '75%' AND fl2 = 0;
pk nm fl1 fl2
4543 7503 0 0
7373 7518 0 0
drop table name, flag2;
drop table t1;
create table t1 (
pk int primary key auto_increment,
nm char(255),
fl1 tinyint default 0,
fl2 int default 0,
index idx1(nm, fl1),
index idx2(fl2)
) engine=myisam;
create table name (
pk int primary key auto_increment,
nm bigint
) engine=myisam;
create table flag2 (
pk int primary key auto_increment,
fl2 int
) engine=myisam;
insert into name(nm) select seq from seq_1_to_10000 order by rand(17);
insert into flag2(fl2) select seq mod 10 from seq_1_to_10000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
pk nm fl1 fl2
analyze format=json select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "256",
"used_key_parts": ["nm"],
"rowid_filter": {
"range": {
"key": "idx2",
"used_key_parts": ["fl2"]
},
"rows": 863,
"selectivity_pct": 8.63,
"r_rows": 1000,
"r_lookups": 44,
"r_selectivity_pct": 0,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"r_loops": 1,
"rows": 44,
"r_rows": 0,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 8.630000114,
"r_filtered": 100,
"index_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
create table t0 select * from t1 where nm like '34%';
delete from t1 using t1,t0 where t1.nm=t0.nm;
analyze format=json select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "256",
"used_key_parts": ["nm"],
"rowid_filter": {
"range": {
"key": "idx2",
"used_key_parts": ["fl2"]
},
"rows": 853,
"selectivity_pct": 8.53,
"r_rows": 987,
"r_lookups": 0,
"r_selectivity_pct": 0,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"r_loops": 1,
"rows": 44,
"r_rows": 0,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 8.529999733,
"r_filtered": 100,
"index_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
drop table t0;
set optimizer_switch='rowid_filter=default';
drop table name, flag2;
drop table t1;
set @@use_stat_tables=@save_use_stat_tables;
#
# MDEV-21633
# Assertion `tmp >= 0' failed in best_access_path with rowid_filter=ON
#
set @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch='rowid_filter=on';
CREATE TABLE t1 (
pk INT AUTO_INCREMENT,
a INT,
b VARCHAR(8),
KEY(a),
PRIMARY KEY(pk),
KEY (a,pk)
) ENGINE=MyISAM;
INSERT INTO t1 (a,b) VALUES
(NULL,'d'),(9,'b'),(2,'x'),(5,'k'),(NULL,'d'),(3,'s'),(5,'k'),(1,'r'),
(8,'l'),(3,'z'),(1,'c'),(1,'q'),(NULL,'x'),(NULL,'p'),(NULL,'z'),(7,'a'),
(0,'i'),(3,'s'),(NULL,'h'),(4,'p'),(1,'i'),(4,'f'),(1,'c'),(NULL,'a'),
(NULL,'x'),(1,'b'),(NULL,'n'),(NULL,'h'),(5,'i'),(6,'e'),(NULL,'i'),
(7,'e'),(1,'r'),(NULL,'z'),(1,'i'),(14,'c'),(6,'u'),(3,'b'),(4,'z'),
(2,'c'),(70,'d'),(NULL,'p'),(21,'j'),(6,'e'),(5,'c'),(13,'i'),(42,'d'),
(80,'s'),(14,'t'),(9,'a'),(0,'2'),(0,NULL),(0,NULL),(0,NULL),(0,''),
(0,''),(0,'1'),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,''),(0,''),
(0,NULL),(0,''),(0,''),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,NULL),
(0,NULL),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,NULL),
(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,''),(0,''),(0,''),(0,''),
(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,'');
CREATE TABLE t2 (c INT) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
pk a b c
6 3 s 3
4 5 k 5
7 5 k 5
explain SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range|filter PRIMARY,a,a_2 PRIMARY|a 4|5 NULL 4 (11%) Using index condition; Using where; Using rowid filter
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join)
SET optimizer_switch='rowid_filter=off';
SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
pk a b c
6 3 s 3
4 5 k 5
7 5 k 5
SET @@optimizer_switch=@save_optimizer_switch;
DROP TABLE t1, t2;

View File

@ -250,411 +250,3 @@ DROP VIEW v1;
DROP DATABASE dbt3_s001; DROP DATABASE dbt3_s001;
use test; use test;
--echo #
--echo # MDEV-18816: potential range filter for one join table with
--echo # impossible WHERE for another
--echo #
create table t1 (
pk int not null primary key, c2 varchar(10) , i1 int,key (c2)
) engine=myisam;
insert into t1 values (1,'a',-5),(2,'a',null);
create table t2 (
pk int, i1 int, c1 varchar(30) , key c1 (c1(30)), key i1 (i1)
) engine=myisam;
insert into t2 values
(1,-5,'a'),(2,null,'a'),(3,null,'a'),(4,null,'a'),(5,5,'a'),(6,null,'a'),
(7,4,'a'),(8,55,'a'),(9,null,'a'),(10,null,'a'),(11,null,'a'),(12,-5,'a'),
(13,-5,'a'),(14,null,'a'),(15,null,'a'),(16,-5,'a'),(17,-5,'a');
let $q=
select 1
from t1
left join
t2 join t1 as t1_a on t2.i1 = t1_a.pk
on t1.c2 = t2.c1
where t1_a.pk is null and t1_a.i1 != 3;
eval $q;
eval explain extended $q;
drop table t1,t2;
--echo #
--echo # MDEV-18640: TABLE::prune_range_rowid_filters: Conditional jump or
--echo # move depends on uninitialized value
--echo #
CREATE TABLE t1 (
pk INT, i INT, PRIMARY KEY (pk), KEY (pk,i)
) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,10), (7,70), (2,20);
SELECT * FROM t1 WHERE pk < 5;
DROP TABLE t1;
--echo #
--echo # MDEV-18956: Possible rowid filter for subquery for which
--echo # in_to_exists strategy has been chosen
--echo #
CREATE TABLE t1 (pk int) engine=myisam ;
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (
pk int auto_increment PRIMARY KEY,
i1 int, i2 int, c2 varchar(1),
KEY (i1), KEY (i2)
) engine=myisam;
INSERT INTO t2 VALUES
(1,8,6,'t'),(2,5,7,'i'),(3,4,4,'h'),(4,207,38,'d'),(5,183,206,'b'),
(6,7,null,'o'),(7,1,2,'j'),(8,17,36,'s'),(9,4,5,'q'),(10,0,6,'l'),
(11,1,9,'j'),(12,5,6,'y'),(13,null,0,'i'),(14,7,7,'x'),(15,5,2,'u');
SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3);
EXPLAIN EXTENDED
SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3);
DROP TABLE t1,t2;
--echo #
--echo # MDEV-19255: rowid range filter built for range condition
--echo # that uses in expensive subquery
--echo #
CREATE TABLE t1 (
pk1 INT PRIMARY KEY, a1 INT, b1 VARCHAR(1), KEY(a1), KEY(b1)
) ENGINE=MyISAM;
INSERT INTO t1 VALUES
(10,0,'z'),(11,3,'j'),(12,8,'f'),(13,8,'p'),(14,6,'w'),(15,0,'c'),(16,1,'j'),
(17,1,'f'),(18,5,'v'),(19,3,'f'),(20,2,'q'),(21,8,'y'),(22,0,'a'),(23,9,'w'),
(24,3,'e'),(25,1,'b'),(26,9,'r'),(27,2,'k'),(28,5,'c'),(29,3,'k'),(30,9,'b'),
(31,8,'j'),(32,1,'t'),(33,8,'n'),(34,3,'z'),(35,0,'u'),(36,3,'a'),(37,3,'g'),
(38,1,'f'),(39,6,'p'),(40,6,'m'),(41,6,'t'),(42,7,'i'),(43,4,'h'),(44,3,'d'),
(45,2,'b'),(46,1,'o'),(47,2,'j'),(48,6,'s'),(49,5,'q'),(50,6,'l'),(51,9,'j'),
(52,6,'y'),(53,0,'i'),(54,7,'x'),(55,2,'u'),(56,6,'t'),(57,4,'b'),(58,5,'m'),
(59,4,'x'),(60,8,'x'),(61,6,'v'),(62,8,'m'),(63,4,'j'),(64,8,'z'),(65,2,'a'),
(66,9,'i'),(67,4,'g'),(68,8,'h'),(69,1,'p'),(70,8,'a'),(71,0,'x'),(72,2,'s'),
(73,6,'k'),(74,0,'m'),(75,6,'e'),(76,9,'y'),(77,7,'d'),(78,7,'w'),(79,6,'y'),
(80,9,'s'),(81,9,'x'),(82,6,'l'),(83,9,'f'),(84,8,'x'),(85,1,'p'),(86,7,'y'),
(87,6,'p'),(88,1,'g'),(89,3,'c'),(90,5,'h'),(91,3,'p'),(92,2,'b'),(93,1,NULL),
(94,3,NULL),(95,2,'y'),(96,7,'s'),(97,7,'x'),(98,6,'i'),(99,9,'t'),(100,5,'j'),
(101,0,'u'),(102,7,'r'),(103,2,'x'),(104,8,'e'),(105,8,'i'),(106,5,'q'),
(107,8,'z'),(108,3,'k'),(109,65,NULL);
CREATE TABLE t2 (pk2 INT PRIMARY KEY, a2 INT, b2 VARCHAR(1)) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1,1,'i');
INSERT INTO t2 SELECT * FROM t1;
INSERT INTO t1 SELECT pk1+200, a1, b1 FROM t1;
INSERT INTO t1 SELECT pk1+400, a1, b1 FROM t1;
ANALYZE TABLE t1,t2 PERSISTENT FOR ALL;
let $q=
SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
eval $q;
eval EXPLAIN EXTENDED $q;
set @@optimizer_where_cost=0.0356*4;
eval EXPLAIN EXTENDED $q;
eval EXPLAIN FORMAT=JSON $q;
set @@optimizer_where_cost=default;
DROP TABLE t1,t2;
--echo #
--echo # MDEV-21794: Optimizer flag rowid_filter leads to long query
--echo #
create table t10(a int);
insert into t10 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t11(a int);
insert into t11 select A.a + B.a* 10 + C.a * 100 from t10 A, t10 B, t10 C;
CREATE TABLE t1 (
el_id int(10) unsigned NOT NULL ,
el_index blob NOT NULL,
el_index_60 varbinary(60) NOT NULL,
filler blob,
PRIMARY KEY (el_id),
KEY el_index (el_index(60)),
KEY el_index_60 (el_index_60,el_id)
);
insert into t1
select
A.a+1000*B.a,
A.a+1000*B.a + 10000,
A.a+1000*B.a + 10000,
'filler-data-filler-data'
from
t11 A, t10 B;
analyze table t1 persistent for all;
--echo # This must not use rowid_filter with key=el_index|el_index_60:
explain
select * from t1
where el_index like '10%' and (el_index_60 like '10%' or el_index_60 like '20%');
drop table t10, t11, t1;
--echo #
--echo # MDEV-22160: SIGSEGV in st_join_table::save_explain_data on SELECT
--echo #
set @save_optimizer_switch= @@optimizer_switch;
SET @@optimizer_switch="index_merge_sort_union=OFF";
CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b));
INSERT INTO t1 VALUES (0,0),(0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4),(3,3),(3,4),(3,5),(8,8),(8,9),(1,0),(2,0),(0,0),(0,0);
explain
SELECT * FROM t1 WHERE a > 0 AND b=0;
SELECT * FROM t1 WHERE a > 0 AND b=0;
drop table t1;
SET @@optimizer_switch=@save_optimizer_switch;
--echo #
--echo # MDEV-28846: Poor performance when rowid filter contains no elements
--echo #
--source include/have_sequence.inc
create table t1 (
pk int primary key auto_increment,
nm varchar(32),
fl1 tinyint default 0,
fl2 tinyint default 0,
index idx1(nm, fl1),
index idx2(fl2)
) engine=myisam;
create table name (
pk int primary key auto_increment,
nm bigint
) engine=myisam;
create table flag2 (
pk int primary key auto_increment,
fl2 tinyint
) engine=myisam;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 2 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
let $a=
`select concat((select nm from t1 where fl2=0 order by RAND(13) limit 1),'%')`;
eval select '$a' as a;
set optimizer_switch='rowid_filter=on';
eval
explain
select * from t1 where nm like '$a' AND fl2 = 0;
--source include/analyze-format.inc
eval
analyze format=json
select * from t1 where nm like '$a' AND fl2 = 0;
eval
select * from t1 where nm like '$a' AND fl2 = 0;
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 2 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
set optimizer_switch='rowid_filter=off';
eval
explain
select * from t1 where nm like '$a' AND fl2 = 0;
--source include/analyze-format.inc
eval
analyze format=json
select * from t1 where nm like '$a' AND fl2 = 0;
eval
select * from t1 where nm like '$a' AND fl2 = 0;
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 10 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
let $a=
`select concat((select nm from t1 where fl2=0 order by RAND(13) limit 1),'%')`;
eval select '$a' as a;
set optimizer_switch='rowid_filter=on';
eval
explain
select * from t1 where nm like '$a' AND fl2 = 0;
eval
select * from t1 where nm like '$a' AND fl2 = 0;
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_10000 order by rand(17);
insert into flag2(fl2) select seq mod 100 from seq_1_to_10000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
let $a=
`select concat(left((select nm from t1 where fl2=0 order by RAND(13) limit 1),2),'%')`;
eval select '$a' as a;
set optimizer_switch='rowid_filter=on';
eval
explain
select * from t1 where nm like '$a' AND fl2 = 0;
--source include/analyze-format.inc
eval
analyze format=json
select * from t1 where nm like '$a' AND fl2 = 0;
eval
select * from t1 where nm like '$a' AND fl2 = 0;
drop table name, flag2;
drop table t1;
# This test shows that if the container is empty there are no lookups into it
create table t1 (
pk int primary key auto_increment,
nm char(255),
fl1 tinyint default 0,
fl2 int default 0,
index idx1(nm, fl1),
index idx2(fl2)
) engine=myisam;
create table name (
pk int primary key auto_increment,
nm bigint
) engine=myisam;
create table flag2 (
pk int primary key auto_increment,
fl2 int
) engine=myisam;
insert into name(nm) select seq from seq_1_to_10000 order by rand(17);
insert into flag2(fl2) select seq mod 10 from seq_1_to_10000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
let $q=
select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
eval $q;
--source include/analyze-format.inc
eval analyze format=json $q;
create table t0 select * from t1 where nm like '34%';
delete from t1 using t1,t0 where t1.nm=t0.nm;
--source include/analyze-format.inc
eval analyze format=json $q;
drop table t0;
set optimizer_switch='rowid_filter=default';
drop table name, flag2;
drop table t1;
set @@use_stat_tables=@save_use_stat_tables;
--echo #
--echo # MDEV-21633
--echo # Assertion `tmp >= 0' failed in best_access_path with rowid_filter=ON
--echo #
set @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch='rowid_filter=on';
CREATE TABLE t1 (
pk INT AUTO_INCREMENT,
a INT,
b VARCHAR(8),
KEY(a),
PRIMARY KEY(pk),
KEY (a,pk)
) ENGINE=MyISAM;
INSERT INTO t1 (a,b) VALUES
(NULL,'d'),(9,'b'),(2,'x'),(5,'k'),(NULL,'d'),(3,'s'),(5,'k'),(1,'r'),
(8,'l'),(3,'z'),(1,'c'),(1,'q'),(NULL,'x'),(NULL,'p'),(NULL,'z'),(7,'a'),
(0,'i'),(3,'s'),(NULL,'h'),(4,'p'),(1,'i'),(4,'f'),(1,'c'),(NULL,'a'),
(NULL,'x'),(1,'b'),(NULL,'n'),(NULL,'h'),(5,'i'),(6,'e'),(NULL,'i'),
(7,'e'),(1,'r'),(NULL,'z'),(1,'i'),(14,'c'),(6,'u'),(3,'b'),(4,'z'),
(2,'c'),(70,'d'),(NULL,'p'),(21,'j'),(6,'e'),(5,'c'),(13,'i'),(42,'d'),
(80,'s'),(14,'t'),(9,'a'),(0,'2'),(0,NULL),(0,NULL),(0,NULL),(0,''),
(0,''),(0,'1'),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,''),(0,''),
(0,NULL),(0,''),(0,''),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,NULL),
(0,NULL),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,NULL),
(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,''),(0,''),(0,''),(0,''),
(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,'');
CREATE TABLE t2 (c INT) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
explain SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
SET optimizer_switch='rowid_filter=off';
SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
SET @@optimizer_switch=@save_optimizer_switch;
# Cleanup
DROP TABLE t1, t2;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
#
# Test rowid filters with Aria
#
SET SESSION DEFAULT_STORAGE_ENGINE='Aria';
#set global aria.optimizer_rowid_compare_cost=0.00001;
#set global aria.optimizer_rowid_copy_cost=0.00001;
--source rowid_filter.test

View File

@ -2141,698 +2141,6 @@ ALTER TABLE orders DROP COLUMN o_totaldiscount;
DROP VIEW v1; DROP VIEW v1;
DROP DATABASE dbt3_s001; DROP DATABASE dbt3_s001;
use test; use test;
#
# MDEV-18816: potential range filter for one join table with
# impossible WHERE for another
#
create table t1 (
pk int not null primary key, c2 varchar(10) , i1 int,key (c2)
) engine=myisam;
insert into t1 values (1,'a',-5),(2,'a',null);
create table t2 (
pk int, i1 int, c1 varchar(30) , key c1 (c1(30)), key i1 (i1)
) engine=myisam;
insert into t2 values
(1,-5,'a'),(2,null,'a'),(3,null,'a'),(4,null,'a'),(5,5,'a'),(6,null,'a'),
(7,4,'a'),(8,55,'a'),(9,null,'a'),(10,null,'a'),(11,null,'a'),(12,-5,'a'),
(13,-5,'a'),(14,null,'a'),(15,null,'a'),(16,-5,'a'),(17,-5,'a');
select 1
from t1
left join
t2 join t1 as t1_a on t2.i1 = t1_a.pk
on t1.c2 = t2.c1
where t1_a.pk is null and t1_a.i1 != 3;
1
explain extended select 1
from t1
left join
t2 join t1 as t1_a on t2.i1 = t1_a.pk
on t1.c2 = t2.c1
where t1_a.pk is null and t1_a.i1 != 3;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
Note 1003 select 1 AS `1` from `test`.`t1` join `test`.`t2` join `test`.`t1` `t1_a` where 0
drop table t1,t2;
#
# MDEV-18640: TABLE::prune_range_rowid_filters: Conditional jump or
# move depends on uninitialized value
#
CREATE TABLE t1 (
pk INT, i INT, PRIMARY KEY (pk), KEY (pk,i)
) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,10), (7,70), (2,20);
SELECT * FROM t1 WHERE pk < 5;
pk i
1 10
2 20
DROP TABLE t1;
#
# MDEV-18956: Possible rowid filter for subquery for which
# in_to_exists strategy has been chosen
#
CREATE TABLE t1 (pk int) engine=myisam ;
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (
pk int auto_increment PRIMARY KEY,
i1 int, i2 int, c2 varchar(1),
KEY (i1), KEY (i2)
) engine=myisam;
INSERT INTO t2 VALUES
(1,8,6,'t'),(2,5,7,'i'),(3,4,4,'h'),(4,207,38,'d'),(5,183,206,'b'),
(6,7,null,'o'),(7,1,2,'j'),(8,17,36,'s'),(9,4,5,'q'),(10,0,6,'l'),
(11,1,9,'j'),(12,5,6,'y'),(13,null,0,'i'),(14,7,7,'x'),(15,5,2,'u');
SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3);
pk
EXPLAIN EXTENDED
SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible HAVING
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL no matching row in const table
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`pk` AS `pk` from `test`.`t1` having 0
DROP TABLE t1,t2;
#
# MDEV-19255: rowid range filter built for range condition
# that uses in expensive subquery
#
CREATE TABLE t1 (
pk1 INT PRIMARY KEY, a1 INT, b1 VARCHAR(1), KEY(a1), KEY(b1)
) ENGINE=MyISAM;
INSERT INTO t1 VALUES
(10,0,'z'),(11,3,'j'),(12,8,'f'),(13,8,'p'),(14,6,'w'),(15,0,'c'),(16,1,'j'),
(17,1,'f'),(18,5,'v'),(19,3,'f'),(20,2,'q'),(21,8,'y'),(22,0,'a'),(23,9,'w'),
(24,3,'e'),(25,1,'b'),(26,9,'r'),(27,2,'k'),(28,5,'c'),(29,3,'k'),(30,9,'b'),
(31,8,'j'),(32,1,'t'),(33,8,'n'),(34,3,'z'),(35,0,'u'),(36,3,'a'),(37,3,'g'),
(38,1,'f'),(39,6,'p'),(40,6,'m'),(41,6,'t'),(42,7,'i'),(43,4,'h'),(44,3,'d'),
(45,2,'b'),(46,1,'o'),(47,2,'j'),(48,6,'s'),(49,5,'q'),(50,6,'l'),(51,9,'j'),
(52,6,'y'),(53,0,'i'),(54,7,'x'),(55,2,'u'),(56,6,'t'),(57,4,'b'),(58,5,'m'),
(59,4,'x'),(60,8,'x'),(61,6,'v'),(62,8,'m'),(63,4,'j'),(64,8,'z'),(65,2,'a'),
(66,9,'i'),(67,4,'g'),(68,8,'h'),(69,1,'p'),(70,8,'a'),(71,0,'x'),(72,2,'s'),
(73,6,'k'),(74,0,'m'),(75,6,'e'),(76,9,'y'),(77,7,'d'),(78,7,'w'),(79,6,'y'),
(80,9,'s'),(81,9,'x'),(82,6,'l'),(83,9,'f'),(84,8,'x'),(85,1,'p'),(86,7,'y'),
(87,6,'p'),(88,1,'g'),(89,3,'c'),(90,5,'h'),(91,3,'p'),(92,2,'b'),(93,1,NULL),
(94,3,NULL),(95,2,'y'),(96,7,'s'),(97,7,'x'),(98,6,'i'),(99,9,'t'),(100,5,'j'),
(101,0,'u'),(102,7,'r'),(103,2,'x'),(104,8,'e'),(105,8,'i'),(106,5,'q'),
(107,8,'z'),(108,3,'k'),(109,65,NULL);
CREATE TABLE t2 (pk2 INT PRIMARY KEY, a2 INT, b2 VARCHAR(1)) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1,1,'i');
INSERT INTO t2 SELECT * FROM t1;
INSERT INTO t1 SELECT pk1+200, a1, b1 FROM t1;
INSERT INTO t1 SELECT pk1+400, a1, b1 FROM t1;
ANALYZE TABLE t1,t2 PERSISTENT FOR ALL;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
test.t2 analyze status Engine-independent statistics collected
test.t2 analyze status OK
SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
pk1 a1 b1 pk2 a2 b2
17 1 f 16 1 j
37 3 g 36 3 a
105 8 i 104 8 e
EXPLAIN EXTENDED SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 101 100.00
1 PRIMARY t1 ALL a1,b1 NULL NULL NULL 400 2.61 Using where; Using join buffer (flat, BNL join)
2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 100.00 Using index condition
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`pk1` AS `pk1`,`test`.`t1`.`a1` AS `a1`,`test`.`t1`.`b1` AS `b1`,`test`.`t2`.`pk2` AS `pk2`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`b2` AS `b2` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`a1` = `test`.`t2`.`a2` and `test`.`t1`.`b1` <= (/* select#2 */ select max(`test`.`t2`.`b2`) from `test`.`t2` where `test`.`t2`.`pk2` <= 1) and `test`.`t1`.`pk1` + 1 = `test`.`t2`.`pk2` + 2
set @@optimizer_where_cost=0.0356*4;
EXPLAIN EXTENDED SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 101 100.00 Using where
1 PRIMARY t1 ref|filter a1,b1 a1|b1 5|4 test.t2.a2 36 (29%) 28.75 Using where; Using rowid filter
2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 100.00 Using index condition
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`pk1` AS `pk1`,`test`.`t1`.`a1` AS `a1`,`test`.`t1`.`b1` AS `b1`,`test`.`t2`.`pk2` AS `pk2`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`b2` AS `b2` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`a1` = `test`.`t2`.`a2` and `test`.`t1`.`b1` <= (/* select#2 */ select max(`test`.`t2`.`b2`) from `test`.`t2` where `test`.`t2`.`pk2` <= 1) and `test`.`t1`.`pk1` + 1 = `test`.`t2`.`pk2` + 2
EXPLAIN FORMAT=JSON SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
EXPLAIN
{
"query_block": {
"select_id": 1,
"nested_loop": [
{
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 101,
"filtered": 100,
"attached_condition": "t2.a2 is not null"
}
},
{
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["a1", "b1"],
"key": "a1",
"key_length": "5",
"used_key_parts": ["a1"],
"ref": ["test.t2.a2"],
"rowid_filter": {
"range": {
"key": "b1",
"used_key_parts": ["b1"]
},
"rows": 115,
"selectivity_pct": 28.75
},
"rows": 36,
"filtered": 28.75,
"attached_condition": "t1.b1 <= (subquery#2) and t1.pk1 + 1 = t2.pk2 + 2"
}
}
],
"subqueries": [
{
"query_block": {
"select_id": 2,
"nested_loop": [
{
"table": {
"table_name": "t2",
"access_type": "range",
"possible_keys": ["PRIMARY"],
"key": "PRIMARY",
"key_length": "4",
"used_key_parts": ["pk2"],
"rows": 1,
"filtered": 100,
"index_condition": "t2.pk2 <= 1"
}
}
]
}
}
]
}
}
set @@optimizer_where_cost=default;
DROP TABLE t1,t2;
#
# MDEV-21794: Optimizer flag rowid_filter leads to long query
#
create table t10(a int);
insert into t10 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t11(a int);
insert into t11 select A.a + B.a* 10 + C.a * 100 from t10 A, t10 B, t10 C;
CREATE TABLE t1 (
el_id int(10) unsigned NOT NULL ,
el_index blob NOT NULL,
el_index_60 varbinary(60) NOT NULL,
filler blob,
PRIMARY KEY (el_id),
KEY el_index (el_index(60)),
KEY el_index_60 (el_index_60,el_id)
);
insert into t1
select
A.a+1000*B.a,
A.a+1000*B.a + 10000,
A.a+1000*B.a + 10000,
'filler-data-filler-data'
from
t11 A, t10 B;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'el_index'
test.t1 analyze Warning Engine-independent statistics are not collected for column 'filler'
test.t1 analyze status OK
# This must not use rowid_filter with key=el_index|el_index_60:
explain
select * from t1
where el_index like '10%' and (el_index_60 like '10%' or el_index_60 like '20%');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range el_index,el_index_60 el_index 62 NULL 1000 Using where
drop table t10, t11, t1;
#
# MDEV-22160: SIGSEGV in st_join_table::save_explain_data on SELECT
#
set @save_optimizer_switch= @@optimizer_switch;
SET @@optimizer_switch="index_merge_sort_union=OFF";
CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b));
INSERT INTO t1 VALUES (0,0),(0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4),(3,3),(3,4),(3,5),(8,8),(8,9),(1,0),(2,0),(0,0),(0,0);
explain
SELECT * FROM t1 WHERE a > 0 AND b=0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref|filter a,b b|a 5|5 const 7 (47%) Using where; Using rowid filter
SELECT * FROM t1 WHERE a > 0 AND b=0;
a b
1 0
1 0
2 0
drop table t1;
SET @@optimizer_switch=@save_optimizer_switch;
#
# MDEV-28846: Poor performance when rowid filter contains no elements
#
create table t1 (
pk int primary key auto_increment,
nm varchar(32),
fl1 tinyint default 0,
fl2 tinyint default 0,
index idx1(nm, fl1),
index idx2(fl2)
) engine=myisam;
create table name (
pk int primary key auto_increment,
nm bigint
) engine=myisam;
create table flag2 (
pk int primary key auto_increment,
fl2 tinyint
) engine=myisam;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 2 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select '500%' as a;
a
500%
set optimizer_switch='rowid_filter=on';
explain
select * from t1 where nm like '500%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx1,idx2 idx1 35 NULL 1 Using index condition; Using where
analyze format=json
select * from t1 where nm like '500%' AND fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "35",
"used_key_parts": ["nm"],
"r_loops": 1,
"rows": 1,
"r_rows": 1,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 49.20000076,
"r_filtered": 100,
"index_condition": "t1.nm like '500%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
select * from t1 where nm like '500%' AND fl2 = 0;
pk nm fl1 fl2
517 500 0 0
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 2 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
set optimizer_switch='rowid_filter=off';
explain
select * from t1 where nm like '500%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx1,idx2 idx1 35 NULL 1 Using index condition; Using where
analyze format=json
select * from t1 where nm like '500%' AND fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "35",
"used_key_parts": ["nm"],
"r_loops": 1,
"rows": 1,
"r_rows": 1,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 49.20000076,
"r_filtered": 100,
"index_condition": "t1.nm like '500%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
select * from t1 where nm like '500%' AND fl2 = 0;
pk nm fl1 fl2
517 500 0 0
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 10 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select '607%' as a;
a
607%
set optimizer_switch='rowid_filter=on';
explain
select * from t1 where nm like '607%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx1,idx2 idx1 35 NULL 1 Using index condition; Using where
select * from t1 where nm like '607%' AND fl2 = 0;
pk nm fl1 fl2
721 607 0 0
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_10000 order by rand(17);
insert into flag2(fl2) select seq mod 100 from seq_1_to_10000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select '75%' as a;
a
75%
set optimizer_switch='rowid_filter=on';
explain
select * from t1 where nm like '75%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref|filter idx1,idx2 idx2|idx1 2|35 const 55 (1%) Using where; Using rowid filter
analyze format=json
select * from t1 where nm like '75%' AND fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["idx1", "idx2"],
"key": "idx2",
"key_length": "2",
"used_key_parts": ["fl2"],
"ref": ["const"],
"rowid_filter": {
"range": {
"key": "idx1",
"used_key_parts": ["nm"]
},
"rows": 115,
"selectivity_pct": 1.15,
"r_rows": 111,
"r_lookups": 100,
"r_selectivity_pct": 2,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"r_loops": 1,
"rows": 55,
"r_rows": 2,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 1.149999976,
"r_filtered": 100,
"attached_condition": "t1.nm like '75%'"
}
}
]
}
}
select * from t1 where nm like '75%' AND fl2 = 0;
pk nm fl1 fl2
4543 7503 0 0
7373 7518 0 0
drop table name, flag2;
drop table t1;
create table t1 (
pk int primary key auto_increment,
nm char(255),
fl1 tinyint default 0,
fl2 int default 0,
index idx1(nm, fl1),
index idx2(fl2)
) engine=myisam;
create table name (
pk int primary key auto_increment,
nm bigint
) engine=myisam;
create table flag2 (
pk int primary key auto_increment,
fl2 int
) engine=myisam;
insert into name(nm) select seq from seq_1_to_10000 order by rand(17);
insert into flag2(fl2) select seq mod 10 from seq_1_to_10000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
pk nm fl1 fl2
analyze format=json select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "256",
"used_key_parts": ["nm"],
"rowid_filter": {
"range": {
"key": "idx2",
"used_key_parts": ["fl2"]
},
"rows": 863,
"selectivity_pct": 8.63,
"r_rows": 1000,
"r_lookups": 44,
"r_selectivity_pct": 0,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"r_loops": 1,
"rows": 44,
"r_rows": 0,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 8.630000114,
"r_filtered": 100,
"index_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
create table t0 select * from t1 where nm like '34%';
delete from t1 using t1,t0 where t1.nm=t0.nm;
analyze format=json select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "256",
"used_key_parts": ["nm"],
"rowid_filter": {
"range": {
"key": "idx2",
"used_key_parts": ["fl2"]
},
"rows": 853,
"selectivity_pct": 8.53,
"r_rows": 987,
"r_lookups": 0,
"r_selectivity_pct": 0,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"r_loops": 1,
"rows": 44,
"r_rows": 0,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 8.529999733,
"r_filtered": 100,
"index_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
drop table t0;
set optimizer_switch='rowid_filter=default';
drop table name, flag2;
drop table t1;
set @@use_stat_tables=@save_use_stat_tables;
#
# MDEV-21633
# Assertion `tmp >= 0' failed in best_access_path with rowid_filter=ON
#
set @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch='rowid_filter=on';
CREATE TABLE t1 (
pk INT AUTO_INCREMENT,
a INT,
b VARCHAR(8),
KEY(a),
PRIMARY KEY(pk),
KEY (a,pk)
) ENGINE=MyISAM;
INSERT INTO t1 (a,b) VALUES
(NULL,'d'),(9,'b'),(2,'x'),(5,'k'),(NULL,'d'),(3,'s'),(5,'k'),(1,'r'),
(8,'l'),(3,'z'),(1,'c'),(1,'q'),(NULL,'x'),(NULL,'p'),(NULL,'z'),(7,'a'),
(0,'i'),(3,'s'),(NULL,'h'),(4,'p'),(1,'i'),(4,'f'),(1,'c'),(NULL,'a'),
(NULL,'x'),(1,'b'),(NULL,'n'),(NULL,'h'),(5,'i'),(6,'e'),(NULL,'i'),
(7,'e'),(1,'r'),(NULL,'z'),(1,'i'),(14,'c'),(6,'u'),(3,'b'),(4,'z'),
(2,'c'),(70,'d'),(NULL,'p'),(21,'j'),(6,'e'),(5,'c'),(13,'i'),(42,'d'),
(80,'s'),(14,'t'),(9,'a'),(0,'2'),(0,NULL),(0,NULL),(0,NULL),(0,''),
(0,''),(0,'1'),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,''),(0,''),
(0,NULL),(0,''),(0,''),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,NULL),
(0,NULL),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,NULL),
(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,''),(0,''),(0,''),(0,''),
(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,'');
CREATE TABLE t2 (c INT) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
pk a b c
6 3 s 3
4 5 k 5
7 5 k 5
explain SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range|filter PRIMARY,a,a_2 PRIMARY|a 4|5 NULL 4 (11%) Using index condition; Using where; Using rowid filter
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join)
SET optimizer_switch='rowid_filter=off';
SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
pk a b c
6 3 s 3
4 5 k 5
7 5 k 5
SET @@optimizer_switch=@save_optimizer_switch;
DROP TABLE t1, t2;
SET GLOBAL innodb_stats_persistent=@save_stats_persistent; SET GLOBAL innodb_stats_persistent=@save_stats_persistent;
# #
# MDEV-18755: possible RORI-plan and possible plan with range filter # MDEV-18755: possible RORI-plan and possible plan with range filter

View File

@ -1,3 +1,4 @@
SET optimizer_switch='rowid_filter=on';
# #
# MDEV-22553: Assertion `info->lastpos == (~ (my_off_t) 0)' failed in mi_rkey with rowid_filer=on # MDEV-22553: Assertion `info->lastpos == (~ (my_off_t) 0)' failed in mi_rkey with rowid_filer=on
# #
@ -19,3 +20,675 @@ ALTER TABLE t1 ENABLE KEYS;
SELECT * FROM t1 WHERE ( a BETWEEN 255 AND 270 OR f = 200 ) AND f IN ( 1, 4, 112, 143 ) AND d IN ('Montana', 'South Dakota'); SELECT * FROM t1 WHERE ( a BETWEEN 255 AND 270 OR f = 200 ) AND f IN ( 1, 4, 112, 143 ) AND d IN ('Montana', 'South Dakota');
a b c d e f a b c d e f
DROP TABLE t1; DROP TABLE t1;
use test;
#
# MDEV-18816: potential range filter for one join table with
# impossible WHERE for another
#
create table t1 (
pk int not null primary key, c2 varchar(10) , i1 int,key (c2)
) engine=myisam;
insert into t1 values (1,'a',-5),(2,'a',null);
create table t2 (
pk int, i1 int, c1 varchar(30) , key c1 (c1(30)), key i1 (i1)
) engine=myisam;
insert into t2 values
(1,-5,'a'),(2,null,'a'),(3,null,'a'),(4,null,'a'),(5,5,'a'),(6,null,'a'),
(7,4,'a'),(8,55,'a'),(9,null,'a'),(10,null,'a'),(11,null,'a'),(12,-5,'a'),
(13,-5,'a'),(14,null,'a'),(15,null,'a'),(16,-5,'a'),(17,-5,'a');
select 1
from t1
left join
t2 join t1 as t1_a on t2.i1 = t1_a.pk
on t1.c2 = t2.c1
where t1_a.pk is null and t1_a.i1 != 3;
1
explain extended select 1
from t1
left join
t2 join t1 as t1_a on t2.i1 = t1_a.pk
on t1.c2 = t2.c1
where t1_a.pk is null and t1_a.i1 != 3;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
Note 1003 select 1 AS `1` from `test`.`t1` join `test`.`t2` join `test`.`t1` `t1_a` where 0
drop table t1,t2;
#
# MDEV-18640: TABLE::prune_range_rowid_filters: Conditional jump or
# move depends on uninitialized value
#
CREATE TABLE t1 (
pk INT, i INT, PRIMARY KEY (pk), KEY (pk,i)
) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,10), (7,70), (2,20);
SELECT * FROM t1 WHERE pk < 5;
pk i
1 10
2 20
DROP TABLE t1;
#
# MDEV-18956: Possible rowid filter for subquery for which
# in_to_exists strategy has been chosen
#
CREATE TABLE t1 (pk int) engine=myisam ;
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (
pk int auto_increment PRIMARY KEY,
i1 int, i2 int, c2 varchar(1),
KEY (i1), KEY (i2)
) engine=myisam;
INSERT INTO t2 VALUES
(1,8,6,'t'),(2,5,7,'i'),(3,4,4,'h'),(4,207,38,'d'),(5,183,206,'b'),
(6,7,null,'o'),(7,1,2,'j'),(8,17,36,'s'),(9,4,5,'q'),(10,0,6,'l'),
(11,1,9,'j'),(12,5,6,'y'),(13,null,0,'i'),(14,7,7,'x'),(15,5,2,'u');
SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3);
pk
EXPLAIN EXTENDED
SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible HAVING
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL no matching row in const table
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`pk` AS `pk` from `test`.`t1` having 0
DROP TABLE t1,t2;
#
# MDEV-19255: rowid range filter built for range condition
# that uses in expensive subquery
#
CREATE TABLE t1 (
pk1 INT PRIMARY KEY, a1 INT, b1 VARCHAR(1), KEY(b1)
) ENGINE=MyISAM;
INSERT INTO t1 VALUES
(10,0,'z'),(11,3,'j'),(12,8,'f'),(13,8,'p'),(14,6,'w'),(15,0,'c'),(16,1,'j'),
(17,1,'f'),(18,5,'v'),(19,3,'f'),(20,2,'q'),(21,8,'y'),(22,0,'a'),(23,9,'w'),
(24,3,'e'),(25,1,'b'),(26,9,'r'),(27,2,'k'),(28,5,'c'),(29,3,'k'),(30,9,'b'),
(31,8,'j'),(32,1,'t'),(33,8,'n'),(34,3,'z'),(35,0,'u'),(36,3,'a'),(37,3,'g'),
(38,1,'f'),(39,6,'p'),(40,6,'m'),(41,6,'t'),(42,7,'i'),(43,4,'h'),(44,3,'d'),
(45,2,'b'),(46,1,'o'),(47,2,'j'),(48,6,'s'),(49,5,'q'),(50,6,'l'),(51,9,'j'),
(52,6,'y'),(53,0,'i'),(54,7,'x'),(55,2,'u'),(56,6,'t'),(57,4,'b'),(58,5,'m'),
(59,4,'x'),(60,8,'x'),(61,6,'v'),(62,8,'m'),(63,4,'j'),(64,8,'z'),(65,2,'a'),
(66,9,'i'),(67,4,'g'),(68,8,'h'),(69,1,'p'),(70,8,'a'),(71,0,'x'),(72,2,'s'),
(73,6,'k'),(74,0,'m'),(75,6,'e'),(76,9,'y'),(77,7,'d'),(78,7,'w'),(79,6,'y'),
(80,9,'s'),(81,9,'x'),(82,6,'l'),(83,9,'f'),(84,8,'x'),(85,1,'p'),(86,7,'y'),
(87,6,'p'),(88,1,'g'),(89,3,'c'),(90,5,'h'),(91,3,'p'),(92,2,'b'),(93,1,NULL),
(94,3,NULL),(95,2,'y'),(96,7,'s'),(97,7,'x'),(98,6,'i'),(99,9,'t'),(100,5,'j'),
(101,0,'u'),(102,7,'r'),(103,2,'x'),(104,8,'e'),(105,8,'i'),(106,5,'q'),
(107,8,'z'),(108,3,'k'),(109,65,NULL);
CREATE TABLE t2 (pk2 INT PRIMARY KEY, a2 INT, b2 VARCHAR(1)) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1,1,'x');
INSERT INTO t2 SELECT * FROM t1;
SELECT * FROM t1 INNER JOIN t2 ON ( pk1 <> pk2 AND pk1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
pk1 a1 b1 pk2 a2 b2
65 2 a 109 65 NULL
EXPLAIN EXTENDED SELECT * FROM t1 INNER JOIN t2 ON ( pk1 <> pk2 AND pk1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 101 100.00 Using where
1 PRIMARY t1 eq_ref|filter PRIMARY,b1 PRIMARY|b1 4|4 test.t2.a2 1 (87%) 87.00 Using where; Using rowid filter
2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 100.00 Using index condition
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`pk1` AS `pk1`,`test`.`t1`.`a1` AS `a1`,`test`.`t1`.`b1` AS `b1`,`test`.`t2`.`pk2` AS `pk2`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`b2` AS `b2` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`pk1` = `test`.`t2`.`a2` and `test`.`t1`.`b1` <= (/* select#2 */ select max(`test`.`t2`.`b2`) from `test`.`t2` where `test`.`t2`.`pk2` <= 1) and `test`.`t2`.`a2` <> `test`.`t2`.`pk2`
EXPLAIN FORMAT=JSON SELECT * FROM t1 INNER JOIN t2 ON ( pk1 <> pk2 AND pk1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
EXPLAIN
{
"query_block": {
"select_id": 1,
"nested_loop": [
{
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 101,
"filtered": 100,
"attached_condition": "t2.a2 <> t2.pk2 and t2.a2 is not null"
}
},
{
"table": {
"table_name": "t1",
"access_type": "eq_ref",
"possible_keys": ["PRIMARY", "b1"],
"key": "PRIMARY",
"key_length": "4",
"used_key_parts": ["pk1"],
"ref": ["test.t2.a2"],
"rowid_filter": {
"range": {
"key": "b1",
"used_key_parts": ["b1"]
},
"rows": 87,
"selectivity_pct": 87
},
"rows": 1,
"filtered": 87,
"attached_condition": "t1.b1 <= (subquery#2)"
}
}
],
"subqueries": [
{
"query_block": {
"select_id": 2,
"nested_loop": [
{
"table": {
"table_name": "t2",
"access_type": "range",
"possible_keys": ["PRIMARY"],
"key": "PRIMARY",
"key_length": "4",
"used_key_parts": ["pk2"],
"rows": 1,
"filtered": 100,
"index_condition": "t2.pk2 <= 1"
}
}
]
}
}
]
}
}
DROP TABLE t1,t2;
#
# MDEV-21794: Optimizer flag rowid_filter leads to long query
#
create table t10(a int);
insert into t10 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t11(a int);
insert into t11 select A.a + B.a* 10 + C.a * 100 from t10 A, t10 B, t10 C;
CREATE TABLE t1 (
el_id int(10) unsigned NOT NULL ,
el_index blob NOT NULL,
el_index_60 varbinary(60) NOT NULL,
filler blob,
PRIMARY KEY (el_id),
KEY el_index (el_index(60)),
KEY el_index_60 (el_index_60,el_id)
);
insert into t1
select
A.a+1000*B.a,
A.a+1000*B.a + 10000,
A.a+1000*B.a + 10000,
'filler-data-filler-data'
from
t11 A, t10 B;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'el_index'
test.t1 analyze Warning Engine-independent statistics are not collected for column 'filler'
test.t1 analyze status Table is already up to date
# This must not use rowid_filter with key=el_index|el_index_60:
explain
select * from t1
where el_index like '10%' and (el_index_60 like '10%' or el_index_60 like '20%');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range el_index,el_index_60 el_index 62 NULL 645 Using where
drop table t10, t11, t1;
#
# MDEV-22160: SIGSEGV in st_join_table::save_explain_data on SELECT
#
set @save_optimizer_switch= @@optimizer_switch;
SET @@optimizer_switch="index_merge_sort_union=OFF";
CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b));
INSERT INTO t1 VALUES (0,0),(0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4),(3,3),(3,4),(3,5),(8,8),(8,9),(1,0),(2,0),(0,0),(0,0);
explain
SELECT * FROM t1 WHERE a > 0 AND b=0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref|filter a,b b|a 5|5 const 7 (47%) Using where; Using rowid filter
SELECT * FROM t1 WHERE a > 0 AND b=0;
a b
1 0
1 0
2 0
drop table t1;
SET @@optimizer_switch=@save_optimizer_switch;
#
# MDEV-21633
# Assertion `tmp >= 0' failed in best_access_path with rowid_filter=ON
#
set @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch='rowid_filter=on';
CREATE TABLE t1 (
pk INT AUTO_INCREMENT,
a INT,
b VARCHAR(8),
KEY(a),
PRIMARY KEY(pk),
KEY (a,pk)
) ENGINE=MyISAM;
INSERT INTO t1 (a,b) VALUES
(NULL,'d'),(9,'b'),(2,'x'),(5,'k'),(NULL,'d'),(3,'s'),(5,'k'),(1,'r'),
(8,'l'),(3,'z'),(1,'c'),(1,'q'),(NULL,'x'),(NULL,'p'),(NULL,'z'),(7,'a'),
(0,'i'),(3,'s'),(NULL,'h'),(4,'p'),(1,'i'),(4,'f'),(1,'c'),(NULL,'a'),
(NULL,'x'),(1,'b'),(NULL,'n'),(NULL,'h'),(5,'i'),(6,'e'),(NULL,'i'),
(7,'e'),(1,'r'),(NULL,'z'),(1,'i'),(14,'c'),(6,'u'),(3,'b'),(4,'z'),
(2,'c'),(70,'d'),(NULL,'p'),(21,'j'),(6,'e'),(5,'c'),(13,'i'),(42,'d'),
(80,'s'),(14,'t'),(9,'a'),(0,'2'),(0,NULL),(0,NULL),(0,NULL),(0,''),
(0,''),(0,'1'),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,''),(0,''),
(0,NULL),(0,''),(0,''),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,NULL),
(0,NULL),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,NULL),
(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,''),(0,''),(0,''),(0,''),
(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,'');
CREATE TABLE t2 (c INT) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
pk a b c
6 3 s 3
4 5 k 5
7 5 k 5
explain SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range|filter PRIMARY,a,a_2 PRIMARY|a 4|5 NULL 4 (11%) Using index condition; Using where; Using rowid filter
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join)
SET optimizer_switch='rowid_filter=off';
SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
pk a b c
6 3 s 3
4 5 k 5
7 5 k 5
SET @@optimizer_switch=@save_optimizer_switch;
DROP TABLE t1, t2;
#
# MDEV-28846: Poor performance when rowid filter contains no elements
#
create table t1 (
pk int primary key auto_increment,
nm varchar(32),
fl1 tinyint default 0,
fl2 tinyint default 0,
index idx1(nm, fl1),
index idx2(fl2)
) engine=myisam;
create table name (
pk int primary key auto_increment,
nm bigint
) engine=myisam;
create table flag2 (
pk int primary key auto_increment,
fl2 tinyint
) engine=myisam;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 2 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select '500%' as a;
a
500%
set optimizer_switch='rowid_filter=on';
explain
select * from t1 where nm like '500%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx1,idx2 idx1 35 NULL 1 Using index condition; Using where
analyze format=json
select * from t1 where nm like '500%' AND fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "35",
"used_key_parts": ["nm"],
"r_loops": 1,
"rows": 1,
"r_rows": 1,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 49.20000076,
"r_filtered": 100,
"index_condition": "t1.nm like '500%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
select * from t1 where nm like '500%' AND fl2 = 0;
pk nm fl1 fl2
517 500 0 0
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 2 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
set optimizer_switch='rowid_filter=off';
explain
select * from t1 where nm like '500%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx1,idx2 idx1 35 NULL 1 Using index condition; Using where
analyze format=json
select * from t1 where nm like '500%' AND fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "35",
"used_key_parts": ["nm"],
"r_loops": 1,
"rows": 1,
"r_rows": 1,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 49.20000076,
"r_filtered": 100,
"index_condition": "t1.nm like '500%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
select * from t1 where nm like '500%' AND fl2 = 0;
pk nm fl1 fl2
517 500 0 0
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 10 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select '607%' as a;
a
607%
set optimizer_switch='rowid_filter=on';
explain
select * from t1 where nm like '607%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx1,idx2 idx1 35 NULL 1 Using index condition; Using where
select * from t1 where nm like '607%' AND fl2 = 0;
pk nm fl1 fl2
721 607 0 0
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_10000 order by rand(17);
insert into flag2(fl2) select seq mod 100 from seq_1_to_10000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select '75%' as a;
a
75%
set optimizer_switch='rowid_filter=on';
explain
select * from t1 where nm like '75%' AND fl2 = 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref|filter idx1,idx2 idx2|idx1 2|35 const 55 (1%) Using where; Using rowid filter
analyze format=json
select * from t1 where nm like '75%' AND fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["idx1", "idx2"],
"key": "idx2",
"key_length": "2",
"used_key_parts": ["fl2"],
"ref": ["const"],
"rowid_filter": {
"range": {
"key": "idx1",
"used_key_parts": ["nm"]
},
"rows": 115,
"selectivity_pct": 1.15,
"r_rows": 111,
"r_lookups": 100,
"r_selectivity_pct": 2,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"r_loops": 1,
"rows": 55,
"r_rows": 2,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 1.149999976,
"r_filtered": 100,
"attached_condition": "t1.nm like '75%'"
}
}
]
}
}
select * from t1 where nm like '75%' AND fl2 = 0;
pk nm fl1 fl2
4543 7503 0 0
7373 7518 0 0
drop table name, flag2;
drop table t1;
create table t1 (
pk int primary key auto_increment,
nm char(255),
fl1 tinyint default 0,
fl2 int default 0,
index idx1(nm, fl1),
index idx2(fl2)
) engine=myisam;
create table name (
pk int primary key auto_increment,
nm bigint
) engine=myisam;
create table flag2 (
pk int primary key auto_increment,
fl2 int
) engine=myisam;
insert into name(nm) select seq from seq_1_to_10000 order by rand(17);
insert into flag2(fl2) select seq mod 10 from seq_1_to_10000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
pk nm fl1 fl2
analyze format=json select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "256",
"used_key_parts": ["nm"],
"rowid_filter": {
"range": {
"key": "idx2",
"used_key_parts": ["fl2"]
},
"rows": 863,
"selectivity_pct": 8.63,
"r_rows": 1000,
"r_lookups": 44,
"r_selectivity_pct": 0,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"r_loops": 1,
"rows": 44,
"r_rows": 0,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 8.630000114,
"r_filtered": 100,
"index_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
create table t0 select * from t1 where nm like '34%';
delete from t1 using t1,t0 where t1.nm=t0.nm;
analyze format=json select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
ANALYZE
{
"query_optimization": {
"r_total_time_ms": "REPLACED"
},
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "256",
"used_key_parts": ["nm"],
"rowid_filter": {
"range": {
"key": "idx2",
"used_key_parts": ["fl2"]
},
"rows": 853,
"selectivity_pct": 8.53,
"r_rows": 987,
"r_lookups": 0,
"r_selectivity_pct": 0,
"r_buffer_size": "REPLACED",
"r_filling_time_ms": "REPLACED"
},
"r_loops": 1,
"rows": 44,
"r_rows": 0,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"filtered": 8.529999733,
"r_filtered": 100,
"index_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'",
"attached_condition": "t1.fl2 = 0"
}
}
]
}
}
drop table t0;
set optimizer_switch='rowid_filter=default';
drop table name, flag2;
drop table t1;

View File

@ -1,3 +1,5 @@
SET optimizer_switch='rowid_filter=on';
--echo # --echo #
--echo # MDEV-22553: Assertion `info->lastpos == (~ (my_off_t) 0)' failed in mi_rkey with rowid_filer=on --echo # MDEV-22553: Assertion `info->lastpos == (~ (my_off_t) 0)' failed in mi_rkey with rowid_filer=on
--echo # --echo #
@ -1623,3 +1625,405 @@ ALTER TABLE t1 ENABLE KEYS;
--echo # Must not crash: --echo # Must not crash:
SELECT * FROM t1 WHERE ( a BETWEEN 255 AND 270 OR f = 200 ) AND f IN ( 1, 4, 112, 143 ) AND d IN ('Montana', 'South Dakota'); SELECT * FROM t1 WHERE ( a BETWEEN 255 AND 270 OR f = 200 ) AND f IN ( 1, 4, 112, 143 ) AND d IN ('Montana', 'South Dakota');
DROP TABLE t1; DROP TABLE t1;
use test;
--echo #
--echo # MDEV-18816: potential range filter for one join table with
--echo # impossible WHERE for another
--echo #
create table t1 (
pk int not null primary key, c2 varchar(10) , i1 int,key (c2)
) engine=myisam;
insert into t1 values (1,'a',-5),(2,'a',null);
create table t2 (
pk int, i1 int, c1 varchar(30) , key c1 (c1(30)), key i1 (i1)
) engine=myisam;
insert into t2 values
(1,-5,'a'),(2,null,'a'),(3,null,'a'),(4,null,'a'),(5,5,'a'),(6,null,'a'),
(7,4,'a'),(8,55,'a'),(9,null,'a'),(10,null,'a'),(11,null,'a'),(12,-5,'a'),
(13,-5,'a'),(14,null,'a'),(15,null,'a'),(16,-5,'a'),(17,-5,'a');
let $q=
select 1
from t1
left join
t2 join t1 as t1_a on t2.i1 = t1_a.pk
on t1.c2 = t2.c1
where t1_a.pk is null and t1_a.i1 != 3;
eval $q;
eval explain extended $q;
drop table t1,t2;
--echo #
--echo # MDEV-18640: TABLE::prune_range_rowid_filters: Conditional jump or
--echo # move depends on uninitialized value
--echo #
CREATE TABLE t1 (
pk INT, i INT, PRIMARY KEY (pk), KEY (pk,i)
) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,10), (7,70), (2,20);
SELECT * FROM t1 WHERE pk < 5;
DROP TABLE t1;
--echo #
--echo # MDEV-18956: Possible rowid filter for subquery for which
--echo # in_to_exists strategy has been chosen
--echo #
CREATE TABLE t1 (pk int) engine=myisam ;
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (
pk int auto_increment PRIMARY KEY,
i1 int, i2 int, c2 varchar(1),
KEY (i1), KEY (i2)
) engine=myisam;
INSERT INTO t2 VALUES
(1,8,6,'t'),(2,5,7,'i'),(3,4,4,'h'),(4,207,38,'d'),(5,183,206,'b'),
(6,7,null,'o'),(7,1,2,'j'),(8,17,36,'s'),(9,4,5,'q'),(10,0,6,'l'),
(11,1,9,'j'),(12,5,6,'y'),(13,null,0,'i'),(14,7,7,'x'),(15,5,2,'u');
SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3);
EXPLAIN EXTENDED
SELECT * FROM t1 HAVING (7, 9) IN (SELECT t2.i1, t2.i2 FROM t2 WHERE t2.i1 = 3);
DROP TABLE t1,t2;
--echo #
--echo # MDEV-19255: rowid range filter built for range condition
--echo # that uses in expensive subquery
--echo #
CREATE TABLE t1 (
pk1 INT PRIMARY KEY, a1 INT, b1 VARCHAR(1), KEY(b1)
) ENGINE=MyISAM;
INSERT INTO t1 VALUES
(10,0,'z'),(11,3,'j'),(12,8,'f'),(13,8,'p'),(14,6,'w'),(15,0,'c'),(16,1,'j'),
(17,1,'f'),(18,5,'v'),(19,3,'f'),(20,2,'q'),(21,8,'y'),(22,0,'a'),(23,9,'w'),
(24,3,'e'),(25,1,'b'),(26,9,'r'),(27,2,'k'),(28,5,'c'),(29,3,'k'),(30,9,'b'),
(31,8,'j'),(32,1,'t'),(33,8,'n'),(34,3,'z'),(35,0,'u'),(36,3,'a'),(37,3,'g'),
(38,1,'f'),(39,6,'p'),(40,6,'m'),(41,6,'t'),(42,7,'i'),(43,4,'h'),(44,3,'d'),
(45,2,'b'),(46,1,'o'),(47,2,'j'),(48,6,'s'),(49,5,'q'),(50,6,'l'),(51,9,'j'),
(52,6,'y'),(53,0,'i'),(54,7,'x'),(55,2,'u'),(56,6,'t'),(57,4,'b'),(58,5,'m'),
(59,4,'x'),(60,8,'x'),(61,6,'v'),(62,8,'m'),(63,4,'j'),(64,8,'z'),(65,2,'a'),
(66,9,'i'),(67,4,'g'),(68,8,'h'),(69,1,'p'),(70,8,'a'),(71,0,'x'),(72,2,'s'),
(73,6,'k'),(74,0,'m'),(75,6,'e'),(76,9,'y'),(77,7,'d'),(78,7,'w'),(79,6,'y'),
(80,9,'s'),(81,9,'x'),(82,6,'l'),(83,9,'f'),(84,8,'x'),(85,1,'p'),(86,7,'y'),
(87,6,'p'),(88,1,'g'),(89,3,'c'),(90,5,'h'),(91,3,'p'),(92,2,'b'),(93,1,NULL),
(94,3,NULL),(95,2,'y'),(96,7,'s'),(97,7,'x'),(98,6,'i'),(99,9,'t'),(100,5,'j'),
(101,0,'u'),(102,7,'r'),(103,2,'x'),(104,8,'e'),(105,8,'i'),(106,5,'q'),
(107,8,'z'),(108,3,'k'),(109,65,NULL);
CREATE TABLE t2 (pk2 INT PRIMARY KEY, a2 INT, b2 VARCHAR(1)) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1,1,'x');
INSERT INTO t2 SELECT * FROM t1;
let $q=
SELECT * FROM t1 INNER JOIN t2 ON ( pk1 <> pk2 AND pk1 = a2 )
WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 );
eval $q;
eval EXPLAIN EXTENDED $q;
eval EXPLAIN FORMAT=JSON $q;
DROP TABLE t1,t2;
--echo #
--echo # MDEV-21794: Optimizer flag rowid_filter leads to long query
--echo #
create table t10(a int);
insert into t10 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t11(a int);
insert into t11 select A.a + B.a* 10 + C.a * 100 from t10 A, t10 B, t10 C;
CREATE TABLE t1 (
el_id int(10) unsigned NOT NULL ,
el_index blob NOT NULL,
el_index_60 varbinary(60) NOT NULL,
filler blob,
PRIMARY KEY (el_id),
KEY el_index (el_index(60)),
KEY el_index_60 (el_index_60,el_id)
);
insert into t1
select
A.a+1000*B.a,
A.a+1000*B.a + 10000,
A.a+1000*B.a + 10000,
'filler-data-filler-data'
from
t11 A, t10 B;
analyze table t1 persistent for all;
--echo # This must not use rowid_filter with key=el_index|el_index_60:
explain
select * from t1
where el_index like '10%' and (el_index_60 like '10%' or el_index_60 like '20%');
drop table t10, t11, t1;
--echo #
--echo # MDEV-22160: SIGSEGV in st_join_table::save_explain_data on SELECT
--echo #
set @save_optimizer_switch= @@optimizer_switch;
SET @@optimizer_switch="index_merge_sort_union=OFF";
CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b));
INSERT INTO t1 VALUES (0,0),(0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4),(3,3),(3,4),(3,5),(8,8),(8,9),(1,0),(2,0),(0,0),(0,0);
explain
SELECT * FROM t1 WHERE a > 0 AND b=0;
SELECT * FROM t1 WHERE a > 0 AND b=0;
drop table t1;
SET @@optimizer_switch=@save_optimizer_switch;
--echo #
--echo # MDEV-21633
--echo # Assertion `tmp >= 0' failed in best_access_path with rowid_filter=ON
--echo #
set @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch='rowid_filter=on';
CREATE TABLE t1 (
pk INT AUTO_INCREMENT,
a INT,
b VARCHAR(8),
KEY(a),
PRIMARY KEY(pk),
KEY (a,pk)
) ENGINE=MyISAM;
INSERT INTO t1 (a,b) VALUES
(NULL,'d'),(9,'b'),(2,'x'),(5,'k'),(NULL,'d'),(3,'s'),(5,'k'),(1,'r'),
(8,'l'),(3,'z'),(1,'c'),(1,'q'),(NULL,'x'),(NULL,'p'),(NULL,'z'),(7,'a'),
(0,'i'),(3,'s'),(NULL,'h'),(4,'p'),(1,'i'),(4,'f'),(1,'c'),(NULL,'a'),
(NULL,'x'),(1,'b'),(NULL,'n'),(NULL,'h'),(5,'i'),(6,'e'),(NULL,'i'),
(7,'e'),(1,'r'),(NULL,'z'),(1,'i'),(14,'c'),(6,'u'),(3,'b'),(4,'z'),
(2,'c'),(70,'d'),(NULL,'p'),(21,'j'),(6,'e'),(5,'c'),(13,'i'),(42,'d'),
(80,'s'),(14,'t'),(9,'a'),(0,'2'),(0,NULL),(0,NULL),(0,NULL),(0,''),
(0,''),(0,'1'),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,''),(0,''),
(0,NULL),(0,''),(0,''),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,NULL),
(0,NULL),(0,''),(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,NULL),
(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,''),(0,''),(0,''),(0,''),
(0,''),(0,''),(0,''),(0,NULL),(0,''),(0,NULL),(0,'');
CREATE TABLE t2 (c INT) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
explain SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
SET optimizer_switch='rowid_filter=off';
SELECT * FROM t1 JOIN t2 WHERE a = c AND pk BETWEEN 4 AND 7 AND a BETWEEN 2 AND 12 AND b != 'foo';
SET @@optimizer_switch=@save_optimizer_switch;
# Cleanup
DROP TABLE t1, t2;
--echo #
--echo # MDEV-28846: Poor performance when rowid filter contains no elements
--echo #
--source include/have_sequence.inc
create table t1 (
pk int primary key auto_increment,
nm varchar(32),
fl1 tinyint default 0,
fl2 tinyint default 0,
index idx1(nm, fl1),
index idx2(fl2)
) engine=myisam;
create table name (
pk int primary key auto_increment,
nm bigint
) engine=myisam;
create table flag2 (
pk int primary key auto_increment,
fl2 tinyint
) engine=myisam;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 2 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
let $a=
`select concat((select nm from t1 where fl2=0 order by RAND(13) limit 1),'%')`;
eval select '$a' as a;
set optimizer_switch='rowid_filter=on';
eval
explain
select * from t1 where nm like '$a' AND fl2 = 0;
--source include/analyze-format.inc
eval
analyze format=json
select * from t1 where nm like '$a' AND fl2 = 0;
eval
select * from t1 where nm like '$a' AND fl2 = 0;
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 2 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
set optimizer_switch='rowid_filter=off';
eval
explain
select * from t1 where nm like '$a' AND fl2 = 0;
--source include/analyze-format.inc
eval
analyze format=json
select * from t1 where nm like '$a' AND fl2 = 0;
eval
select * from t1 where nm like '$a' AND fl2 = 0;
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_1000 order by rand(17);
insert into flag2(fl2) select seq mod 10 from seq_1_to_1000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
let $a=
`select concat((select nm from t1 where fl2=0 order by RAND(13) limit 1),'%')`;
eval select '$a' as a;
set optimizer_switch='rowid_filter=on';
eval
explain
select * from t1 where nm like '$a' AND fl2 = 0;
eval
select * from t1 where nm like '$a' AND fl2 = 0;
truncate table name;
truncate table flag2;
truncate table t1;
insert into name(nm) select seq from seq_1_to_10000 order by rand(17);
insert into flag2(fl2) select seq mod 100 from seq_1_to_10000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
let $a=
`select concat(left((select nm from t1 where fl2=0 order by RAND(13) limit 1),2),'%')`;
eval select '$a' as a;
set optimizer_switch='rowid_filter=on';
eval
explain
select * from t1 where nm like '$a' AND fl2 = 0;
--source include/analyze-format.inc
eval
analyze format=json
select * from t1 where nm like '$a' AND fl2 = 0;
eval
select * from t1 where nm like '$a' AND fl2 = 0;
drop table name, flag2;
drop table t1;
# This test shows that if the container is empty there are no lookups into it
create table t1 (
pk int primary key auto_increment,
nm char(255),
fl1 tinyint default 0,
fl2 int default 0,
index idx1(nm, fl1),
index idx2(fl2)
) engine=myisam;
create table name (
pk int primary key auto_increment,
nm bigint
) engine=myisam;
create table flag2 (
pk int primary key auto_increment,
fl2 int
) engine=myisam;
insert into name(nm) select seq from seq_1_to_10000 order by rand(17);
insert into flag2(fl2) select seq mod 10 from seq_1_to_10000 order by rand(19);
insert into t1(nm,fl2)
select nm, fl2 from name, flag2 where name.pk = flag2.pk;
analyze table t1 persistent for all;
let $q=
select * from t1
where
(
nm like '3400%' or nm like '3402%' or nm like '3403%' or
nm like '3404%' or nm like '3405%' or nm like '3406%' or nm like '3407%' or
nm like '3409%' or
nm like '3411%' or nm like '3412%' or nm like '3413%' or
nm like '3414%' or nm like '3415%' or nm like '3416%' or nm like '3417%' or
nm like '3418%' or nm like '3419%' or
nm like '3421%' or nm like '3422%' or nm like '3423%' or
nm like '3424%' or nm like '3425%' or nm like '3426%' or nm like '3427%' or
nm like '3428%' or nm like '3429%' or
nm like '3430%' or nm like '3431%' or nm like '3432%' or nm like '3433%' or
nm like '3434%' or nm like '3435%' or nm like '3436%' or nm like '3437%' or
nm like '3439%' or
nm like '3440%' or nm like '3441%' or nm like '3442%' or nm like '3443%' or
nm like '3444%' or nm like '3445%' or nm like '3446%' or nm like '3447%' or
nm like '3448%'
) and fl2 = 0;
eval $q;
--source include/analyze-format.inc
eval analyze format=json $q;
create table t0 select * from t1 where nm like '34%';
delete from t1 using t1,t0 where t1.nm=t0.nm;
--source include/analyze-format.inc
eval analyze format=json $q;
drop table t0;
set optimizer_switch='rowid_filter=default';
drop table name, flag2;
drop table t1;

View File

@ -409,7 +409,7 @@ WHERE (pk BETWEEN 4 AND 5 OR pk < 2) AND c1 < 240
ORDER BY c1 ORDER BY c1
LIMIT 1; LIMIT 1;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY,k1 k1 5 NULL 4 Using index condition; Using where 1 SIMPLE t1 range|filter PRIMARY,k1 k1|PRIMARY 5|4 NULL 4 (38%) Using index condition; Using where; Using rowid filter
DROP TABLE t1; DROP TABLE t1;
# #
# #

View File

@ -92,7 +92,7 @@ my_bool init_dynamic_array2(PSI_memory_key psi_key, DYNAMIC_ARRAY *array,
my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void * element) my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void * element)
{ {
void *buffer; void *buffer;
if (array->elements == array->max_element) if (unlikely(array->elements == array->max_element))
{ /* Call only when necessary */ { /* Call only when necessary */
if (!(buffer=alloc_dynamic(array))) if (!(buffer=alloc_dynamic(array)))
return TRUE; return TRUE;
@ -102,7 +102,42 @@ my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void * element)
buffer=array->buffer+(array->elements * array->size_of_element); buffer=array->buffer+(array->elements * array->size_of_element);
array->elements++; array->elements++;
} }
memcpy(buffer,element,(size_t) array->size_of_element); memcpy(buffer, element, array->size_of_element);
return FALSE;
}
/* Fast version of appending to dynamic array */
void init_append_dynamic(DYNAMIC_ARRAY_APPEND *append,
DYNAMIC_ARRAY *array)
{
append->array= array;
append->pos= array->buffer + array->elements * array->size_of_element;
append->end= array->buffer + array->max_element * array->size_of_element;
}
my_bool append_dynamic(DYNAMIC_ARRAY_APPEND *append,
const void *element)
{
DYNAMIC_ARRAY *array= append->array;
size_t size_of_element= array->size_of_element;
if (unlikely(append->pos == append->end))
{
void *buffer;
if (!(buffer=alloc_dynamic(array)))
return TRUE;
append->pos= (uchar*)buffer + size_of_element;
append->end= array->buffer + array->max_element * size_of_element;
memcpy(buffer, element, size_of_element);
}
else
{
array->elements++;
memcpy(append->pos, element, size_of_element);
append->pos+= size_of_element;
}
return FALSE; return FALSE;
} }
@ -281,7 +316,7 @@ my_bool allocate_dynamic(DYNAMIC_ARRAY *array, size_t max_elements)
void get_dynamic(DYNAMIC_ARRAY *array, void *element, size_t idx) void get_dynamic(DYNAMIC_ARRAY *array, void *element, size_t idx)
{ {
if (idx >= array->elements) if (unlikely(idx >= array->elements))
{ {
DBUG_PRINT("warning",("To big array idx: %d, array size is %d", DBUG_PRINT("warning",("To big array idx: %d, array size is %d",
idx,array->elements)); idx,array->elements));
@ -306,7 +341,7 @@ void delete_dynamic(DYNAMIC_ARRAY *array)
/* /*
Just mark as empty if we are using a static buffer Just mark as empty if we are using a static buffer
*/ */
if (!(array->malloc_flags & MY_INIT_BUFFER_USED) && array->buffer) if (array->buffer && !(array->malloc_flags & MY_INIT_BUFFER_USED))
my_free(array->buffer); my_free(array->buffer);
array->buffer= 0; array->buffer= 0;

View File

@ -6964,8 +6964,7 @@ check_result_t handler_rowid_filter_check(void *h_arg)
extern "C" int handler_rowid_filter_is_active(void *h_arg) extern "C" int handler_rowid_filter_is_active(void *h_arg)
{ {
if (!h_arg) DBUG_ASSERT(h_arg);
return false;
handler *h= (handler*) h_arg; handler *h= (handler*) h_arg;
return h->rowid_filter_is_active; return h->rowid_filter_is_active;
} }

View File

@ -4665,10 +4665,14 @@ public:
DBUG_ASSERT(pushed_rowid_filter != NULL && DBUG_ASSERT(pushed_rowid_filter != NULL &&
save_pushed_rowid_filter == NULL); save_pushed_rowid_filter == NULL);
save_pushed_rowid_filter= pushed_rowid_filter; save_pushed_rowid_filter= pushed_rowid_filter;
if (rowid_filter_is_active) save_rowid_filter_is_active= rowid_filter_is_active;
save_rowid_filter_is_active= rowid_filter_is_active;
pushed_rowid_filter= NULL; pushed_rowid_filter= NULL;
rowid_filter_is_active= false;
if (rowid_filter_is_active)
{
rowid_filter_is_active= false;
rowid_filter_changed();
}
} }
virtual void enable_pushed_rowid_filter() virtual void enable_pushed_rowid_filter()
@ -4676,12 +4680,17 @@ public:
DBUG_ASSERT(save_pushed_rowid_filter != NULL && DBUG_ASSERT(save_pushed_rowid_filter != NULL &&
pushed_rowid_filter == NULL); pushed_rowid_filter == NULL);
pushed_rowid_filter= save_pushed_rowid_filter; pushed_rowid_filter= save_pushed_rowid_filter;
if (save_rowid_filter_is_active)
rowid_filter_is_active= true;
save_pushed_rowid_filter= NULL; save_pushed_rowid_filter= NULL;
if (save_rowid_filter_is_active)
{
rowid_filter_is_active= true;
rowid_filter_changed();
}
} }
virtual bool rowid_filter_push(Rowid_filter *rowid_filter) { return true; } virtual bool rowid_filter_push(Rowid_filter *rowid_filter) { return true; }
/* Signal that rowid filter may have been enabled / disabled */
virtual void rowid_filter_changed() {}
/* Needed for partition / spider */ /* Needed for partition / spider */
virtual TABLE_LIST *get_next_global_for_child() { return NULL; } virtual TABLE_LIST *get_next_global_for_child() { return NULL; }

View File

@ -86,6 +86,13 @@
/* Rowid copy is usually just a single memcpy of a short string */ /* Rowid copy is usually just a single memcpy of a short string */
#define DEFAULT_ROWID_COPY_COST 0.000002653 #define DEFAULT_ROWID_COPY_COST 0.000002653
/*
Cost modifiers rowid_filter. These takes into account the overhead of
using and calling Rowid_filter_sorted_array::check() from the engine
*/
#define ROWID_FILTER_PER_CHECK_MODIFIER 4 /* times key_copy_cost */
#define ROWID_FILTER_PER_ELEMENT_MODIFIER 3 /* times rowid_compare_cost */
/* /*
Average disk seek time on a hard disk is 8-10 ms, which is also Average disk seek time on a hard disk is 8-10 ms, which is also
about the time to read a IO_SIZE (8192) block. about the time to read a IO_SIZE (8192) block.

View File

@ -19,6 +19,7 @@
#include "sql_class.h" #include "sql_class.h"
#include "opt_range.h" #include "opt_range.h"
#include "rowid_filter.h" #include "rowid_filter.h"
#include "optimizer_defaults.h"
#include "sql_select.h" #include "sql_select.h"
#include "opt_trace.h" #include "opt_trace.h"
@ -127,8 +128,10 @@ void Range_rowid_filter_cost_info::init(Rowid_filter_container_type cont_type,
cost_of_building_range_filter= build_cost(container_type); cost_of_building_range_filter= build_cost(container_type);
where_cost= tab->in_use->variables.optimizer_where_cost; where_cost= tab->in_use->variables.optimizer_where_cost;
base_lookup_cost= tab->file->ROW_NEXT_FIND_COST; base_lookup_cost= (ROWID_FILTER_PER_CHECK_MODIFIER *
rowid_compare_cost= tab->file->ROWID_COMPARE_COST; tab->file->KEY_COPY_COST);
rowid_compare_cost= (ROWID_FILTER_PER_ELEMENT_MODIFIER *
tab->file->ROWID_COMPARE_COST);
selectivity= est_elements/((double) table->stat_records()); selectivity= est_elements/((double) table->stat_records());
gain= avg_access_and_eval_gain_per_row(container_type, gain= avg_access_and_eval_gain_per_row(container_type,
tab->file->ROW_LOOKUP_COST); tab->file->ROW_LOOKUP_COST);
@ -589,41 +592,40 @@ bool Range_rowid_filter::fill()
file->pushed_idx_cond_keyno= MAX_KEY; file->pushed_idx_cond_keyno= MAX_KEY;
file->in_range_check_pushed_down= false; file->in_range_check_pushed_down= false;
/* We're going to just read rowids / primary keys */ /* We're going to just read rowids / clustered primary keys */
table->prepare_for_position(); table->prepare_for_position();
table->file->ha_start_keyread(quick->index); file->ha_start_keyread(quick->index);
if (quick->init() || quick->reset()) if (quick->init() || quick->reset())
rc= 1; goto end;
while (!rc) while (!(rc= quick->get_next()))
{ {
rc= quick->get_next(); file->position(quick->record);
if (thd->killed) if (container->add(NULL, (char*) file->ref) || thd->killed)
rc= 1;
if (!rc)
{ {
file->position(quick->record); rc= 1;
if (container->add(NULL, (char*) file->ref)) break;
rc= 1;
else
tracker->increment_container_elements_count();
} }
} }
end:
quick->range_end(); quick->range_end();
table->file->ha_end_keyread(); file->ha_end_keyread();
table->status= table_status_save; table->status= table_status_save;
file->pushed_idx_cond= pushed_idx_cond_save; file->pushed_idx_cond= pushed_idx_cond_save;
file->pushed_idx_cond_keyno= pushed_idx_cond_keyno_save; file->pushed_idx_cond_keyno= pushed_idx_cond_keyno_save;
file->in_range_check_pushed_down= in_range_check_pushed_down_save; file->in_range_check_pushed_down= in_range_check_pushed_down_save;
tracker->report_container_buff_size(table->file->ref_length);
tracker->set_container_elements_count(container->elements());
tracker->report_container_buff_size(file->ref_length);
if (rc != HA_ERR_END_OF_FILE) if (rc != HA_ERR_END_OF_FILE)
return 1; return 1;
table->file->rowid_filter_is_active= true; container->sort(refpos_order_cmp, (void *) file);
file->rowid_filter_is_active= container->elements() != 0;
return 0; return 0;
} }
@ -647,18 +649,13 @@ bool Range_rowid_filter::fill()
bool Rowid_filter_sorted_array::check(void *ctxt, char *elem) bool Rowid_filter_sorted_array::check(void *ctxt, char *elem)
{ {
TABLE *table= (TABLE *) ctxt; handler *file= ((TABLE *) ctxt)->file;
if (!is_checked)
{
refpos_container.sort(refpos_order_cmp, (void *) (table->file));
is_checked= true;
}
int l= 0; int l= 0;
int r= refpos_container.elements()-1; int r= refpos_container.elements()-1;
while (l <= r) while (l <= r)
{ {
int m= (l + r) / 2; int m= (l + r) / 2;
int cmp= refpos_order_cmp((void *) (table->file), int cmp= refpos_order_cmp((void *) file,
refpos_container.get_pos(m), elem); refpos_container.get_pos(m), elem);
if (cmp == 0) if (cmp == 0)
return true; return true;
@ -675,14 +672,6 @@ Range_rowid_filter::~Range_rowid_filter()
{ {
delete container; delete container;
container= 0; container= 0;
if (select) delete select;
{ select= 0;
if (select->quick)
{
delete select->quick;
select->quick= 0;
}
delete select;
select= 0;
}
} }

View File

@ -186,7 +186,10 @@ public:
virtual bool check(void *ctxt, char *elem) = 0; virtual bool check(void *ctxt, char *elem) = 0;
/* True if the container does not contain any element */ /* True if the container does not contain any element */
virtual bool is_empty() = 0; bool is_empty() { return elements() == 0; }
virtual uint elements() = 0;
virtual void sort (int (*cmp) (void *ctxt, const void *el1, const void *el2),
void *cmp_arg) = 0;
virtual ~Rowid_filter_container() {} virtual ~Rowid_filter_container() {}
}; };
@ -264,7 +267,7 @@ public:
bool build() { return fill(); } bool build() { return fill(); }
bool check(char *elem) bool check(char *elem) override
{ {
if (container->is_empty()) if (container->is_empty())
return false; return false;
@ -296,52 +299,49 @@ class Refpos_container_sorted_array : public Sql_alloc
/* Number of bytes allocated for an element */ /* Number of bytes allocated for an element */
uint elem_size; uint elem_size;
/* The dynamic array over which the wrapper is built */ /* The dynamic array over which the wrapper is built */
Dynamic_array<char> *array; DYNAMIC_ARRAY array;
DYNAMIC_ARRAY_APPEND append;
public: public:
Refpos_container_sorted_array(uint max_elems, uint elem_sz) Refpos_container_sorted_array(uint max_elems, uint elem_sz)
: max_elements(max_elems), elem_size(elem_sz), array(0) {} :max_elements(max_elems), elem_size(elem_sz)
{
bzero(&array, sizeof(array));
}
~Refpos_container_sorted_array() ~Refpos_container_sorted_array()
{ {
delete array; delete_dynamic(&array);
array= 0;
} }
bool alloc() bool alloc()
{ {
array= new Dynamic_array<char> (PSI_INSTRUMENT_MEM, /* This can never fail as things will be allocated on demand */
elem_size * max_elements, init_dynamic_array2(PSI_INSTRUMENT_MEM, &array, elem_size, 0,
elem_size * max_elements/sizeof(char) + 1); max_elements, 512, MYF(0));
return array == NULL; init_append_dynamic(&append, &array);
return 0;
} }
bool add(char *elem) bool add(const char *elem)
{ {
for (uint i= 0; i < elem_size; i++) return append_dynamic(&append, elem);
{
if (array->append(elem[i]))
return true;
}
return false;
} }
char *get_pos(uint n) inline uchar *get_pos(uint n) const
{ {
return array->get_pos(n * elem_size); return dynamic_array_ptr(&array, n);
} }
uint elements() { return (uint) (array->elements() / elem_size); } inline uint elements() const { return (uint) array.elements; }
void sort (int (*cmp) (void *ctxt, const void *el1, const void *el2), void sort (int (*cmp) (void *ctxt, const void *el1, const void *el2),
void *cmp_arg) void *cmp_arg)
{ {
my_qsort2(array->front(), array->elements()/elem_size, my_qsort2(array.buffer, array.elements,
elem_size, (qsort2_cmp) cmp, cmp_arg); elem_size, (qsort2_cmp) cmp, cmp_arg);
} }
bool is_empty() { return elements() == 0; }
}; };
@ -356,23 +356,29 @@ class Rowid_filter_sorted_array: public Rowid_filter_container
{ {
/* The dynamic array to store rowids / primary keys */ /* The dynamic array to store rowids / primary keys */
Refpos_container_sorted_array refpos_container; Refpos_container_sorted_array refpos_container;
/* Initially false, becomes true after the first call of (check() */
bool is_checked;
public: public:
Rowid_filter_sorted_array(uint elems, uint elem_size) Rowid_filter_sorted_array(uint elems, uint elem_size)
: refpos_container(elems, elem_size), is_checked(false) {} : refpos_container(elems, elem_size) {}
Rowid_filter_container_type get_type() Rowid_filter_container_type get_type() override
{ return SORTED_ARRAY_CONTAINER; } { return SORTED_ARRAY_CONTAINER; }
bool alloc() { return refpos_container.alloc(); } bool alloc() override { return refpos_container.alloc(); }
bool add(void *ctxt, char *elem) { return refpos_container.add(elem); } bool add(void *ctxt, char *elem) override
{ return refpos_container.add(elem); }
bool check(void *ctxt, char *elem); bool check(void *ctxt, char *elem) override;
uint elements() override { return refpos_container.elements(); }
void sort (int (*cmp) (void *ctxt, const void *el1, const void *el2),
void *cmp_arg)
{
return refpos_container.sort(cmp, cmp_arg);
}
bool is_empty() { return refpos_container.is_empty(); }
}; };
/** /**

View File

@ -414,7 +414,8 @@ public:
n_positive_checks++; n_positive_checks++;
} }
inline void increment_container_elements_count() { container_elements++; } inline void set_container_elements_count(uint elements)
{ container_elements= elements; }
uint get_container_elements() const { return container_elements; } uint get_container_elements() const { return container_elements; }

View File

@ -170,10 +170,9 @@ static double get_merge_buffers_cost(THD *thd, uint *buff_elems, uint elem_size,
size_t n_buffers= last - first + 1; size_t n_buffers= last - first + 1;
/* Using log2(n)=log(n)/log(2) formula */
return (2*((double)total_buf_elems*elem_size) / IO_SIZE * return (2*((double)total_buf_elems*elem_size) / IO_SIZE *
default_optimizer_costs.disk_read_cost + default_optimizer_costs.disk_read_cost +
total_buf_elems*log((double) n_buffers) * compare_factor / M_LN2); total_buf_elems*log2((double) n_buffers) * compare_factor);
} }

View File

@ -4040,7 +4040,8 @@ row_search_idx_cond_check(
ut_ad(rec_offs_validate(rec, prebuilt->index, offsets)); ut_ad(rec_offs_validate(rec, prebuilt->index, offsets));
if (!prebuilt->idx_cond) { if (!prebuilt->idx_cond) {
if (!handler_rowid_filter_is_active(prebuilt->pk_filter)) { if (!prebuilt->pk_filter ||
!handler_rowid_filter_is_active(prebuilt->pk_filter)) {
return(CHECK_POS); return(CHECK_POS);
} }
} else { } else {
@ -4082,7 +4083,8 @@ row_search_idx_cond_check(
switch (result) { switch (result) {
case CHECK_POS: case CHECK_POS:
if (handler_rowid_filter_is_active(prebuilt->pk_filter)) { if (prebuilt->pk_filter &&
handler_rowid_filter_is_active(prebuilt->pk_filter)) {
ut_ad(!prebuilt->index->is_primary()); ut_ad(!prebuilt->index->is_primary());
if (prebuilt->clust_index_was_generated) { if (prebuilt->clust_index_was_generated) {
ulint len; ulint len;

View File

@ -1094,8 +1094,9 @@ ulong ha_maria::index_flags(uint inx, uint part, bool all_parts) const
} }
else else
{ {
flags= HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | flags= (HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
HA_READ_ORDER | HA_KEYREAD_ONLY | HA_DO_INDEX_COND_PUSHDOWN; HA_READ_ORDER | HA_KEYREAD_ONLY | HA_DO_INDEX_COND_PUSHDOWN |
HA_DO_RANGE_FILTER_PUSHDOWN);
} }
return flags; return flags;
} }
@ -2535,10 +2536,12 @@ int ha_maria::index_read_idx_map(uchar * buf, uint index, const uchar * key,
end_range= NULL; end_range= NULL;
if (index == pushed_idx_cond_keyno) if (index == pushed_idx_cond_keyno)
ma_set_index_cond_func(file, handler_index_cond_check, this); ma_set_index_cond_func(file, handler_index_cond_check, this);
if (pushed_rowid_filter && handler_rowid_filter_is_active(this))
ma_set_rowid_filter_func(file, handler_rowid_filter_check, this);
error= maria_rkey(file, buf, index, key, keypart_map, find_flag); error= maria_rkey(file, buf, index, key, keypart_map, find_flag);
ma_set_index_cond_func(file, NULL, 0); ma_reset_index_filter_functions(file);
return error; return error;
} }
@ -2612,18 +2615,22 @@ int ha_maria::index_next_same(uchar * buf,
int ha_maria::index_init(uint idx, bool sorted) int ha_maria::index_init(uint idx, bool sorted)
{ {
active_index=idx; active_index= idx;
if (pushed_idx_cond_keyno == idx) if (pushed_idx_cond_keyno == idx)
ma_set_index_cond_func(file, handler_index_cond_check, this); ma_set_index_cond_func(file, handler_index_cond_check, this);
if (pushed_rowid_filter && handler_rowid_filter_is_active(this))
ma_set_rowid_filter_func(file, handler_rowid_filter_check, this);
return 0; return 0;
} }
int ha_maria::index_end() int ha_maria::index_end()
{ {
/*
in_range_check_pushed_down and index_id_cond_keyno are reset in
handler::cancel_pushed_idx_cond()
*/
active_index=MAX_KEY; active_index=MAX_KEY;
ma_set_index_cond_func(file, NULL, 0); ma_reset_index_filter_functions(file);
in_range_check_pushed_down= FALSE;
ds_mrr.dsmrr_close(); ds_mrr.dsmrr_close();
return 0; return 0;
} }
@ -2811,7 +2818,7 @@ int ha_maria::extra(enum ha_extra_function operation)
int ha_maria::reset(void) int ha_maria::reset(void)
{ {
ma_set_index_cond_func(file, NULL, 0); ma_reset_index_filter_functions(file);
ds_mrr.dsmrr_close(); ds_mrr.dsmrr_close();
if (file->trn) if (file->trn)
{ {
@ -3871,8 +3878,6 @@ bool ha_maria::is_changed() const
static void aria_update_optimizer_costs(OPTIMIZER_COSTS *costs) static void aria_update_optimizer_costs(OPTIMIZER_COSTS *costs)
{ {
costs->rowid_copy_cost= 0.000001; // Just a short memcopy
costs->rowid_cmp_cost= 0.000001; // Just a short memcmp
} }
@ -4269,6 +4274,26 @@ Item *ha_maria::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
return NULL; return NULL;
} }
bool ha_maria::rowid_filter_push(Rowid_filter* rowid_filter)
{
/* This will be used in index_init() */
pushed_rowid_filter= rowid_filter;
return false;
}
/* Enable / disable rowid filter depending if it's active or not */
void ha_maria::rowid_filter_changed()
{
if (pushed_rowid_filter && handler_rowid_filter_is_active(this))
ma_set_rowid_filter_func(file, handler_rowid_filter_check, this);
else
ma_set_rowid_filter_func(file, NULL, this);
}
/** /**
Find record by unique constrain (used in temporary tables) Find record by unique constrain (used in temporary tables)

View File

@ -184,6 +184,8 @@ public:
/* Index condition pushdown implementation */ /* Index condition pushdown implementation */
Item *idx_cond_push(uint keyno, Item* idx_cond) override final; Item *idx_cond_push(uint keyno, Item* idx_cond) override final;
bool rowid_filter_push(Rowid_filter* rowid_filter) override;
void rowid_filter_changed() override;
int find_unique_row(uchar *record, uint unique_idx) override final; int find_unique_row(uchar *record, uint unique_idx) override final;

View File

@ -510,8 +510,17 @@ void ma_set_index_cond_func(MARIA_HA *info, index_cond_func_t func,
{ {
info->index_cond_func= func; info->index_cond_func= func;
info->index_cond_func_arg= func_arg; info->index_cond_func_arg= func_arg;
info->has_cond_pushdown= (info->index_cond_func || info->rowid_filter_func);
} }
void ma_set_rowid_filter_func(MARIA_HA *info,
rowid_filter_func_t check_func,
void *func_arg)
{
info->rowid_filter_func= check_func;
info->rowid_filter_func_arg= func_arg;
info->has_cond_pushdown= (info->index_cond_func || info->rowid_filter_func);
}
/* /*
Start/Stop Inserting Duplicates Into a Table, WL#1648. Start/Stop Inserting Duplicates Into a Table, WL#1648.

View File

@ -20,14 +20,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
/* Get position to last record */
MARIA_RECORD_POS maria_position(MARIA_HA *info)
{
return info->cur_row.lastpos;
}
uint maria_max_key_length() uint maria_max_key_length()
{ {
uint tmp= (_ma_max_key_length() - 8 - HA_MAX_KEY_SEG*3); uint tmp= (_ma_max_key_length() - 8 - HA_MAX_KEY_SEG*3);

View File

@ -678,22 +678,44 @@ int _ma_read_key_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos)
CHECK_OUT_OF_RANGE to indicate that we don't have any active row. CHECK_OUT_OF_RANGE to indicate that we don't have any active row.
*/ */
check_result_t ma_check_index_cond(register MARIA_HA *info, uint keynr, check_result_t ma_check_index_cond_real(register MARIA_HA *info, uint keynr,
uchar *record) uchar *record)
{ {
check_result_t res= CHECK_POS; check_result_t res= CHECK_POS;
DBUG_ASSERT(info->index_cond_func || info->rowid_filter_func);
if (_ma_put_key_in_record(info, keynr, FALSE, record))
{
/* Impossible case; Can only happen if bug in code */
_ma_print_error(info, HA_ERR_CRASHED, 0);
info->cur_row.lastpos= HA_OFFSET_ERROR; /* No active record */
my_errno= HA_ERR_CRASHED;
return CHECK_ERROR;
}
if (info->index_cond_func) if (info->index_cond_func)
{ {
if (_ma_put_key_in_record(info, keynr, FALSE, record)) if ((res= info->index_cond_func(info->index_cond_func_arg)) ==
CHECK_OUT_OF_RANGE)
{ {
/* Impossible case; Can only happen if bug in code */ /* We got beyond the end of scanned range */
_ma_print_error(info, HA_ERR_CRASHED, 0);
info->cur_row.lastpos= HA_OFFSET_ERROR; /* No active record */ info->cur_row.lastpos= HA_OFFSET_ERROR; /* No active record */
my_errno= HA_ERR_CRASHED; my_errno= HA_ERR_END_OF_FILE;
res= CHECK_ERROR; return res;
} }
else if ((res= info->index_cond_func(info->index_cond_func_arg)) == /*
CHECK_OUT_OF_RANGE) If we got an error, out-of-range condition, or ICP condition computed to
FALSE - we don't need to check the Rowid Filter.
*/
if (res != CHECK_POS)
return res;
}
/* Check the Rowid Filter, if present */
if (info->rowid_filter_func)
{
if ((res= info->rowid_filter_func(info->rowid_filter_func_arg)) ==
CHECK_OUT_OF_RANGE)
{ {
/* We got beyond the end of scanned range */ /* We got beyond the end of scanned range */
info->cur_row.lastpos= HA_OFFSET_ERROR; /* No active record */ info->cur_row.lastpos= HA_OFFSET_ERROR; /* No active record */

View File

@ -120,6 +120,7 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key_data,
/* The key references a concurrently inserted record. */ /* The key references a concurrently inserted record. */
if (search_flag == HA_READ_KEY_EXACT && if (search_flag == HA_READ_KEY_EXACT &&
(keyinfo->flag & HA_NOSAME) &&
last_used_keyseg == keyinfo->seg + keyinfo->keysegs) last_used_keyseg == keyinfo->seg + keyinfo->keysegs)
{ {
/* Simply ignore the key if it matches exactly. (Bug #29838) */ /* Simply ignore the key if it matches exactly. (Bug #29838) */

View File

@ -213,7 +213,6 @@ extern int maria_rsame_with_pos(MARIA_HA *file, uchar *record,
extern int maria_update(MARIA_HA *file, const uchar *old, extern int maria_update(MARIA_HA *file, const uchar *old,
const uchar *new_record); const uchar *new_record);
extern int maria_write(MARIA_HA *file, const uchar *buff); extern int maria_write(MARIA_HA *file, const uchar *buff);
extern MARIA_RECORD_POS maria_position(MARIA_HA *file);
extern int maria_status(MARIA_HA *info, MARIA_INFO *x, uint flag); extern int maria_status(MARIA_HA *info, MARIA_INFO *x, uint flag);
extern int maria_lock_database(MARIA_HA *file, int lock_type); extern int maria_lock_database(MARIA_HA *file, int lock_type);
extern int maria_delete_table(const char *name); extern int maria_delete_table(const char *name);
@ -1011,6 +1010,7 @@ struct st_maria_handler
my_bool switched_transactional; my_bool switched_transactional;
/* If transaction will autocommit */ /* If transaction will autocommit */
my_bool autocommit; my_bool autocommit;
my_bool has_cond_pushdown;
#ifdef _WIN32 #ifdef _WIN32
my_bool owned_by_merge; /* This Maria table is part of a merge union */ my_bool owned_by_merge; /* This Maria table is part of a merge union */
#endif #endif
@ -1022,6 +1022,8 @@ struct st_maria_handler
my_bool create_unique_index_by_sort; my_bool create_unique_index_by_sort;
index_cond_func_t index_cond_func; /* Index condition function */ index_cond_func_t index_cond_func; /* Index condition function */
void *index_cond_func_arg; /* parameter for the func */ void *index_cond_func_arg; /* parameter for the func */
rowid_filter_func_t rowid_filter_func; /* rowid filter check function */
void *rowid_filter_func_arg; /* parameter for the func */
}; };
/* Table options for the Aria and S3 storage engine */ /* Table options for the Aria and S3 storage engine */
@ -1347,7 +1349,11 @@ extern int _ma_read_rnd_no_record(MARIA_HA *info, uchar *buf,
MARIA_RECORD_POS filepos, MARIA_RECORD_POS filepos,
my_bool skip_deleted_blocks); my_bool skip_deleted_blocks);
my_off_t _ma_no_keypos_to_recpos(MARIA_SHARE *share, my_off_t pos); my_off_t _ma_no_keypos_to_recpos(MARIA_SHARE *share, my_off_t pos);
/* Get position to last record */
static inline MARIA_RECORD_POS maria_position(MARIA_HA *info)
{
return info->cur_row.lastpos;
}
extern my_bool _ma_ck_write(MARIA_HA *info, MARIA_KEY *key); extern my_bool _ma_ck_write(MARIA_HA *info, MARIA_KEY *key);
extern my_bool _ma_enlarge_root(MARIA_HA *info, MARIA_KEY *key, extern my_bool _ma_enlarge_root(MARIA_HA *info, MARIA_KEY *key,
MARIA_RECORD_POS *root); MARIA_RECORD_POS *root);
@ -1734,7 +1740,25 @@ extern my_bool maria_flush_log_for_page_none(PAGECACHE_IO_HOOK_ARGS *args);
extern PAGECACHE *maria_log_pagecache; extern PAGECACHE *maria_log_pagecache;
extern void ma_set_index_cond_func(MARIA_HA *info, index_cond_func_t func, extern void ma_set_index_cond_func(MARIA_HA *info, index_cond_func_t func,
void *func_arg); void *func_arg);
check_result_t ma_check_index_cond(MARIA_HA *info, uint keynr, uchar *record); extern void ma_set_rowid_filter_func(MARIA_HA *info,
rowid_filter_func_t check_func,
void *func_arg);
static inline void ma_reset_index_filter_functions(MARIA_HA *info)
{
info->index_cond_func= NULL;
info->rowid_filter_func= NULL;
info->has_cond_pushdown= 0;
}
check_result_t ma_check_index_cond_real(MARIA_HA *info, uint keynr,
uchar *record);
static inline check_result_t ma_check_index_cond(MARIA_HA *info, uint keynr,
uchar *record)
{
if (!info->has_cond_pushdown)
return CHECK_POS;
return ma_check_index_cond_real(info, keynr, record);
}
extern my_bool ma_yield_and_check_if_killed(MARIA_HA *info, int inx); extern my_bool ma_yield_and_check_if_killed(MARIA_HA *info, int inx);
extern my_bool ma_killed_standalone(MARIA_HA *); extern my_bool ma_killed_standalone(MARIA_HA *);

View File

@ -1971,9 +1971,8 @@ int ha_myisam::index_init(uint idx, bool sorted)
active_index=idx; active_index=idx;
if (pushed_idx_cond_keyno == idx) if (pushed_idx_cond_keyno == idx)
mi_set_index_cond_func(file, handler_index_cond_check, this); mi_set_index_cond_func(file, handler_index_cond_check, this);
if (pushed_rowid_filter) if (pushed_rowid_filter && handler_rowid_filter_is_active(this))
mi_set_rowid_filter_func(file, handler_rowid_filter_check, mi_set_rowid_filter_func(file, handler_rowid_filter_check, this);
handler_rowid_filter_is_active, this);
return 0; return 0;
} }
@ -1981,11 +1980,10 @@ int ha_myisam::index_init(uint idx, bool sorted)
int ha_myisam::index_end() int ha_myisam::index_end()
{ {
DBUG_ENTER("ha_myisam::index_end"); DBUG_ENTER("ha_myisam::index_end");
active_index=MAX_KEY; active_index= MAX_KEY;
//pushed_idx_cond_keyno= MAX_KEY;
mi_set_index_cond_func(file, NULL, 0); mi_set_index_cond_func(file, NULL, 0);
in_range_check_pushed_down= FALSE; in_range_check_pushed_down= FALSE;
mi_set_rowid_filter_func(file, NULL, NULL, 0); mi_set_rowid_filter_func(file, NULL, 0);
ds_mrr.dsmrr_close(); ds_mrr.dsmrr_close();
#if !defined(DBUG_OFF) && defined(SQL_SELECT_FIXED_FOR_UPDATE) #if !defined(DBUG_OFF) && defined(SQL_SELECT_FIXED_FOR_UPDATE)
file->update&= ~HA_STATE_AKTIV; // Forget active row file->update&= ~HA_STATE_AKTIV; // Forget active row
@ -2021,9 +2019,8 @@ int ha_myisam::index_read_idx_map(uchar *buf, uint index, const uchar *key,
end_range= NULL; end_range= NULL;
if (index == pushed_idx_cond_keyno) if (index == pushed_idx_cond_keyno)
mi_set_index_cond_func(file, handler_index_cond_check, this); mi_set_index_cond_func(file, handler_index_cond_check, this);
if (pushed_rowid_filter) if (pushed_rowid_filter && handler_rowid_filter_is_active(this))
mi_set_rowid_filter_func(file, handler_rowid_filter_check, mi_set_rowid_filter_func(file, handler_rowid_filter_check, this);
handler_rowid_filter_is_active, this);
res= mi_rkey(file, buf, index, key, keypart_map, find_flag); res= mi_rkey(file, buf, index, key, keypart_map, find_flag);
mi_set_index_cond_func(file, NULL, 0); mi_set_index_cond_func(file, NULL, 0);
return res; return res;
@ -2728,12 +2725,23 @@ Item *ha_myisam::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
bool ha_myisam::rowid_filter_push(Rowid_filter* rowid_filter) bool ha_myisam::rowid_filter_push(Rowid_filter* rowid_filter)
{ {
/* This will be used in index_init() */
pushed_rowid_filter= rowid_filter; pushed_rowid_filter= rowid_filter;
mi_set_rowid_filter_func(file, handler_rowid_filter_check,
handler_rowid_filter_is_active, this);
return false; return false;
} }
/* Enable / disable rowid filter depending if it's active or not */
void ha_myisam::rowid_filter_changed()
{
if (pushed_rowid_filter && handler_rowid_filter_is_active(this))
mi_set_rowid_filter_func(file, handler_rowid_filter_check, this);
else
mi_set_rowid_filter_func(file, NULL, this);
}
struct st_mysql_storage_engine myisam_storage_engine= struct st_mysql_storage_engine myisam_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION }; { MYSQL_HANDLERTON_INTERFACE_VERSION };

View File

@ -173,8 +173,9 @@ public:
int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size); int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size);
/* Index condition pushdown implementation */ /* Index condition pushdown implementation */
Item *idx_cond_push(uint keyno, Item* idx_cond); Item *idx_cond_push(uint keyno, Item* idx_cond) override;
bool rowid_filter_push(Rowid_filter* rowid_filter); bool rowid_filter_push(Rowid_filter* rowid_filter) override;
void rowid_filter_changed() override;
private: private:
DsMrr_impl ds_mrr; DsMrr_impl ds_mrr;

View File

@ -376,16 +376,16 @@ void mi_set_index_cond_func(MI_INFO *info, index_cond_func_t func,
{ {
info->index_cond_func= func; info->index_cond_func= func;
info->index_cond_func_arg= func_arg; info->index_cond_func_arg= func_arg;
info->has_cond_pushdown= (info->index_cond_func || info->rowid_filter_func);
} }
void mi_set_rowid_filter_func(MI_INFO *info, void mi_set_rowid_filter_func(MI_INFO *info,
rowid_filter_func_t check_func, rowid_filter_func_t check_func,
rowid_filter_is_active_func_t is_active_func,
void *func_arg) void *func_arg)
{ {
info->rowid_filter_func= check_func; info->rowid_filter_func= check_func;
info->rowid_filter_is_active_func= is_active_func;
info->rowid_filter_func_arg= func_arg; info->rowid_filter_func_arg= func_arg;
info->has_cond_pushdown= (info->index_cond_func || info->rowid_filter_func);
} }
/* /*

View File

@ -510,14 +510,6 @@ int mi_unpack_index_tuple(MI_INFO *info, uint keynr, uchar *record)
} }
static int mi_check_rowid_filter_is_active(MI_INFO *info)
{
if (info->rowid_filter_is_active_func == NULL)
return 0;
return info->rowid_filter_is_active_func(info->rowid_filter_func_arg);
}
/* /*
Check the current index tuple: Check ICP condition and/or Rowid Filter Check the current index tuple: Check ICP condition and/or Rowid Filter
@ -532,21 +524,23 @@ static int mi_check_rowid_filter_is_active(MI_INFO *info)
Check result according to check_result_t definition Check result according to check_result_t definition
*/ */
check_result_t mi_check_index_tuple(MI_INFO *info, uint keynr, uchar *record) check_result_t mi_check_index_tuple_real(MI_INFO *info, uint keynr, uchar *record)
{ {
int need_unpack= TRUE;
check_result_t res= CHECK_POS; check_result_t res= CHECK_POS;
DBUG_ASSERT(info->index_cond_func || info->rowid_filter_func);
if (mi_unpack_index_tuple(info, keynr, record))
return CHECK_ERROR;
if (info->index_cond_func) if (info->index_cond_func)
{ {
if (mi_unpack_index_tuple(info, keynr, record)) if ((res= info->index_cond_func(info->index_cond_func_arg)) ==
res= CHECK_ERROR; CHECK_OUT_OF_RANGE)
else if ((res= info->index_cond_func(info->index_cond_func_arg)) ==
CHECK_OUT_OF_RANGE)
{ {
/* We got beyond the end of scanned range */ /* We got beyond the end of scanned range */
info->lastpos= HA_OFFSET_ERROR; /* No active record */ info->lastpos= HA_OFFSET_ERROR; /* No active record */
my_errno= HA_ERR_END_OF_FILE; my_errno= HA_ERR_END_OF_FILE;
return res;
} }
/* /*
@ -555,25 +549,17 @@ check_result_t mi_check_index_tuple(MI_INFO *info, uint keynr, uchar *record)
*/ */
if (res != CHECK_POS) if (res != CHECK_POS)
return res; return res;
need_unpack= FALSE;
} }
/* Check the Rowid Filter, if present */ /* Check the Rowid Filter, if present */
if (mi_check_rowid_filter_is_active(info)) if (info->rowid_filter_func)
{ {
/* Unpack the index tuple if we haven't done it already */ if ((res= info->rowid_filter_func(info->rowid_filter_func_arg)) ==
if (need_unpack && mi_unpack_index_tuple(info, keynr, record)) CHECK_OUT_OF_RANGE)
res= CHECK_ERROR;
else
{ {
if ((res= info->rowid_filter_func(info->rowid_filter_func_arg)) == /* We got beyond the end of scanned range */
CHECK_OUT_OF_RANGE) info->lastpos= HA_OFFSET_ERROR; /* No active record */
{ my_errno= HA_ERR_END_OF_FILE;
/* We got beyond the end of scanned range */
info->lastpos= HA_OFFSET_ERROR; /* No active record */
my_errno= HA_ERR_END_OF_FILE;
}
} }
} }
return res; return res;

View File

@ -119,7 +119,7 @@ int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key,
while ((info->lastpos >= info->state->data_file_length && while ((info->lastpos >= info->state->data_file_length &&
(search_flag != HA_READ_KEY_EXACT || (search_flag != HA_READ_KEY_EXACT ||
last_used_keyseg != keyinfo->seg + keyinfo->keysegs)) || last_used_keyseg != keyinfo->seg + keyinfo->keysegs)) ||
(res= mi_check_index_tuple(info, inx, buf)) == CHECK_NEG) (res= mi_check_index_tuple(info, inx, buf)) == CHECK_NEG)
{ {
uint not_used[2]; uint not_used[2];
/* /*

View File

@ -304,10 +304,10 @@ struct st_myisam_info
/* If info->buff has to be reread for rnext */ /* If info->buff has to be reread for rnext */
my_bool buff_used; my_bool buff_used;
my_bool create_unique_index_by_sort; my_bool create_unique_index_by_sort;
my_bool has_cond_pushdown;
index_cond_func_t index_cond_func; /* Index condition function */ index_cond_func_t index_cond_func; /* Index condition function */
void *index_cond_func_arg; /* parameter for the func */ void *index_cond_func_arg; /* parameter for the func */
rowid_filter_func_t rowid_filter_func; /* rowid filter check function */ rowid_filter_func_t rowid_filter_func; /* rowid filter check function */
rowid_filter_is_active_func_t rowid_filter_is_active_func; /* is activefunction */
void *rowid_filter_func_arg; /* parameter for the func */ void *rowid_filter_func_arg; /* parameter for the func */
THR_LOCK_DATA lock; THR_LOCK_DATA lock;
uchar *rtree_recursion_state; /* For RTREE */ uchar *rtree_recursion_state; /* For RTREE */
@ -742,7 +742,15 @@ my_bool mi_dynmap_file(MI_INFO *info, my_off_t size);
int mi_munmap_file(MI_INFO *info); int mi_munmap_file(MI_INFO *info);
void mi_remap_file(MI_INFO *info, my_off_t size); void mi_remap_file(MI_INFO *info, my_off_t size);
check_result_t mi_check_index_tuple(MI_INFO *info, uint keynr, uchar *record); check_result_t mi_check_index_tuple_real(MI_INFO *info, uint keynr,
uchar *record);
static inline check_result_t mi_check_index_tuple(MI_INFO *info, uint keynr,
uchar *record)
{
if (!info->has_cond_pushdown && ! info->rowid_filter_func)
return CHECK_POS;
return mi_check_index_tuple_real(info, keynr, record);
}
/* Functions needed by mi_check */ /* Functions needed by mi_check */
int killed_ptr(HA_CHECK *param); int killed_ptr(HA_CHECK *param);
@ -754,7 +762,6 @@ extern void mi_set_index_cond_func(MI_INFO *info, index_cond_func_t check_func,
void *func_arg); void *func_arg);
extern void mi_set_rowid_filter_func(MI_INFO *info, extern void mi_set_rowid_filter_func(MI_INFO *info,
rowid_filter_func_t check_func, rowid_filter_func_t check_func,
rowid_filter_is_active_func_t is_active_func,
void *func_arg); void *func_arg);
int flush_blocks(HA_CHECK *param, KEY_CACHE *key_cache, File file, int flush_blocks(HA_CHECK *param, KEY_CACHE *key_cache, File file,
ulonglong *dirty_part_map); ulonglong *dirty_part_map);