Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
30b3c3bf
Commit
30b3c3bf
authored
Nov 21, 2003
by
sergefp@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merged, most likely needs post-merge fix
parents
5e46a059
4016048d
Changes
16
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1930 additions
and
154 deletions
+1930
-154
BitKeeper/etc/logging_ok
BitKeeper/etc/logging_ok
+1
-0
mysql-test/r/index_merge.result
mysql-test/r/index_merge.result
+312
-0
mysql-test/r/index_merge_innodb.result
mysql-test/r/index_merge_innodb.result
+55
-0
mysql-test/t/index_merge.test
mysql-test/t/index_merge.test
+267
-0
mysql-test/t/index_merge_innodb.test
mysql-test/t/index_merge_innodb.test
+54
-0
sql/opt_ft.cc
sql/opt_ft.cc
+1
-1
sql/opt_ft.h
sql/opt_ft.h
+4
-3
sql/opt_range.cc
sql/opt_range.cc
+898
-102
sql/opt_range.h
sql/opt_range.h
+175
-18
sql/sql_class.cc
sql/sql_class.cc
+2
-2
sql/sql_list.h
sql/sql_list.h
+7
-0
sql/sql_select.cc
sql/sql_select.cc
+87
-18
sql/sql_select.h
sql/sql_select.h
+3
-2
sql/sql_test.cc
sql/sql_test.cc
+31
-1
sql/sql_union.cc
sql/sql_union.cc
+1
-1
sql/sql_update.cc
sql/sql_update.cc
+32
-6
No files found.
BitKeeper/etc/logging_ok
View file @
30b3c3bf
...
...
@@ -103,6 +103,7 @@ peter@mysql.com
peterg@mysql.com
pgulutzan@linux.local
pmartin@build.mysql2.com
psergey@psergey.(none)
ram@deer.(none)
ram@gw.mysql.r18.ru
ram@gw.udmsearch.izhnet.ru
...
...
mysql-test/r/index_merge.result
0 → 100644
View file @
30b3c3bf
This diff is collapsed.
Click to expand it.
mysql-test/r/index_merge_innodb.result
0 → 100644
View file @
30b3c3bf
drop table if exists t1;
create table t1
(
key1 int not null,
key2 int not null,
INDEX i1(key1),
INDEX i2(key2),
) type=innodb;
explain select * from t1 where key1 < 5 or key2 > 197;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using where
select * from t1 where key1 < 5 or key2 > 197;
key1 key2
0 200
1 199
2 198
3 197
4 196
explain select * from t1 where key1 < 3 or key2 > 195;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using where
select * from t1 where key1 < 3 or key2 > 195;
key1 key2
0 200
1 199
2 198
4 196
3 197
alter table t1 add str1 char (255) not null,
add zeroval int not null default 0,
add str2 char (255) not null,
add str3 char (255) not null;
update t1 set str1='aaa', str2='bbb', str3=concat(key2, '-', key1 div 2, '_' ,if(key1 mod 2 = 0, 'a', 'A'));
alter table t1 add primary key (str1, zeroval, str2, str3);
explain select * from t1 where key1 < 5 or key2 > 197;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using where
select * from t1 where key1 < 5 or key2 > 197;
key1 key2 str1 zeroval str2 str3
0 200 aaa 0 bbb 200-0_a
1 199 aaa 0 bbb 199-0_A
2 198 aaa 0 bbb 198-1_a
3 197 aaa 0 bbb 197-1_A
4 196 aaa 0 bbb 196-2_a
explain select * from t1 where key1 < 3 or key2 > 195;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using where
select * from t1 where key1 < 3 or key2 > 195;
key1 key2 str1 zeroval str2 str3
0 200 aaa 0 bbb 200-0_a
1 199 aaa 0 bbb 199-0_A
2 198 aaa 0 bbb 198-1_a
4 196 aaa 0 bbb 196-2_a
3 197 aaa 0 bbb 197-1_A
drop table t1;
mysql-test/t/index_merge.test
0 → 100644
View file @
30b3c3bf
#
# Index merge tests
#
--
disable_warnings
drop
table
if
exists
t0
,
t1
,
t2
,
t3
;
--
enable_warnings
# Create and fill a table with simple keys
create
table
t0
(
key1
int
not
null
,
INDEX
i1
(
key1
),
);
--
disable_query_log
insert
into
t0
values
(
1
),(
2
),(
3
),(
4
),(
5
),(
6
),(
7
),(
8
);
let
$
1
=
7
;
set
@
d
=
8
;
while
(
$
1
)
{
eval
insert
into
t0
select
key1
+@
d
from
t0
;
eval
set
@
d
=@
d
*
2
;
dec
$
1
;
}
--
enable_query_log
alter
table
t0
add
key2
int
not
null
,
add
index
i2
(
key2
);
alter
table
t0
add
key3
int
not
null
,
add
index
i3
(
key3
);
alter
table
t0
add
key4
int
not
null
,
add
index
i4
(
key4
);
alter
table
t0
add
key5
int
not
null
,
add
index
i5
(
key5
);
alter
table
t0
add
key6
int
not
null
,
add
index
i6
(
key6
);
alter
table
t0
add
key7
int
not
null
,
add
index
i7
(
key7
);
alter
table
t0
add
key8
int
not
null
,
add
index
i8
(
key8
);
update
t0
set
key2
=
key1
,
key3
=
key1
,
key4
=
key1
,
key5
=
key1
,
key6
=
key1
,
key7
=
key1
,
key8
=
1024
-
key1
;
analyze
table
t0
;
# 1. One index
explain
select
*
from
t0
where
key1
<
3
or
key1
>
1020
;
# 2. Simple cases
explain
select
*
from
t0
where
key1
<
3
or
key2
>
1020
;
select
*
from
t0
where
key1
<
3
or
key2
>
1020
;
explain
select
*
from
t0
where
key1
<
3
or
key2
<
4
;
explain
select
*
from
t0
where
(
key1
>
30
and
key1
<
35
)
or
(
key2
>
32
and
key2
<
40
);
select
*
from
t0
where
(
key1
>
30
and
key1
<
35
)
or
(
key2
>
32
and
key2
<
40
);
# 3. Check that index_merge doesn't break "ignore/force/use index"
explain
select
*
from
t0
ignore
index
(
i2
)
where
key1
<
3
or
key2
<
4
;
explain
select
*
from
t0
where
(
key1
<
3
or
key2
<
4
)
and
key3
=
50
;
explain
select
*
from
t0
use
index
(i1,i2) where (key1 < 3 or key2 <4) and key3 = 50
;
explain
select
*
from
t0
where
(
key1
>
1
or
key2
>
2
);
explain
select
*
from
t0
force
index
(
i1
,
i2
)
where
(
key1
>
1
or
key2
>
2
);
# 4. Check if conjuncts are grouped by keyuse
explain
select
*
from
t0
where
key1
<
3
or
key2
<
3
or
(
key1
>
5
and
key1
<
8
)
or
(
key1
>
10
and
key1
<
12
)
or
(
key2
>
100
and
key2
<
110
);
# 5. Check index_merge with conjuncts that are always true/false
# verify fallback to "range" if there is only one non-confluent condition
explain
select
*
from
t0
where
key2
=
45
or
key1
<=>
null
;
explain
select
*
from
t0
where
key2
=
45
or
key1
is
not
null
;
explain
select
*
from
t0
where
key2
=
45
or
key1
is
null
;
# the last conj. is always false and will be discarded
explain
select
*
from
t0
where
key2
=
10
or
key3
=
3
or
key4
<=>
null
;
# the last conj. is always true and will cause 'all' scan
explain
select
*
from
t0
where
key2
=
10
or
key3
=
3
or
key4
is
null
;
# some more complicated cases
explain
select
key1
from
t0
where
(
key1
<=>
null
)
or
(
key2
<
5
)
or
(
key3
=
10
)
or
(
key4
<=>
null
);
explain
select
key1
from
t0
where
(
key1
<=>
null
)
or
(
key1
<
5
)
or
(
key3
=
10
)
or
(
key4
<=>
null
);
# 6.Several ways to do index_merge, (ignored) index_merge vs. range
explain
select
*
from
t0
where
(
key1
<
3
or
key2
<
3
)
and
(
key3
<
4
or
key4
<
4
)
and
(
key5
<
5
or
key6
<
5
);
explain
select
*
from
t0
where
(
key1
<
3
or
key2
<
6
)
and
(
key1
<
7
or
key3
<
4
);
select
*
from
t0
where
(
key1
<
3
or
key2
<
6
)
and
(
key1
<
7
or
key3
<
4
);
explain
select
*
from
t0
where
(
key1
<
3
or
key2
<
3
)
and
(
key3
<
4
or
key4
<
4
)
and
(
key5
<
2
or
key6
<
2
);
# now index_merge is not used at all when "range" is possible
explain
select
*
from
t0
where
(
key1
<
3
or
key2
<
3
)
and
(
key3
<
100
);
# this even can cause "all" scan:
explain
select
*
from
t0
where
(
key1
<
3
or
key2
<
3
)
and
(
key3
<
1000
);
# 7. Complex cases
# tree_or(List<SEL_IMERGE>, range SEL_TREE).
explain
select
*
from
t0
where
((
key1
<
4
or
key2
<
4
)
and
(
key2
<
5
or
key3
<
4
))
or
key2
>
5
;
explain
select
*
from
t0
where
((
key1
<
4
or
key2
<
4
)
and
(
key2
<
5
or
key3
<
4
))
or
key1
<
7
;
select
*
from
t0
where
((
key1
<
4
or
key2
<
4
)
and
(
key2
<
5
or
key3
<
4
))
or
key1
<
7
;
# tree_or(List<SEL_IMERGE>, List<SEL_IMERGE>).
explain
select
*
from
t0
where
((
key1
<
4
or
key2
<
4
)
and
(
key3
<
5
or
key5
<
4
))
or
((
key5
<
5
or
key6
<
6
)
and
(
key7
<
7
or
key8
<
4
));
explain
select
*
from
t0
where
((
key3
<
5
or
key5
<
4
)
and
(
key1
<
4
or
key2
<
4
))
or
((
key7
<
7
or
key8
<
4
)
and
(
key5
<
5
or
key6
<
6
));
explain
select
*
from
t0
where
((
key3
<
5
or
key5
<
4
)
and
(
key1
<
4
or
key2
<
4
))
or
((
key3
<
7
or
key5
<
2
)
and
(
key5
<
5
or
key6
<
6
));
explain
select
*
from
t0
where
((
key3
<
5
or
key5
<
4
)
and
(
key1
<
4
or
key2
<
4
))
or
(((
key3
<
7
and
key7
<
6
)
or
key5
<
2
)
and
(
key5
<
5
or
key6
<
6
));
explain
select
*
from
t0
where
((
key3
<
5
or
key5
<
4
)
and
(
key1
<
4
or
key2
<
4
))
or
((
key3
>=
5
or
key5
<
2
)
and
(
key5
<
5
or
key6
<
6
));
explain
select
*
from
t0
force
index
(
i1
,
i2
,
i3
,
i4
,
i5
,
i6
)
where
((
key3
<
5
or
key5
<
4
)
and
(
key1
<
4
or
key2
<
4
))
or
((
key3
>=
5
or
key5
<
2
)
and
(
key5
<
5
or
key6
<
6
));
# 8. Verify that "order by" after index merge uses filesort
select
*
from
t0
where
key1
<
5
or
key8
<
4
order
by
key1
;
explain
select
*
from
t0
where
key1
<
5
or
key8
<
4
order
by
key1
;
# 9. Check that index_merge cost is compared to 'index' where possible
create
table
t2
like
t0
;
insert
into
t2
select
*
from
t0
;
alter
table
t2
add
index
i1_3
(
key1
,
key3
);
alter
table
t2
add
index
i2_3
(
key2
,
key3
);
alter
table
t2
drop
index
i1
;
alter
table
t2
drop
index
i2
;
alter
table
t2
add
index
i321
(
key3
,
key2
,
key1
);
# index_merge vs 'index', index_merge is better.
explain
select
key3
from
t2
where
key1
=
100
or
key2
=
100
;
# index_merge vs 'index', 'index' is better.
explain
select
key3
from
t2
where
key1
<
100
or
key2
<
100
;
# index_merge vs 'all', index_merge is better.
explain
select
key7
from
t2
where
key1
<
100
or
key2
<
100
;
# 10. Multipart keys.
create
table
t4
(
key1a
int
not
null
,
key1b
int
not
null
,
key2
int
not
null
,
key2_1
int
not
null
,
key2_2
int
not
null
,
key3
int
not
null
,
index
i1a
(
key1a
,
key1b
),
index
i1b
(
key1b
,
key1a
),
index
i2_1
(
key2
,
key2_1
),
index
i2_2
(
key2
,
key2_1
),
);
insert
into
t4
select
key1
,
key1
,
key1
div
10
,
key1
%
10
,
key1
%
10
,
key1
from
t0
;
# the following will be handled by index_merge:
select
*
from
t4
where
key1a
=
3
or
key1b
=
4
;
explain
select
*
from
t4
where
key1a
=
3
or
key1b
=
4
;
# and the following will not
explain
select
*
from
t4
where
key2
=
1
and
(
key2_1
=
1
or
key3
=
5
);
explain
select
*
from
t4
where
key2
=
1
and
(
key2_1
=
1
or
key2_2
=
5
);
explain
select
*
from
t4
where
key2_1
=
1
or
key2_2
=
5
;
# 11. Multitable selects
create
table
t1
like
t0
;
insert
into
t1
select
*
from
t0
;
# index_merge on first table in join
explain
select
*
from
t0
left
join
t1
on
(
t0
.
key1
=
t1
.
key1
)
where
t0
.
key1
=
3
or
t0
.
key2
=
4
;
select
*
from
t0
left
join
t1
on
(
t0
.
key1
=
t1
.
key1
)
where
t0
.
key1
=
3
or
t0
.
key2
=
4
;
explain
select
*
from
t0
,
t1
where
(
t0
.
key1
=
t1
.
key1
)
and
(
t0
.
key1
=
3
or
t0
.
key2
=
4
);
# index_merge vs. ref
explain
select
*
from
t0
,
t1
where
(
t0
.
key1
=
t1
.
key1
)
and
(
t0
.
key1
=
3
or
t0
.
key2
=
4
)
and
t1
.
key1
<
200
;
# index_merge vs. ref
explain
select
*
from
t0
,
t1
where
(
t0
.
key1
=
t1
.
key1
)
and
(
t0
.
key1
=
3
or
t0
.
key2
<
4
)
and
t1
.
key1
=
2
;
# index_merge on second table in join
explain
select
*
from
t0
,
t1
where
t0
.
key1
=
5
and
(
t1
.
key1
=
t0
.
key1
or
t1
.
key8
=
t0
.
key1
);
# index_merge inside union
explain
select
*
from
t1
where
key1
=
3
or
key2
=
4
union
select
*
from
t1
where
key1
<
4
or
key3
=
5
;
# index merge in subselect
explain
select
*
from
(
select
*
from
t1
where
key1
=
3
or
key2
=
3
)
as
Z
where
key8
>
5
;
# 12. check for long index_merges.
create
table
t3
like
t0
;
insert
into
t3
select
*
from
t0
;
alter
table
t3
add
key9
int
not
null
,
add
index
i9
(
key9
);
alter
table
t3
add
keyA
int
not
null
,
add
index
iA
(
keyA
);
alter
table
t3
add
keyB
int
not
null
,
add
index
iB
(
keyB
);
alter
table
t3
add
keyC
int
not
null
,
add
index
iC
(
keyC
);
update
t3
set
key9
=
key1
,
keyA
=
key1
,
keyB
=
key1
,
keyC
=
key1
;
explain
select
*
from
t3
where
key1
=
1
or
key2
=
2
or
key3
=
3
or
key4
=
4
or
key5
=
5
or
key6
=
6
or
key7
=
7
or
key8
=
8
or
key9
=
9
or
keyA
=
10
or
keyB
=
11
or
keyC
=
12
;
select
*
from
t3
where
key1
=
1
or
key2
=
2
or
key3
=
3
or
key4
=
4
or
key5
=
5
or
key6
=
6
or
key7
=
7
or
key8
=
8
or
key9
=
9
or
keyA
=
10
or
keyB
=
11
or
keyC
=
12
;
drop
table
t0
,
t1
,
t2
,
t3
,
t4
;
mysql-test/t/index_merge_innodb.test
0 → 100644
View file @
30b3c3bf
#
# Index merge tests
#
--
source
include
/
have_innodb
.
inc
--
disable_warnings
drop
table
if
exists
t1
;
--
enable_warnings
create
table
t1
(
key1
int
not
null
,
key2
int
not
null
,
INDEX
i1
(
key1
),
INDEX
i2
(
key2
),
)
type
=
innodb
;
--
disable_query_log
let
$
1
=
200
;
while
(
$
1
)
{
eval
insert
into
t1
values
(
200
-
$
1
,
$
1
);
dec
$
1
;
}
--
enable_query_log
# No primary key
explain
select
*
from
t1
where
key1
<
5
or
key2
>
197
;
select
*
from
t1
where
key1
<
5
or
key2
>
197
;
explain
select
*
from
t1
where
key1
<
3
or
key2
>
195
;
select
*
from
t1
where
key1
<
3
or
key2
>
195
;
# Primary key as case-sensitive string with \0s.
# also make primary key be longer then max. index length of MyISAM.
alter
table
t1
add
str1
char
(
255
)
not
null
,
add
zeroval
int
not
null
default
0
,
add
str2
char
(
255
)
not
null
,
add
str3
char
(
255
)
not
null
;
update
t1
set
str1
=
'aaa'
,
str2
=
'bbb'
,
str3
=
concat
(
key2
,
'-'
,
key1
div
2
,
'_'
,
if
(
key1
mod
2
=
0
,
'a'
,
'A'
));
alter
table
t1
add
primary
key
(
str1
,
zeroval
,
str2
,
str3
);
explain
select
*
from
t1
where
key1
<
5
or
key2
>
197
;
select
*
from
t1
where
key1
<
5
or
key2
>
197
;
explain
select
*
from
t1
where
key1
<
3
or
key2
>
195
;
select
*
from
t1
where
key1
<
3
or
key2
>
195
;
drop
table
t1
;
sql/opt_ft.cc
View file @
30b3c3bf
...
...
@@ -26,7 +26,7 @@
** Create a FT or QUICK RANGE based on a key
****************************************************************************/
QUICK_SELECT
*
get_ft_or_quick_select_for_ref
(
THD
*
thd
,
TABLE
*
table
,
QUICK_
RANGE_
SELECT
*
get_ft_or_quick_select_for_ref
(
THD
*
thd
,
TABLE
*
table
,
JOIN_TAB
*
tab
)
{
if
(
tab
->
type
==
JT_FT
)
...
...
sql/opt_ft.h
View file @
30b3c3bf
...
...
@@ -24,18 +24,19 @@
#pragma interface
/* gcc class implementation */
#endif
class
FT_SELECT
:
public
QUICK_SELECT
{
class
FT_SELECT
:
public
QUICK_
RANGE_
SELECT
{
public:
TABLE_REF
*
ref
;
FT_SELECT
(
THD
*
thd
,
TABLE
*
table
,
TABLE_REF
*
tref
)
:
QUICK_SELECT
(
thd
,
table
,
tref
->
key
,
1
),
ref
(
tref
)
{
init
();
}
QUICK_
RANGE_
SELECT
(
thd
,
table
,
tref
->
key
,
1
),
ref
(
tref
)
{
init
();
}
int
init
()
{
return
error
=
file
->
ft_init
();
}
int
get_next
()
{
return
error
=
file
->
ft_read
(
record
);
}
int
get_type
()
{
return
QS_TYPE_FULLTEXT
;
}
};
QUICK_SELECT
*
get_ft_or_quick_select_for_ref
(
THD
*
thd
,
TABLE
*
table
,
QUICK_
RANGE_
SELECT
*
get_ft_or_quick_select_for_ref
(
THD
*
thd
,
TABLE
*
table
,
JOIN_TAB
*
tab
);
#endif
sql/opt_range.cc
View file @
30b3c3bf
This diff is collapsed.
Click to expand it.
sql/opt_range.h
View file @
30b3c3bf
...
...
@@ -65,41 +65,198 @@ class QUICK_RANGE :public Sql_alloc {
}
};
class
INDEX_MERGE
;
class
QUICK_SELECT
{
/*
Quick select interface.
This class is parent for all QUICK_*_SELECT and FT_SELECT classes.
*/
class
QUICK_SELECT_I
{
public:
ha_rows
records
;
/* estimate of # of records to be retrieved */
double
read_time
;
/* time to perform this retrieval */
TABLE
*
head
;
/*
the only index this quick select uses, or MAX_KEY for
QUICK_INDEX_MERGE_SELECT
*/
uint
index
;
uint
max_used_key_length
,
used_key_parts
;
QUICK_SELECT_I
();
virtual
~
QUICK_SELECT_I
(){};
virtual
int
init
()
=
0
;
virtual
void
reset
(
void
)
=
0
;
virtual
int
get_next
()
=
0
;
/* get next record to retrieve */
virtual
bool
reverse_sorted
()
=
0
;
virtual
bool
unique_key_range
()
{
return
false
;
}
enum
{
QS_TYPE_RANGE
=
0
,
QS_TYPE_INDEX_MERGE
=
1
,
QS_TYPE_RANGE_DESC
=
2
,
QS_TYPE_FULLTEXT
=
3
};
/* Get type of this quick select - one of the QS_* values */
virtual
int
get_type
()
=
0
;
};
struct
st_qsel_param
;
class
SEL_ARG
;
class
QUICK_RANGE_SELECT
:
public
QUICK_SELECT_I
{
protected:
bool
next
,
dont_free
;
public:
int
error
;
uint
index
,
max_used_key_length
,
used_key_parts
;
TABLE
*
head
;
handler
*
file
;
byte
*
record
;
protected:
friend
void
print_quick_sel_range
(
QUICK_RANGE_SELECT
*
quick
,
key_map
needed_reg
);
friend
QUICK_RANGE_SELECT
*
get_quick_select_for_ref
(
THD
*
thd
,
TABLE
*
table
,
struct
st_table_ref
*
ref
);
friend
bool
get_quick_keys
(
struct
st_qsel_param
*
param
,
QUICK_RANGE_SELECT
*
quick
,
KEY_PART
*
key
,
SEL_ARG
*
key_tree
,
char
*
min_key
,
uint
min_key_flag
,
char
*
max_key
,
uint
max_key_flag
);
friend
QUICK_RANGE_SELECT
*
get_quick_select
(
struct
st_qsel_param
*
,
uint
idx
,
SEL_ARG
*
key_tree
,
MEM_ROOT
*
alloc
);
friend
class
QUICK_SELECT_DESC
;
List
<
QUICK_RANGE
>
ranges
;
List_iterator
<
QUICK_RANGE
>
it
;
QUICK_RANGE
*
range
;
MEM_ROOT
alloc
;
KEY_PART
*
key_parts
;
ha_rows
records
;
double
read_time
;
QUICK_SELECT
(
THD
*
thd
,
TABLE
*
table
,
uint
index_arg
,
bool
no_alloc
=
0
);
virtual
~
QUICK_SELECT
();
void
reset
(
void
)
{
next
=
0
;
it
.
rewind
();
}
int
init
()
{
return
error
=
file
->
index_init
(
index
);
}
virtual
int
get_next
();
virtual
bool
reverse_sorted
()
{
return
0
;
}
KEY_PART
*
key_parts
;
int
cmp_next
(
QUICK_RANGE
*
range
);
public:
QUICK_RANGE_SELECT
(
THD
*
thd
,
TABLE
*
table
,
uint
index_arg
,
bool
no_alloc
=
0
,
MEM_ROOT
*
parent_alloc
=
NULL
);
~
QUICK_RANGE_SELECT
();
void
reset
(
void
)
{
next
=
0
;
it
.
rewind
();
}
int
init
();
int
get_next
();
bool
reverse_sorted
()
{
return
0
;
}
bool
unique_key_range
();
int
get_type
()
{
return
QS_TYPE_RANGE
;
}
};
/*
Helper class for keeping track of rows that have been passed to output
in index_merge access method.
NOTES
Current implementation uses a temporary table to store ROWIDs of rows that
have been passed to output. In the future it might be changed to use more
efficient mechanisms, like Unique class.
*/
class
INDEX_MERGE
{
public:
INDEX_MERGE
(
THD
*
thd_arg
);
~
INDEX_MERGE
();
int
init
(
TABLE
*
table
);
int
check_record_in
();
int
start_last_quick_select
();
int
error
;
private:
/* The only field in temporary table */
class
Item_rowid
:
public
Item_str_func
{
TABLE
*
head
;
/* source table */
public:
Item_rowid
(
TABLE
*
table
)
:
head
(
table
)
{
max_length
=
table
->
file
->
ref_length
;
collation
.
set
(
&
my_charset_bin
);
};
const
char
*
func_name
()
const
{
return
"rowid"
;
}
bool
const_item
()
const
{
return
0
;
}
String
*
val_str
(
String
*
);
void
fix_length_and_dec
()
{}
};
/* Check if record has been processed and save it if it wasn't */
inline
int
put_record
();
/* Check if record has been processed without saving it */
inline
int
check_record
();
/* If true, check_record_in does't store ROWIDs it is passed. */
bool
dont_save
;
THD
*
thd
;
TABLE
*
head
;
/* source table */
TABLE
*
temp_table
;
/* temp. table used for values storage */
TMP_TABLE_PARAM
tmp_table_param
;
/* temp. table creation parameters */
Item_rowid
*
rowid_item
;
/* the only field in temp. table */
List
<
Item
>
fields
;
/* temp. table fields list
(the only element is rowid_item) */
ORDER
order
;
/* key for temp. table (rowid_item) */
};
class
QUICK_SELECT_DESC
:
public
QUICK_SELECT
/*
Index merge quick select.
It is implemented as a container for several QUICK_RANGE_SELECTs.
*/
class
QUICK_INDEX_MERGE_SELECT
:
public
QUICK_SELECT_I
{
public:
QUICK_INDEX_MERGE_SELECT
(
THD
*
thd
,
TABLE
*
table
);
~
QUICK_INDEX_MERGE_SELECT
();
int
init
();
void
reset
(
void
);
int
get_next
();
bool
reverse_sorted
()
{
return
false
;
}
bool
unique_key_range
()
{
return
false
;
}
int
get_type
()
{
return
QS_TYPE_INDEX_MERGE
;
}
bool
push_quick_back
(
QUICK_RANGE_SELECT
*
quick_sel_range
);
/* range quick selects this index_merge read consists of */
List
<
QUICK_RANGE_SELECT
>
quick_selects
;
/* quick select which is currently used for rows retrieval */
List_iterator_fast
<
QUICK_RANGE_SELECT
>
cur_quick_it
;
QUICK_RANGE_SELECT
*
cur_quick_select
;
/*
Last element in quick_selects list.
INDEX_MERGE::start_last_quick_select is called before retrieving
rows for it.
*/
QUICK_RANGE_SELECT
*
last_quick_select
;
/*
Used to keep track of what records have been already passed to output
when doing index_merge access (NULL means no index_merge)
*/
INDEX_MERGE
index_merge
;
MEM_ROOT
alloc
;
};
class
QUICK_SELECT_DESC
:
public
QUICK_RANGE_SELECT
{
public:
QUICK_SELECT_DESC
(
QUICK_SELECT
*
q
,
uint
used_key_parts
);
QUICK_SELECT_DESC
(
QUICK_
RANGE_
SELECT
*
q
,
uint
used_key_parts
);
int
get_next
();
bool
reverse_sorted
()
{
return
1
;
}
int
get_type
()
{
return
QS_TYPE_RANGE_DESC
;
}
private:
int
cmp_prev
(
QUICK_RANGE
*
range
);
bool
range_reads_after_key
(
QUICK_RANGE
*
range
);
...
...
@@ -114,7 +271,7 @@ private:
class
SQL_SELECT
:
public
Sql_alloc
{
public:
QUICK_SELECT
*
quick
;
// If quick-select used
QUICK_SELECT
_I
*
quick
;
// If quick-select used
COND
*
cond
;
// where condition
TABLE
*
head
;
IO_CACHE
file
;
// Positions to used records
...
...
@@ -134,7 +291,7 @@ class SQL_SELECT :public Sql_alloc {
ha_rows
limit
,
bool
force_quick_range
=
0
);
};
QUICK_SELECT
*
get_quick_select_for_ref
(
THD
*
thd
,
TABLE
*
table
,
QUICK_
RANGE_
SELECT
*
get_quick_select_for_ref
(
THD
*
thd
,
TABLE
*
table
,
struct
st_table_ref
*
ref
);
#endif
sql/sql_class.cc
View file @
30b3c3bf
...
...
@@ -575,8 +575,8 @@ int THD::send_explain_fields(select_result *result)
item
->
maybe_null
=
1
;
field_list
.
push_back
(
item
=
new
Item_empty_string
(
"key"
,
NAME_LEN
));
item
->
maybe_null
=
1
;
field_list
.
push_back
(
item
=
new
Item_
return_int
(
"key_len"
,
3
,
MYSQL_TYPE_LONGLONG
));
field_list
.
push_back
(
item
=
new
Item_
empty_string
(
"key_len"
,
NAME_LEN
*
MAX_KEY
));
item
->
maybe_null
=
1
;
field_list
.
push_back
(
item
=
new
Item_empty_string
(
"ref"
,
NAME_LEN
*
MAX_REF_PARTS
));
...
...
sql/sql_list.h
View file @
30b3c3bf
...
...
@@ -135,6 +135,12 @@ public:
last
=
&
first
;
return
tmp
->
info
;
}
inline
void
concat
(
base_list
*
list
)
{
*
last
=
list
->
first
;
last
=
list
->
last
;
elements
+=
list
->
elements
;
}
inline
list_node
*
last_node
()
{
return
*
last
;
}
inline
list_node
*
first_node
()
{
return
first
;}
inline
void
*
head
()
{
return
first
->
info
;
}
...
...
@@ -255,6 +261,7 @@ public:
}
empty
();
}
inline
void
concat
(
List
<
T
>
*
list
)
{
base_list
::
concat
(
list
);
}
};
...
...
sql/sql_select.cc
View file @
30b3c3bf
...
...
@@ -32,7 +32,8 @@
const
char
*
join_type_str
[]
=
{
"UNKNOWN"
,
"system"
,
"const"
,
"eq_ref"
,
"ref"
,
"MAYBE_REF"
,
"ALL"
,
"range"
,
"index"
,
"fulltext"
,
"ref_or_null"
,
"unique_subquery"
,
"index_subquery"
"ref_or_null"
,
"unique_subquery"
,
"index_subquery"
,
"index_merge"
};
const
key_map
key_map_empty
(
0
);
...
...
@@ -116,7 +117,7 @@ static int join_read_next_same_or_null(READ_RECORD *info);
static
COND
*
make_cond_for_table
(
COND
*
cond
,
table_map
table
,
table_map
used_table
);
static
Item
*
part_of_refkey
(
TABLE
*
form
,
Field
*
field
);
static
uint
find_shortest_key
(
TABLE
*
table
,
const
key_map
*
usable_keys
);
uint
find_shortest_key
(
TABLE
*
table
,
const
key_map
*
usable_keys
);
static
bool
test_if_skip_sort_order
(
JOIN_TAB
*
tab
,
ORDER
*
order
,
ha_rows
select_limit
,
bool
no_changes
);
static
int
create_sort_index
(
THD
*
thd
,
JOIN
*
join
,
ORDER
*
order
,
...
...
@@ -3417,7 +3418,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
with key reading */
if
(
tab
->
needed_reg
.
is_clear_all
()
&&
tab
->
type
!=
JT_EQ_REF
&&
tab
->
type
!=
JT_FT
&&
(
tab
->
type
!=
JT_REF
||
(
uint
)
tab
->
ref
.
key
==
tab
->
quick
->
index
))
(
uint
)
tab
->
ref
.
key
==
tab
->
quick
->
index
))
{
sel
->
quick
=
tab
->
quick
;
// Use value from get_quick_...
sel
->
quick_keys
.
clear_all
();
...
...
@@ -6745,7 +6746,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
return
reverse
;
}
static
uint
find_shortest_key
(
TABLE
*
table
,
const
key_map
*
usable_keys
)
uint
find_shortest_key
(
TABLE
*
table
,
const
key_map
*
usable_keys
)
{
uint
min_length
=
(
uint
)
~
0
;
uint
best
=
MAX_KEY
;
...
...
@@ -6879,6 +6880,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
else
if
(
select
&&
select
->
quick
)
// Range found by opt_range
{
/* assume results are not ordered when index merge is used */
if
(
select
->
quick
->
get_type
()
==
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
DBUG_RETURN
(
0
);
ref_key
=
select
->
quick
->
index
;
ref_key_parts
=
select
->
quick
->
used_key_parts
;
}
...
...
@@ -6913,6 +6917,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
else
{
/*
We have verified above that select->quick is not
index_merge quick select.
*/
select
->
quick
->
index
=
new_ref_key
;
select
->
quick
->
init
();
}
...
...
@@ -6934,10 +6942,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
if
(
!
select
->
quick
->
reverse_sorted
())
{
if
(
table
->
file
->
index_flags
(
ref_key
)
&
HA_NOT_READ_PREFIX_LAST
)
if
(
table
->
file
->
index_flags
(
ref_key
)
&
HA_NOT_READ_PREFIX_LAST
||
(
select
->
quick
->
get_type
()
==
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
))
DBUG_RETURN
(
0
);
// Use filesort
// ORDER BY range_key DESC
QUICK_SELECT_DESC
*
tmp
=
new
QUICK_SELECT_DESC
(
select
->
quick
,
// ORDER BY range_key DESC
QUICK_SELECT_DESC
*
tmp
=
new
QUICK_SELECT_DESC
((
QUICK_RANGE_SELECT
*
)(
select
->
quick
),
used_key_parts
);
if
(
!
tmp
||
tmp
->
error
)
{
...
...
@@ -7079,8 +7090,11 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
{
select
->
quick
=
tab
->
quick
;
tab
->
quick
=
0
;
/* We can only use 'Only index' if quick key is same as ref_key */
if
(
table
->
key_read
&&
(
uint
)
tab
->
ref
.
key
!=
select
->
quick
->
index
)
/*
We can only use 'Only index' if quick key is same as ref_key
and in index_merge 'Only index' cannot be used
*/
if
(
table
->
key_read
&&
((
uint
)
tab
->
ref
.
key
!=
select
->
quick
->
index
))
{
table
->
key_read
=
0
;
table
->
file
->
extra
(
HA_EXTRA_NO_KEYREAD
);
...
...
@@ -8880,12 +8894,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
JOIN_TAB
*
tab
=
join
->
join_tab
+
i
;
TABLE
*
table
=
tab
->
table
;
char
buff
[
512
],
*
buff_ptr
=
buff
;
char
buff1
[
512
],
buff2
[
512
];
char
buff1
[
512
],
buff2
[
512
],
buff3
[
512
];
char
keylen_str_buf
[
64
];
char
derived_name
[
64
];
String
tmp1
(
buff1
,
sizeof
(
buff1
),
cs
);
String
tmp2
(
buff2
,
sizeof
(
buff2
),
cs
);
String
tmp3
(
buff3
,
sizeof
(
buff3
),
cs
);
tmp1
.
length
(
0
);
tmp2
.
length
(
0
);
tmp3
.
length
(
0
);
item_list
.
empty
();
item_list
.
push_back
(
new
Item_int
((
int32
)
...
...
@@ -8894,7 +8911,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
strlen
(
join
->
select_lex
->
type
),
cs
));
if
(
tab
->
type
==
JT_ALL
&&
tab
->
select
&&
tab
->
select
->
quick
)
tab
->
type
=
JT_RANGE
;
{
if
(
tab
->
select
->
quick
->
get_type
()
==
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
tab
->
type
=
JT_INDEX_MERGE
;
else
tab
->
type
=
JT_RANGE
;
}
if
(
table
->
derived_select_number
)
{
/* Derived table name generation */
...
...
@@ -8930,10 +8953,14 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if
(
tab
->
ref
.
key_parts
)
{
KEY
*
key_info
=
table
->
key_info
+
tab
->
ref
.
key
;
register
uint
length
;
item_list
.
push_back
(
new
Item_string
(
key_info
->
name
,
strlen
(
key_info
->
name
),
system_charset_info
));
item_list
.
push_back
(
new
Item_int
((
int32
)
tab
->
ref
.
key_length
));
length
=
longlong2str
(
tab
->
ref
.
key_length
,
keylen_str_buf
,
10
)
-
keylen_str_buf
;
item_list
.
push_back
(
new
Item_string
(
keylen_str_buf
,
length
,
system_charset_info
));
for
(
store_key
**
ref
=
tab
->
ref
.
key_copy
;
*
ref
;
ref
++
)
{
if
(
tmp2
.
length
())
...
...
@@ -8945,18 +8972,60 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
else
if
(
tab
->
type
==
JT_NEXT
)
{
KEY
*
key_info
=
table
->
key_info
+
tab
->
index
;
register
uint
length
;
item_list
.
push_back
(
new
Item_string
(
key_info
->
name
,
strlen
(
key_info
->
name
),
cs
));
item_list
.
push_back
(
new
Item_int
((
int32
)
key_info
->
key_length
));
length
=
longlong2str
(
key_info
->
key_length
,
keylen_str_buf
,
10
)
-
keylen_str_buf
;
item_list
.
push_back
(
new
Item_string
(
keylen_str_buf
,
length
,
system_charset_info
));
item_list
.
push_back
(
item_null
);
}
else
if
(
tab
->
select
&&
tab
->
select
->
quick
)
{
KEY
*
key_info
=
table
->
key_info
+
tab
->
select
->
quick
->
index
;
item_list
.
push_back
(
new
Item_string
(
key_info
->
name
,
strlen
(
key_info
->
name
),
cs
));
item_list
.
push_back
(
new
Item_int
((
int32
)
tab
->
select
->
quick
->
max_used_key_length
));
if
(
tab
->
select
->
quick
->
get_type
()
==
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
{
QUICK_INDEX_MERGE_SELECT
*
quick_imerge
=
(
QUICK_INDEX_MERGE_SELECT
*
)
tab
->
select
->
quick
;
QUICK_RANGE_SELECT
*
quick
;
List_iterator_fast
<
QUICK_RANGE_SELECT
>
it
(
quick_imerge
->
quick_selects
);
while
((
quick
=
it
++
))
{
KEY
*
key_info
=
table
->
key_info
+
quick
->
index
;
register
uint
length
;
if
(
tmp3
.
length
())
tmp3
.
append
(
','
);
tmp3
.
append
(
key_info
->
name
);
if
(
tmp2
.
length
())
tmp2
.
append
(
','
);
length
=
longlong2str
(
quick
->
max_used_key_length
,
keylen_str_buf
,
10
)
-
keylen_str_buf
;
tmp2
.
append
(
keylen_str_buf
,
length
);
}
}
else
{
KEY
*
key_info
=
table
->
key_info
+
tab
->
select
->
quick
->
index
;
register
uint
length
;
tmp3
.
append
(
key_info
->
name
);
length
=
longlong2str
(
tab
->
select
->
quick
->
max_used_key_length
,
keylen_str_buf
,
10
)
-
keylen_str_buf
;
tmp2
.
append
(
keylen_str_buf
,
length
);
}
item_list
.
push_back
(
new
Item_string
(
tmp3
.
ptr
(),
tmp3
.
length
(),
cs
));
item_list
.
push_back
(
new
Item_string
(
tmp2
.
ptr
(),
tmp2
.
length
(),
cs
));
item_list
.
push_back
(
item_null
);
}
else
...
...
sql/sql_select.h
View file @
30b3c3bf
...
...
@@ -76,7 +76,7 @@ typedef struct st_join_cache {
enum
join_type
{
JT_UNKNOWN
,
JT_SYSTEM
,
JT_CONST
,
JT_EQ_REF
,
JT_REF
,
JT_MAYBE_REF
,
JT_ALL
,
JT_RANGE
,
JT_NEXT
,
JT_FT
,
JT_REF_OR_NULL
,
JT_UNIQUE_SUBQUERY
,
JT_INDEX_SUBQUERY
};
JT_UNIQUE_SUBQUERY
,
JT_INDEX_SUBQUERY
,
JT_INDEX_MERGE
};
class
JOIN
;
...
...
@@ -85,7 +85,7 @@ typedef struct st_join_table {
KEYUSE
*
keyuse
;
/* pointer to first used key */
SQL_SELECT
*
select
;
COND
*
select_cond
;
QUICK_SELECT
*
quick
;
QUICK_SELECT
_I
*
quick
;
Item
*
on_expr
;
const
char
*
info
;
byte
*
null_ref_key
;
...
...
@@ -311,6 +311,7 @@ void copy_fields(TMP_TABLE_PARAM *param);
void
copy_funcs
(
Item
**
func_ptr
);
bool
create_myisam_from_heap
(
THD
*
thd
,
TABLE
*
table
,
TMP_TABLE_PARAM
*
param
,
int
error
,
bool
ignore_last_dupp_error
);
uint
find_shortest_key
(
TABLE
*
table
,
key_map
usable_keys
);
/* functions from opt_sum.cc */
int
opt_sum_query
(
TABLE_LIST
*
tables
,
List
<
Item
>
&
all_fields
,
COND
*
conds
);
...
...
sql/sql_test.cc
View file @
30b3c3bf
...
...
@@ -181,9 +181,39 @@ TEST_join(JOIN *join)
" quick select checked for each record (keys: %s)
\n
"
,
tab
->
select
->
quick_keys
.
print
(
buf
));
else
if
(
tab
->
select
->
quick
)
fprintf
(
DBUG_FILE
,
" quick select used on key %s, length: %d
\n
"
,
{
int
quick_type
=
tab
->
select
->
quick
->
get_type
();
if
((
quick_type
==
QUICK_SELECT_I
::
QS_TYPE_RANGE
)
||
(
quick_type
==
QUICK_SELECT_I
::
QS_TYPE_RANGE_DESC
))
{
fprintf
(
DBUG_FILE
,
" quick select used on key %s, length: %d
\n
"
,
form
->
key_info
[
tab
->
select
->
quick
->
index
].
name
,
tab
->
select
->
quick
->
max_used_key_length
);
}
else
if
(
quick_type
==
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
{
QUICK_INDEX_MERGE_SELECT
*
quick_imerge
=
(
QUICK_INDEX_MERGE_SELECT
*
)
tab
->
select
->
quick
;
QUICK_RANGE_SELECT
*
quick
;
fprintf
(
DBUG_FILE
,
" index_merge quick select used
\n
"
);
List_iterator_fast
<
QUICK_RANGE_SELECT
>
it
(
quick_imerge
->
quick_selects
);
while
((
quick
=
it
++
))
{
fprintf
(
DBUG_FILE
,
" range quick select: key %s, length: %d
\n
"
,
form
->
key_info
[
quick
->
index
].
name
,
quick
->
max_used_key_length
);
}
}
else
{
fprintf
(
DBUG_FILE
,
" quick select of unknown nature used
\n
"
);
}
}
else
VOID
(
fputs
(
" select used
\n
"
,
DBUG_FILE
));
}
...
...
sql/sql_union.cc
View file @
30b3c3bf
...
...
@@ -117,7 +117,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
{
SELECT_LEX
*
lex_select_save
=
thd
->
lex
->
current_select
;
SELECT_LEX
*
select_cursor
,
*
sl
;
DBUG_ENTER
(
"st_select_lex_unit::prepare"
);
DBUG_ENTER
(
"st_select_lex_unit::prepare"
);
/*
result object should be reassigned even if preparing already done for
...
...
sql/sql_update.cc
View file @
30b3c3bf
...
...
@@ -177,10 +177,18 @@ int mysql_update(THD *thd,
init_ftfuncs
(
thd
,
&
thd
->
lex
->
select_lex
,
1
);
/* Check if we are modifying a key that we are used to search with */
if
(
select
&&
select
->
quick
)
used_key_is_modified
=
(
!
select
->
quick
->
unique_key_range
()
&&
check_if_key_used
(
table
,
(
used_index
=
select
->
quick
->
index
),
fields
));
{
if
(
select
->
quick
->
get_type
()
!=
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
{
used_index
=
select
->
quick
->
index
;
used_key_is_modified
=
(
!
select
->
quick
->
unique_key_range
()
&&
check_if_key_used
(
table
,
used_index
,
fields
));
}
else
{
used_key_is_modified
=
true
;
}
}
else
if
((
used_index
=
table
->
file
->
key_used_on_scan
)
<
MAX_KEY
)
used_key_is_modified
=
check_if_key_used
(
table
,
used_index
,
fields
);
else
...
...
@@ -698,8 +706,26 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
case
JT_ALL
:
/* If range search on index */
if
(
join_tab
->
quick
)
return
!
check_if_key_used
(
table
,
join_tab
->
quick
->
index
,
*
fields
);
{
if
(
join_tab
->
quick
->
get_type
()
!=
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
{
return
!
check_if_key_used
(
table
,
join_tab
->
quick
->
index
,
*
fields
);
}
else
{
QUICK_INDEX_MERGE_SELECT
*
qsel_imerge
=
(
QUICK_INDEX_MERGE_SELECT
*
)(
join_tab
->
quick
);
List_iterator_fast
<
QUICK_RANGE_SELECT
>
it
(
qsel_imerge
->
quick_selects
);
QUICK_RANGE_SELECT
*
quick
;
while
((
quick
=
it
++
))
{
if
(
check_if_key_used
(
table
,
quick
->
index
,
*
fields
))
return
0
;
}
return
1
;
}
}
/* If scanning in clustered key */
if
((
table
->
file
->
table_flags
()
&
HA_PRIMARY_KEY_IN_READ_INDEX
)
&&
table
->
primary_key
<
MAX_KEY
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment