Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions mysql-test/main/index_intersect.result
Original file line number Diff line number Diff line change
Expand Up @@ -973,3 +973,69 @@ f1 f4 f5
DROP TABLE t1;
SET SESSION optimizer_switch='index_merge_sort_intersection=on';
SET SESSION optimizer_switch='rowid_filter=default';
#
# MDEV-38327 wrong result with index_merge_sort_intersection and rowid_filter=on
#
CREATE TABLE t1 (c int, b int, a int , d int, PRIMARY KEY (c), KEY ib (b), KEY iad (a,d));
INSERT INTO t1
SELECT seq + 1000000, FLOOR(seq / 5) % 1350 + 1000000, FLOOR(seq / 5) % 1350 , seq % 10 FROM seq_1_to_7000 ;
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
set optimizer_switch='index_merge_sort_intersection=on';
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status Table is already up to date
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
drop table t1;
## MDEV-28878 case
CREATE TABLE t1 (f int);
INSERT INTO t1 VALUES (0),(4);
CREATE TABLE t2 (pk int, a int, b varchar(10), PRIMARY KEY (pk), KEY a (a), KEY b (b));
INSERT INTO t2 VALUES
(1,2,'v'),(2,3,'p'),(3,4,'p'),(4,2,'y'),(5,7,'q'),
(6,4,'a'),(7,1,'d'),(8,5,'a'),(9,5,'z'),(10,1,'t'),
(11,1,'y'),(12,5,'o'),(13,4,'a'),(14,5,'s'),(15,5,'m');
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
SET optimizer_switch='rowid_filter=on';
SET optimizer_switch='index_merge_sort_intersection=off';
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;
f pk a b
4 3 4 p
SET optimizer_switch='index_merge_sort_intersection=on';
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;
f pk a b
4 3 4 p
DROP TABLE t1, t2;
49 changes: 49 additions & 0 deletions mysql-test/main/index_intersect.test
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,52 @@ DROP TABLE t1;

SET SESSION optimizer_switch='index_merge_sort_intersection=on';
SET SESSION optimizer_switch='rowid_filter=default';

--echo #
--echo # MDEV-38327 wrong result with index_merge_sort_intersection and rowid_filter=on
--echo #
--source include/have_sequence.inc
CREATE TABLE t1 (c int, b int, a int , d int, PRIMARY KEY (c), KEY ib (b), KEY iad (a,d));
INSERT INTO t1
SELECT seq + 1000000, FLOOR(seq / 5) % 1350 + 1000000, FLOOR(seq / 5) % 1350 , seq % 10 FROM seq_1_to_7000 ;

let $query=
select a, b, c from t1 where a=1000 and b=1001000;

eval explain $query;
eval $query;

set optimizer_switch='index_merge_sort_intersection=on';

eval explain $query;
eval $query;

analyze table t1;

eval explain $query;
eval $query;

drop table t1;

--echo ## MDEV-28878 case

CREATE TABLE t1 (f int);
INSERT INTO t1 VALUES (0),(4);

CREATE TABLE t2 (pk int, a int, b varchar(10), PRIMARY KEY (pk), KEY a (a), KEY b (b));
INSERT INTO t2 VALUES
(1,2,'v'),(2,3,'p'),(3,4,'p'),(4,2,'y'),(5,7,'q'),
(6,4,'a'),(7,1,'d'),(8,5,'a'),(9,5,'z'),(10,1,'t'),
(11,1,'y'),(12,5,'o'),(13,4,'a'),(14,5,'s'),(15,5,'m');

ANALYZE TABLE t1, t2 PERSISTENT FOR ALL;

SET optimizer_switch='rowid_filter=on'; # Default

SET optimizer_switch='index_merge_sort_intersection=off'; # Default
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;

SET optimizer_switch='index_merge_sort_intersection=on';
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;

DROP TABLE t1, t2;
66 changes: 66 additions & 0 deletions mysql-test/main/index_intersect_innodb.result
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,72 @@ f1 f4 f5
DROP TABLE t1;
SET SESSION optimizer_switch='index_merge_sort_intersection=on';
SET SESSION optimizer_switch='rowid_filter=default';
#
# MDEV-38327 wrong result with index_merge_sort_intersection and rowid_filter=on
#
CREATE TABLE t1 (c int, b int, a int , d int, PRIMARY KEY (c), KEY ib (b), KEY iad (a,d));
INSERT INTO t1
SELECT seq + 1000000, FLOOR(seq / 5) % 1350 + 1000000, FLOOR(seq / 5) % 1350 , seq % 10 FROM seq_1_to_7000 ;
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
set optimizer_switch='index_merge_sort_intersection=on';
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
explain select a, b, c from t1 where a=1000 and b=1001000;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge ib,iad ib,iad 5,5 NULL 1 Using sort_intersect(ib,iad); Using where
select a, b, c from t1 where a=1000 and b=1001000;
a b c
1000 1001000 1005000
1000 1001000 1005001
1000 1001000 1005002
1000 1001000 1005003
1000 1001000 1005004
drop table t1;
## MDEV-28878 case
CREATE TABLE t1 (f int);
INSERT INTO t1 VALUES (0),(4);
CREATE TABLE t2 (pk int, a int, b varchar(10), PRIMARY KEY (pk), KEY a (a), KEY b (b));
INSERT INTO t2 VALUES
(1,2,'v'),(2,3,'p'),(3,4,'p'),(4,2,'y'),(5,7,'q'),
(6,4,'a'),(7,1,'d'),(8,5,'a'),(9,5,'z'),(10,1,'t'),
(11,1,'y'),(12,5,'o'),(13,4,'a'),(14,5,'s'),(15,5,'m');
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
SET optimizer_switch='rowid_filter=on';
SET optimizer_switch='index_merge_sort_intersection=off';
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;
f pk a b
4 3 4 p
SET optimizer_switch='index_merge_sort_intersection=on';
SELECT * FROM t1 JOIN t2 ON t1.f = t2.a WHERE t2.b >= 'j' AND t2.a != 5;
f pk a b
4 3 4 p
DROP TABLE t1, t2;
set global innodb_stats_persistent= @innodb_stats_persistent_save;
set global innodb_stats_persistent_sample_pages=
@innodb_stats_persistent_sample_pages_save;
Expand Down
6 changes: 6 additions & 0 deletions sql/opt_range.h
Original file line number Diff line number Diff line change
Expand Up @@ -1576,6 +1576,7 @@ class QUICK_INDEX_SORT_SELECT : public QUICK_SELECT_I



/* Index merge sort union */
class QUICK_INDEX_MERGE_SELECT : public QUICK_INDEX_SORT_SELECT
{
private:
Expand All @@ -1593,6 +1594,7 @@ class QUICK_INDEX_MERGE_SELECT : public QUICK_INDEX_SORT_SELECT
void add_keys_and_lengths(String *key_names, String *used_lengths) override;
};

/* Index merge sort intersection */
class QUICK_INDEX_INTERSECT_SELECT : public QUICK_INDEX_SORT_SELECT
{
protected:
Expand All @@ -1611,6 +1613,8 @@ class QUICK_INDEX_INTERSECT_SELECT : public QUICK_INDEX_SORT_SELECT


/*
Index merge intersection

Rowid-Ordered Retrieval (ROR) index intersection quick select.
This quick select produces intersection of row sequences returned
by several QUICK_RANGE_SELECTs it "merges".
Expand Down Expand Up @@ -1698,6 +1702,8 @@ class QUICK_ROR_INTERSECT_SELECT : public QUICK_SELECT_I


/*
Index merge union

Rowid-Ordered Retrieval index union select.
This quick select produces union of row sequences returned by several
quick select it "merges".
Expand Down
2 changes: 1 addition & 1 deletion sql/rowid_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
5. At the execution stage
In the function sub_select() just before the first access of a join
table s employing a range filter
The method JOIN_TAB::build_range_rowid_filter_if_needed() is called
The method JOIN_TAB::build_range_rowid_filter() is called
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can split cleanups like this to a separate commit if needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes please.

The method fills the filter using the quick select created by
JOIN::make_range_rowid_filters().
Expand Down
6 changes: 1 addition & 5 deletions sql/sql_delete.cc
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,7 @@ bool Update_plan::save_explain_data_intern(THD *thd,
/* Set jtype */
if (select && select->quick)
{
int quick_type= select->quick->get_type();
if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION))
if (is_index_merge(select->quick->get_type()))
explain->jtype= JT_INDEX_MERGE;
else
explain->jtype= JT_RANGE;
Expand Down
31 changes: 10 additions & 21 deletions sql/sql_select.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14456,6 +14456,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
}
tab->type= JT_RANGE;
tab->use_quick=1;
if (is_index_merge(tab->quick->get_type()))
tab->clear_range_rowid_filter();
tab->ref.key= -1;
tab->ref.key_parts=0; // Don't use ref key.
join->best_positions[i].records_read= rows2double(tab->quick->records);
Expand Down Expand Up @@ -27404,17 +27406,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
else if (select && select->quick) // Range found by opt_range
{
int quick_type= select->quick->get_type();
/*
assume results are not ordered when index merge is used
TODO: sergeyp: Results of all index merge selects actually are ordered
/*
assume results are not ordered when index merge is used
TODO: sergeyp: Results of all index merge selects actually are ordered
by clustered PK values.
*/

if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT)

if (is_index_merge(select->quick->get_type()))
{
/*
we set ref_key=MAX_KEY instead of -1, because test_if_cheaper_ordering()
Expand Down Expand Up @@ -27654,10 +27652,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
goto skipped_filesort;

quick_type= select->quick->get_type();
if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
if (is_index_merge(quick_type) ||
quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
{
tab->limit= 0;
Expand Down Expand Up @@ -30850,10 +30845,7 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
{
cur_quick= tab_select->quick;
quick_type= cur_quick->get_type();
if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION))
if (is_index_merge(quick_type))
tab_type= type == JT_HASH ? JT_HASH_INDEX_MERGE : JT_INDEX_MERGE;
else
tab_type= type == JT_HASH ? JT_HASH_RANGE : JT_RANGE;
Expand Down Expand Up @@ -31055,10 +31047,7 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
eta->pushed_index_cond= cache_idx_cond;
}

if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
if (is_index_merge(quick_type))
{
eta->push_extra(ET_USING);
}
Expand Down
7 changes: 7 additions & 0 deletions sql/sql_select.h
Original file line number Diff line number Diff line change
Expand Up @@ -2013,6 +2013,13 @@ void copy_fields(TMP_TABLE_PARAM *param);
bool copy_funcs(Item **func_ptr, const THD *thd);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
bool is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args);
inline bool is_index_merge(int qtype)
{
return qtype == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
qtype == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
qtype == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
qtype == QUICK_SELECT_I::QS_TYPE_ROR_UNION;
}

/* functions from opt_sum.cc */
bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
Expand Down
2 changes: 1 addition & 1 deletion storage/innobase/row/row0sel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4034,7 +4034,7 @@ row_search_idx_cond_check(
byte* mysql_rec, /*!< out: record
in MySQL format (invalid unless
prebuilt->idx_cond!=NULL and
we return ICP_MATCH) */
we return CHECK_POS) */
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct
for the table handle */
const rec_t* rec, /*!< in: InnoDB record */
Expand Down