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
f0dc1892
Commit
f0dc1892
authored
Jun 29, 2001
by
monty@hundin.mysql.fi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix ORDER BY ... DESC optimization
parent
545e596e
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
355 additions
and
84 deletions
+355
-84
Docs/manual.texi
Docs/manual.texi
+107
-14
mysql-test/r/order_by.result
mysql-test/r/order_by.result
+84
-24
mysql-test/t/order_by.test
mysql-test/t/order_by.test
+35
-8
sql/opt_range.cc
sql/opt_range.cc
+90
-22
sql/opt_range.h
sql/opt_range.h
+6
-4
sql/sql_delete.cc
sql/sql_delete.cc
+1
-5
sql/sql_select.cc
sql/sql_select.cc
+32
-7
No files found.
Docs/manual.texi
View file @
f0dc1892
...
@@ -410,6 +410,7 @@ MySQL Language Reference
...
@@ -410,6 +410,7 @@ MySQL Language Reference
* SET OPTION:: @code{SET OPTION} syntax
* SET OPTION:: @code{SET OPTION} syntax
* SET TRANSACTION:: @code{SET TRANSACTION} syntax
* SET TRANSACTION:: @code{SET TRANSACTION} syntax
* GRANT:: @code{GRANT} and @code{REVOKE} syntax
* GRANT:: @code{GRANT} and @code{REVOKE} syntax
* HANDLER:: @code{HANDLER} syntax
* CREATE INDEX:: @code{CREATE INDEX} syntax
* CREATE INDEX:: @code{CREATE INDEX} syntax
* DROP INDEX:: @code{DROP INDEX} syntax
* DROP INDEX:: @code{DROP INDEX} syntax
* Comments:: Comment syntax
* Comments:: Comment syntax
...
@@ -664,6 +665,7 @@ Replication in MySQL
...
@@ -664,6 +665,7 @@ Replication in MySQL
MySQL Full-text Search
MySQL Full-text Search
* Fulltext Search::
* Fulltext Fine-tuning::
* Fulltext Fine-tuning::
* Fulltext Features to Appear in MySQL 4.0::
* Fulltext Features to Appear in MySQL 4.0::
* Fulltext TODO::
* Fulltext TODO::
...
@@ -14139,6 +14141,7 @@ to restart @code{mysqld} with @code{--skip-grant-tables} to run
...
@@ -14139,6 +14141,7 @@ to restart @code{mysqld} with @code{--skip-grant-tables} to run
* SET OPTION:: @code{SET OPTION} syntax
* SET OPTION:: @code{SET OPTION} syntax
* SET TRANSACTION:: @code{SET TRANSACTION} syntax
* SET TRANSACTION:: @code{SET TRANSACTION} syntax
* GRANT:: @code{GRANT} and @code{REVOKE} syntax
* GRANT:: @code{GRANT} and @code{REVOKE} syntax
* HANDLER:: @code{HANDLER} syntax
* CREATE INDEX:: @code{CREATE INDEX} syntax
* CREATE INDEX:: @code{CREATE INDEX} syntax
* DROP INDEX:: @code{DROP INDEX} syntax
* DROP INDEX:: @code{DROP INDEX} syntax
* Comments:: Comment syntax
* Comments:: Comment syntax
...
@@ -19410,6 +19413,8 @@ alter_specification:
...
@@ -19410,6 +19413,8 @@ alter_specification:
or DROP [COLUMN] col_name
or DROP [COLUMN] col_name
or DROP PRIMARY KEY
or DROP PRIMARY KEY
or DROP INDEX index_name
or DROP INDEX index_name
or DISABLE KEYS
or ENABLE KEYS
or RENAME [TO] new_tbl_name
or RENAME [TO] new_tbl_name
or ORDER BY col
or ORDER BY col
or table_options
or table_options
...
@@ -19571,6 +19576,15 @@ If you use @code{ALTER TABLE} on a @code{MyISAM} table, all non-unique
...
@@ -19571,6 +19576,15 @@ If you use @code{ALTER TABLE} on a @code{MyISAM} table, all non-unique
indexes are created in a separate batch (like in @code{REPAIR}).
indexes are created in a separate batch (like in @code{REPAIR}).
This should make @code{ALTER TABLE} much faster when you have many indexes.
This should make @code{ALTER TABLE} much faster when you have many indexes.
@item
Since @strong{MySQL 4.0} this feature could be activated explicitly.
@code{ALTER TABLE ... DISABLE KEYS} makes @strong{MySQL} to stop updating
non-unique indexes for @code{MyISAM} table.
@code{ALTER TABLE ... ENABLE KEYS} then should be used to recreate missing
indexes. As @strong{MySQL} does it with special algorithm which is much
faster then inserting keys one by one, disabling keys could give a
considerable speedup on bulk inserts.
@item
@item
@findex mysql_info()
@findex mysql_info()
With the C API function @code{mysql_info()}, you can find out how many
With the C API function @code{mysql_info()}, you can find out how many
...
@@ -21880,6 +21894,9 @@ differ somewhat:
...
@@ -21880,6 +21894,9 @@ differ somewhat:
| delayed_queue_size | 1000 |
| delayed_queue_size | 1000 |
| flush | OFF |
| flush | OFF |
| flush_time | 0 |
| flush_time | 0 |
| ft_min_word_len | 4 |
| ft_max_word_len | 254 |
| ft_max_word_len_for_sort| 20 |
| have_bdb | YES |
| have_bdb | YES |
| have_gemini | NO |
| have_gemini | NO |
| have_innodb | YES |
| have_innodb | YES |
...
@@ -22063,6 +22080,31 @@ tables will be closed (to free up resources and sync things to disk). We
...
@@ -22063,6 +22080,31 @@ tables will be closed (to free up resources and sync things to disk). We
only recommend this option on Win95, Win98, or on systems where you have
only recommend this option on Win95, Win98, or on systems where you have
very little resources.
very little resources.
@item @code{ft_min_word_len}
The minimum length of the word to be included in a @code{FULLTEXT} index.
@strong{Note: @code{FULLTEXT} index have to be rebuilt (e.g. with
@code{OPTIMIZE TABLE}) after changing this variable.}
@item @code{ft_max_word_len}
The maximum length of the word to be included in a @code{FULLTEXT} index.
@strong{Note: @code{FULLTEXT} index have to be rebuilt after changing
this variable.}
@item @code{ft_max_word_len_sort}
The maximum length of the word in a @code{FULLTEXT} index
to be used in fast index recreation method in
@code{REPAIR}, @code{CREATE INDEX}, @code{OPTIMIZE TABLE}, or
@code{ALTER TABLE}. Longer words are inserted the slow way.
The rule of the thumb is as follows: with @code{ft_max_word_len_sort}
increasing, @strong{MySQL} will create bigger temporary files
(thus slowing the process down, due to disk I/O), and will put
fewer keys in one sort block (againg, decreasing the efficiency).
When @code{ft_max_word_len_sort} is too small, instead,
@strong{MySQL} will insert a lot of words into index the slow way -
but short words will be inserted very fast. It applies only to
index recreation during @code{REPAIR}, @code{CREATE INDEX},
@code{OPTIMIZE TABLE}, or @code{ALTER TABLE}.
@item @code{have_bdb}
@item @code{have_bdb}
@code{YES} if @code{mysqld} supports Berkeley DB tables. @code{DISABLED}
@code{YES} if @code{mysqld} supports Berkeley DB tables. @code{DISABLED}
if @code{--skip-bdb} is used.
if @code{--skip-bdb} is used.
...
@@ -23156,7 +23198,7 @@ You can set the default isolation level for @code{mysqld} with
...
@@ -23156,7 +23198,7 @@ You can set the default isolation level for @code{mysqld} with
@findex GRANT
@findex GRANT
@findex REVOKE
@findex REVOKE
@node GRANT,
CREATE INDEX
, SET TRANSACTION, Reference
@node GRANT,
HANDLER
, SET TRANSACTION, Reference
@section @code{GRANT} and @code{REVOKE} Syntax
@section @code{GRANT} and @code{REVOKE} Syntax
@example
@example
...
@@ -23386,11 +23428,52 @@ dropped only with explicit @code{REVOKE} commands or by manipulating the
...
@@ -23386,11 +23428,52 @@ dropped only with explicit @code{REVOKE} commands or by manipulating the
@strong{MySQL} grant tables.
@strong{MySQL} grant tables.
@end itemize
@end itemize
@findex HANDLER
@node HANDLER, CREATE INDEX, GRANT, Reference
@section @code{HANDLER} Syntax
@example
HANDLER table OPEN [ AS alias ]
HANDLER table READ index @{ = | >= | <= | < @} (value1, value2, ... ) [ WHERE ... ] [LIMIT ... ]
HANDLER table READ index @{ FIRST | NEXT | PREV | LAST @} [ WHERE ... ] [LIMIT ... ]
HANDLER table READ @{ FIRST | NEXT @} [ WHERE ... ] [LIMIT ... ]
HANDLER table CLOSE
@end example
The @code{HANDLER} statement provides direct access to @strong{MySQL} table
interface, bypassing SQL optimizer. Thus, it is faster then SELECT.
The first form of @code{HANDLER} statement opens a table, making
in accessible via the following @code{HANDLER ... READ} routines.
The second form fetches one (or, specified by @code{LIMIT} clause) row
where the index specified complies to the condition and @code{WHERE}
condition is met. If the index consists of several parts (spans over
several columns) the values are specified in comma-separated list,
providing values only for few first columns is possible.
The third form fetches one (or, specified by @code{LIMIT} clause) row
from the table in index order, matching @code{WHERE} condition.
The fourth form (without index specification) fetches one (or, specified
by @code{LIMIT} clause) row from the table in natural row order (as stored
in data file) matching @code{WHERE} condition. It is faster than
@code{HANDLER table READ index} when full table scan is desired.
The last form closes the table, opened with @code{HANDLER ... OPEN}.
@code{HANDLER} is somewhat low-level statement, for example it does not
provide consistency. That is @code{HANDLER ... OPEN} does @strong{not}
takes a snapshot of the table, and does @strong{not} locks the table. The
above means, that after @code{HANDLER ... OPEN} table data can be
modified (by this or other thread) and these modifications may appear only
partially in @code{HANDLER ... NEXT} or @code{HANDLER ... PREV} scans.
@cindex indexes
@cindex indexes
@cindex indexes, multi-part
@cindex indexes, multi-part
@cindex multi-part index
@cindex multi-part index
@findex CREATE INDEX
@findex CREATE INDEX
@node CREATE INDEX, DROP INDEX,
GRANT
, Reference
@node CREATE INDEX, DROP INDEX,
HANDLER
, Reference
@section @code{CREATE INDEX} Syntax
@section @code{CREATE INDEX} Syntax
@example
@example
...
@@ -30809,13 +30892,10 @@ unless you know what you are doing!
...
@@ -30809,13 +30892,10 @@ unless you know what you are doing!
@itemize
@itemize
@item
@item
Minimal length of word to be indexed is defined in
Minimal length of word to be indexed is defined by @strong{MySQL}
@code{myisam/ftdefs.h} file by the line
variable @code{ft_min_word_length}. @xref{SHOW VARIABLES}.
@example
Change it to the value you prefer, and rebuild
#define MIN_WORD_LEN 4
your @code{FULLTEXT} indexes (e.g. with @code{OPTIMIZE TABLE}).
@end example
Change it to the value you prefer, recompile @strong{MySQL}, and rebuild
your @code{FULLTEXT} indexes.
@item
@item
The stopword list is defined in @code{myisam/ft_static.c}
The stopword list is defined in @code{myisam/ft_static.c}
...
@@ -30881,9 +30961,6 @@ index operations (querying/dumping/statistics).
...
@@ -30881,9 +30961,6 @@ index operations (querying/dumping/statistics).
@itemize @bullet
@itemize @bullet
@item Make all operations with @code{FULLTEXT} index @strong{faster}.
@item Make all operations with @code{FULLTEXT} index @strong{faster}.
@item Support for braces @code{()} in boolean full-text search.
@item Support for braces @code{()} in boolean full-text search.
@item Phrase search, proximity operators
@item Boolean search can work without @code{FULLTEXT} index
(yes, @strong{very} slow).
@item Support for "always-index words". They could be any strings
@item Support for "always-index words". They could be any strings
the user wants to treat as words, examples are "C++", "AS/400", "TCP/IP", etc.
the user wants to treat as words, examples are "C++", "AS/400", "TCP/IP", etc.
@item Support for full-text search in @code{MERGE} tables.
@item Support for full-text search in @code{MERGE} tables.
...
@@ -32543,8 +32620,12 @@ Execute a @code{FLUSH TABLES} statement or the shell command @code{mysqladmin
...
@@ -32543,8 +32620,12 @@ Execute a @code{FLUSH TABLES} statement or the shell command @code{mysqladmin
flush-tables}.
flush-tables}.
@end enumerate
@end enumerate
This procedure will be built into @code{LOAD DATA INFILE} in some future
Since @strong{MySQL 4.0} you can also use
version of @strong{MySQL}.
@code{ALTER TABLE tbl_name DISABLE KEYS} instead of
@code{myisamchk --keys-used=0 -rq /path/to/db/tbl_name} and
@code{ALTER TABLE tbl_name ENABLE KEYS} instead of
@code{myisamchk -r -q /path/to/db/tbl_name}. This way you can also skip
@code{FLUSH TABLES} steps.
@item
@item
You can speed up insertions by locking your tables:
You can speed up insertions by locking your tables:
...
@@ -46004,6 +46085,8 @@ Responsible for @strong{MySQL} configure.
...
@@ -46004,6 +46085,8 @@ Responsible for @strong{MySQL} configure.
Full-text search.
Full-text search.
@item
@item
Added keys to the @code{MERGE} library.
Added keys to the @code{MERGE} library.
@item
@code{HANDLER} command.
@end itemize
@end itemize
@item Jeremy Cole
@item Jeremy Cole
...
@@ -46344,6 +46427,11 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
...
@@ -46344,6 +46427,11 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
@itemize @bullet
@itemize @bullet
@item
@item
Added @code{ALTER TABLE table_name DISABLE KEYS} and
@code{ALTER TABLE table_name ENABLE KEYS} commands.
@item
@code{LOAD DATA FROM MASTER} "auto-magically" sets up a slave.
@item
Renamed @code{safe_mysqld} to @code{mysqld_safe}.
Renamed @code{safe_mysqld} to @code{mysqld_safe}.
@item
@item
Allow one to use @code{IN} instead of @code{FROM} in @code{SHOW} commands.
Allow one to use @code{IN} instead of @code{FROM} in @code{SHOW} commands.
...
@@ -46471,6 +46559,9 @@ not yet 100% confident in this code.
...
@@ -46471,6 +46559,9 @@ not yet 100% confident in this code.
@appendixsubsec Changes in release 3.23.40
@appendixsubsec Changes in release 3.23.40
@itemize @bullet
@itemize @bullet
@item
@item
Added option @code{--warnings} to @code{mysqld}. Now @code{mysqld}
only prints the error @code{Aborted connection} if this option is used.
@item
Fixed parser to allow floats of type @code{1.0e1} (no sign after @code{e}).
Fixed parser to allow floats of type @code{1.0e1} (no sign after @code{e}).
@item
@item
Option @code{--force} to @code{myisamchk} now also updates states.
Option @code{--force} to @code{myisamchk} now also updates states.
...
@@ -51899,6 +51990,8 @@ Multiple result sets.
...
@@ -51899,6 +51990,8 @@ Multiple result sets.
Change the protocol to allow binary transfer of values. To do this
Change the protocol to allow binary transfer of values. To do this
efficiently, we need to add an API to allow binding of variables.
efficiently, we need to add an API to allow binding of variables.
@item
@item
Add @code{PREPARE} of statements and sending of parameters to @code{mysqld}.
@item
Make it possible to specify @code{long_query_time} with a granularity
Make it possible to specify @code{long_query_time} with a granularity
in microseconds.
in microseconds.
@item
@item
mysql-test/r/order_by.result
View file @
f0dc1892
...
@@ -112,58 +112,118 @@ member_id nickname voornaam
...
@@ -112,58 +112,118 @@ member_id nickname voornaam
1
1
2
2
table type possible_keys key key_len ref rows Extra
table type possible_keys key key_len ref rows Extra
t1
index NULL a 20 NULL 10
Using index
t1
range a a 20 NULL 2 where used;
Using index
a b c
a b c
1 NULL NULL
1 NULL b
1 NULL b
table type possible_keys key key_len ref rows Extra
t1 range a a 4 NULL 10 where used; Using index
a b c
2 3 c
2 2 b
2 2 a
2 1 b
2 1 a
1 3 b
1 1 b
1 1 b
1 1 NULL
1 NULL b
1 NULL NULL
table type possible_keys key key_len ref rows Extra
t1 ref a a 4 const 5 where used; Using index; Using filesort
a b c
1 3 b
1 1 NULL
1 1 NULL
1 1 b
1 1 b
1 1 b
1 1 b
2 0 a
1 NULL NULL
2 0 b
1 NULL b
table type possible_keys key key_len ref rows Extra
t1 ref a a 9 const,const 2 where used; Using index; Using filesort
a b c
1 NULL NULL
1 NULL b
table type possible_keys key key_len ref rows Extra
t1 range a a 9 NULL 8 where used; Using index; Using filesort
table type possible_keys key key_len ref rows Extra
t1 range a a 9 NULL 5 where used; Using index
table type possible_keys key key_len ref rows Extra
t1 ref a a 9 const,const 1 where used; Using index; Using filesort
table type possible_keys key key_len ref rows Extra
t1 range a a 9 NULL 6 where used; Using index
table type possible_keys key key_len ref rows Extra
t1 range a a 9 NULL 5 where used; Using index
table type possible_keys key key_len ref rows Extra
t1 range a a 9 NULL 2 where used; Using index; Using filesort
table type possible_keys key key_len ref rows Extra
t1 index NULL a 18 NULL 11 Using index
a b c
1 0
1 0 b
1 1
1 1 b
1 1 b
1 3 b
2 1 a
2 1 a
2 1 b
2 1 b
2 1 c
2 2 a
2 2 b
2 3 c
table type possible_keys key key_len ref rows Extra
table type possible_keys key key_len ref rows Extra
t1 index NULL a
20 NULL 10
Using index
t1 index NULL a
18 NULL 11
Using index
a b c
a b c
2 1 c
2 3 c
2 2 b
2 2 a
2 1 b
2 1 b
2 1 a
2 1 a
2 0 b
1 3 b
2 0 a
1 1 b
1 1 b
1 1 b
1 1 b
1 1
NULL
1 1
1
NULL
b
1
0
b
1
NULL NULL
1
0
table type possible_keys key key_len ref rows Extra
table type possible_keys key key_len ref rows Extra
t1 range a a
20 NULL 2
where used; Using index
t1 range a a
18 NULL 3
where used; Using index
a b c
a b c
1 1 b
1 1 b
1 1 b
1 1 b
table type possible_keys key key_len ref rows Extra
table type possible_keys key key_len ref rows Extra
t1 range a a 4 NULL
5
where used; Using index
t1 range a a 4 NULL
6
where used; Using index
a b c
a b c
1 1 b
1 1 b
1 1 b
1 1 b
1 1 NULL
1 1
1 0 b
1 0
count(*)
9
a b c
2 3 c
2 2 b
2 2 a
2 1 b
2 1 a
1 3 b
1 1 b
1 1 b
1 1
table type possible_keys key key_len ref rows Extra
table type possible_keys key key_len ref rows Extra
t1 range a a
9 NULL 7
where used; Using index
t1 range a a
8 NULL 10
where used; Using index
a b c
a b c
2 1 c
2 1 b
2 1 b
2 1 a
2 1 a
2 0 b
2 0 a
1 1 b
1 1 b
1 1 b
1 1 b
1 1 NULL
1 1
1 0 b
1 0
table type possible_keys key key_len ref rows Extra
table type possible_keys key key_len ref rows Extra
t1 range a a 4 NULL
4
where used; Using index
t1 range a a 4 NULL
5
where used; Using index
a b c
a b c
1 3 b
1 1 b
1 1 b
1 1 b
1 1 b
1 1
NULL
1 1
1
NULL
b
1
0
b
1
NULL NULL
1
0
mysql-test/t/order_by.test
View file @
f0dc1892
...
@@ -168,8 +168,8 @@ drop table t1,t2,t3;
...
@@ -168,8 +168,8 @@ drop table t1,t2,t3;
#bug reported by Wouter de Jong
#bug reported by Wouter de Jong
drop
table
if
exists
members
;
drop
table
if
exists
t1
;
CREATE
TABLE
members
(
CREATE
TABLE
t1
(
member_id
int
(
11
)
NOT
NULL
auto_increment
,
member_id
int
(
11
)
NOT
NULL
auto_increment
,
inschrijf_datum
varchar
(
20
)
NOT
NULL
default
''
,
inschrijf_datum
varchar
(
20
)
NOT
NULL
default
''
,
lastchange_datum
varchar
(
20
)
NOT
NULL
default
''
,
lastchange_datum
varchar
(
20
)
NOT
NULL
default
''
,
...
@@ -200,24 +200,51 @@ CREATE TABLE members (
...
@@ -200,24 +200,51 @@ CREATE TABLE members (
PRIMARY
KEY
(
member_id
)
PRIMARY
KEY
(
member_id
)
)
TYPE
=
MyISAM
PACK_KEYS
=
1
;
)
TYPE
=
MyISAM
PACK_KEYS
=
1
;
insert
into
members
(
member_id
)
values
(
1
),(
2
),(
3
);
insert
into
t1
(
member_id
)
values
(
1
),(
2
),(
3
);
select
member_id
,
nickname
,
voornaam
FROM
members
select
member_id
,
nickname
,
voornaam
FROM
t1
ORDER
by
lastchange_datum
DESC
LIMIT
2
;
ORDER
by
lastchange_datum
DESC
LIMIT
2
;
drop
table
members
;
drop
table
t1
;
#
# Test optimization of ORDER BY DESC
#
create
table
t1
(
a
int
not
null
,
b
int
,
c
varchar
(
10
),
key
(
a
,
b
,
c
));
create
table
t1
(
a
int
not
null
,
b
int
,
c
varchar
(
10
),
key
(
a
,
b
,
c
));
insert
into
t1
values
(
1
,
NULL
,
NULL
),
(
1
,
NULL
,
'b'
),
(
1
,
1
,
NULL
),
(
1
,
1
,
'b'
),
(
1
,
1
,
'b'
),
(
2
,
0
,
'a'
),
(
2
,
0
,
'b'
),
(
2
,
1
,
'a'
),
(
2
,
1
,
'b'
),
(
2
,
1
,
'c'
);
insert
into
t1
values
(
1
,
NULL
,
NULL
),
(
1
,
NULL
,
'b'
),
(
1
,
1
,
NULL
),
(
1
,
1
,
'b'
),
(
1
,
1
,
'b'
),
(
2
,
1
,
'a'
),
(
2
,
1
,
'b'
),
(
2
,
2
,
'a'
),
(
2
,
2
,
'b'
),
(
2
,
3
,
'c'
),(
1
,
3
,
'b'
);
explain
select
*
from
t1
where
(
a
=
1
and
b
is
null
and
c
=
'b'
)
or
(
a
>
2
)
order
by
a
desc
;
select
*
from
t1
where
(
a
=
1
and
b
is
null
and
c
=
'b'
)
or
(
a
>
2
)
order
by
a
desc
;
explain
select
*
from
t1
where
a
>=
1
and
a
<
3
order
by
a
desc
;
select
*
from
t1
where
a
>=
1
and
a
<
3
order
by
a
desc
;
explain
select
*
from
t1
where
a
=
1
order
by
a
desc
,
b
desc
;
select
*
from
t1
where
a
=
1
order
by
a
desc
,
b
desc
;
explain
select
*
from
t1
where
a
=
1
and
b
is
null
order
by
a
desc
,
b
desc
;
select
*
from
t1
where
a
=
1
and
b
is
null
order
by
a
desc
,
b
desc
;
explain
select
*
from
t1
where
a
>=
1
and
a
<
3
and
b
>
0
order
by
a
desc
,
b
desc
;
explain
select
*
from
t1
where
a
=
2
and
b
>
0
order
by
a
desc
,
b
desc
;
explain
select
*
from
t1
where
a
=
2
and
b
is
null
order
by
a
desc
,
b
desc
;
explain
select
*
from
t1
where
a
=
2
and
(
b
is
null
or
b
>
0
)
order
by
a
desc
,
b
desc
;
explain
select
*
from
t1
where
a
=
2
and
b
>
0
order
by
a
desc
,
b
desc
;
explain
select
*
from
t1
where
a
=
2
and
b
<
2
order
by
a
desc
,
b
desc
;
#
# Test things when we don't have NULL keys
#
alter
table
t1
modify
b
int
not
null
,
modify
c
varchar
(
10
)
not
null
;
explain
select
*
from
t1
order
by
a
,
b
,
c
;
explain
select
*
from
t1
order
by
a
,
b
,
c
;
select
*
from
t1
order
by
a
,
b
,
c
;
select
*
from
t1
order
by
a
,
b
,
c
;
explain
select
*
from
t1
order
by
a
desc
,
b
desc
,
c
desc
;
explain
select
*
from
t1
order
by
a
desc
,
b
desc
,
c
desc
;
select
*
from
t1
order
by
a
desc
,
b
desc
,
c
desc
;
select
*
from
t1
order
by
a
desc
,
b
desc
,
c
desc
;
# test multiple ranges, NO_MAX_RANGE and EQ_RANGE
# test multiple ranges, NO_MAX_RANGE and EQ_RANGE
explain
select
*
from
t1
where
(
a
=
1
and
b
is
null
and
c
=
'b'
)
or
(
a
>
2
)
order
by
a
desc
;
explain
select
*
from
t1
where
(
a
=
1
and
b
=
1
and
c
=
'b'
)
or
(
a
>
2
)
order
by
a
desc
;
select
*
from
t1
where
(
a
=
1
and
b
=
1
and
c
=
'b'
)
or
(
a
>
2
)
order
by
a
desc
;
select
*
from
t1
where
(
a
=
1
and
b
=
1
and
c
=
'b'
)
or
(
a
>
2
)
order
by
a
desc
;
# test NEAR_MAX, NO_MIN_RANGE
# test NEAR_MAX, NO_MIN_RANGE
explain
select
*
from
t1
where
a
<
2
and
b
<=
1
order
by
a
desc
,
b
desc
;
explain
select
*
from
t1
where
a
<
2
and
b
<=
1
order
by
a
desc
,
b
desc
;
select
*
from
t1
where
a
<
2
and
b
<=
1
order
by
a
desc
,
b
desc
;
select
*
from
t1
where
a
<
2
and
b
<=
1
order
by
a
desc
,
b
desc
;
select
count
(
*
)
from
t1
where
a
<
5
and
b
>
0
;
select
*
from
t1
where
a
<
5
and
b
>
0
order
by
a
desc
,
b
desc
;
# test HA_READ_AFTER_KEY (at the end of the file), NEAR_MIN
# test HA_READ_AFTER_KEY (at the end of the file), NEAR_MIN
explain
select
*
from
t1
where
a
between
1
and
3
and
b
<=
1
order
by
a
desc
,
b
desc
;
explain
select
*
from
t1
where
a
between
1
and
3
and
b
<=
1
order
by
a
desc
,
b
desc
;
select
*
from
t1
where
a
between
1
and
3
and
b
<=
1
order
by
a
desc
,
b
desc
;
select
*
from
t1
where
a
between
1
and
3
and
b
<=
1
order
by
a
desc
,
b
desc
;
...
@@ -226,4 +253,4 @@ explain select * from t1 where a between 0 and 1 order by a desc, b desc;
...
@@ -226,4 +253,4 @@ explain select * from t1 where a between 0 and 1 order by a desc, b desc;
select
*
from
t1
where
a
between
0
and
1
order
by
a
desc
,
b
desc
;
select
*
from
t1
where
a
between
0
and
1
order
by
a
desc
,
b
desc
;
drop
table
t1
;
drop
table
t1
;
/* vim:set ft=sql sw=2 noet: */
sql/opt_range.cc
View file @
f0dc1892
...
@@ -382,7 +382,7 @@ SQL_SELECT::~SQL_SELECT()
...
@@ -382,7 +382,7 @@ SQL_SELECT::~SQL_SELECT()
#undef index // Fix for Unixware 7
#undef index // Fix for Unixware 7
QUICK_SELECT
::
QUICK_SELECT
(
TABLE
*
table
,
uint
key_nr
,
bool
no_alloc
)
QUICK_SELECT
::
QUICK_SELECT
(
TABLE
*
table
,
uint
key_nr
,
bool
no_alloc
)
:
error
(
0
),
index
(
key_nr
),
max_used_key_length
(
0
),
head
(
table
),
:
dont_free
(
0
),
error
(
0
),
index
(
key_nr
),
max_used_key_length
(
0
),
head
(
table
),
it
(
ranges
),
range
(
0
)
it
(
ranges
),
range
(
0
)
{
{
if
(
!
no_alloc
)
if
(
!
no_alloc
)
...
@@ -399,8 +399,11 @@ QUICK_SELECT::QUICK_SELECT(TABLE *table,uint key_nr,bool no_alloc)
...
@@ -399,8 +399,11 @@ QUICK_SELECT::QUICK_SELECT(TABLE *table,uint key_nr,bool no_alloc)
QUICK_SELECT
::~
QUICK_SELECT
()
QUICK_SELECT
::~
QUICK_SELECT
()
{
{
file
->
index_end
();
if
(
!
dont_free
)
free_root
(
&
alloc
,
MYF
(
0
));
{
file
->
index_end
();
free_root
(
&
alloc
,
MYF
(
0
));
}
}
}
int
QUICK_SELECT
::
init
()
int
QUICK_SELECT
::
init
()
...
@@ -2516,6 +2519,7 @@ int QUICK_SELECT::cmp_next(QUICK_RANGE *range)
...
@@ -2516,6 +2519,7 @@ int QUICK_SELECT::cmp_next(QUICK_RANGE *range)
return
(
range
->
flag
&
NEAR_MAX
)
?
1
:
0
;
// Exact match
return
(
range
->
flag
&
NEAR_MAX
)
?
1
:
0
;
// Exact match
}
}
/*
/*
* This is a hack: we inherit from QUICK_SELECT so that we can use the
* This is a hack: we inherit from QUICK_SELECT so that we can use the
* get_next() interface, but we have to hold a pointer to the original
* get_next() interface, but we have to hold a pointer to the original
...
@@ -2525,29 +2529,44 @@ int QUICK_SELECT::cmp_next(QUICK_RANGE *range)
...
@@ -2525,29 +2529,44 @@ int QUICK_SELECT::cmp_next(QUICK_RANGE *range)
* which handle the ranges and implement the get_next() function. But
* which handle the ranges and implement the get_next() function. But
* for now, this seems to work right at least.
* for now, this seems to work right at least.
*/
*/
QUICK_SELECT_DESC
::
QUICK_SELECT_DESC
(
QUICK_SELECT
*
q
)
:
QUICK_SELECT
(
*
q
),
quick
(
q
),
rev_it
(
rev_ranges
)
QUICK_SELECT_DESC
::
QUICK_SELECT_DESC
(
QUICK_SELECT
*
q
,
uint
used_key_parts
)
:
QUICK_SELECT
(
*
q
),
rev_it
(
rev_ranges
)
{
{
bool
not_read_after_key
=
file
->
option_flag
()
&
HA_NOT_READ_AFTER_KEY
;
bool
not_read_after_key
=
file
->
option_flag
()
&
HA_NOT_READ_AFTER_KEY
;
for
(
QUICK_RANGE
*
r
=
it
++
;
r
;
r
=
it
++
)
for
(
QUICK_RANGE
*
r
=
it
++
;
r
;
r
=
it
++
)
{
{
rev_ranges
.
push_front
(
r
);
rev_ranges
.
push_front
(
r
);
if
(
not_read_after_key
&&
range_reads_after_key
(
r
))
if
(
not_read_after_key
&&
range_reads_after_key
(
r
)
||
test_if_null_range
(
r
,
used_key_parts
))
{
{
it
.
rewind
();
// Reset range
error
=
HA_ERR_UNSUPPORTED
;
error
=
HA_ERR_UNSUPPORTED
;
break
;
dont_free
=
1
;
// Don't free memory from 'q'
return
;
}
}
}
}
/* Remove EQ_RANGE flag for keys that are not using the full key */
for
(
QUICK_RANGE
*
r
=
rev_it
++
;
r
;
r
=
rev_it
++
)
{
if
((
r
->
flag
&
EQ_RANGE
)
&&
head
->
key_info
[
index
].
key_length
!=
r
->
max_length
)
r
->
flag
&=
~
EQ_RANGE
;
}
rev_it
.
rewind
();
q
->
dont_free
=
1
;
// Don't free shared mem
delete
q
;
}
}
int
QUICK_SELECT_DESC
::
get_next
()
int
QUICK_SELECT_DESC
::
get_next
()
{
{
DBUG_ENTER
(
"QUICK_SELECT_DESC::get_next"
);
DBUG_ENTER
(
"QUICK_SELECT_DESC::get_next"
);
/* The max key is handled as follows:
/* The max key is handled as follows:
* - if there is NO_MAX_RANGE, start at the end and move backwards
* - if there is NO_MAX_RANGE, start at the end and move backwards
* - if it is an EQ_RANGE
and max key covers the entire key, go directly
* - if it is an EQ_RANGE
, which means that max key covers the entire
* to the key and read through it (sorting backwards is
*
key, go directly
to the key and read through it (sorting backwards is
* same as sorting forwards)
* same as sorting forwards)
* - if it is NEAR_MAX, go to the key or next, step back once, and
* - if it is NEAR_MAX, go to the key or next, step back once, and
* move backwards
* move backwards
...
@@ -2560,9 +2579,9 @@ int QUICK_SELECT_DESC::get_next()
...
@@ -2560,9 +2579,9 @@ int QUICK_SELECT_DESC::get_next()
int
result
;
int
result
;
if
(
range
)
if
(
range
)
{
// Already read through key
{
// Already read through key
result
=
((
range
->
flag
&
EQ_RANGE
)
?
result
=
((
range
->
flag
&
EQ_RANGE
)
file
->
index_next_same
(
record
,
(
byte
*
)
range
->
min_key
,
?
file
->
index_next_same
(
record
,
(
byte
*
)
range
->
min_key
,
range
->
min_length
)
:
range
->
min_length
)
:
file
->
index_prev
(
record
));
file
->
index_prev
(
record
));
if
(
!
result
)
if
(
!
result
)
{
{
...
@@ -2587,8 +2606,7 @@ int QUICK_SELECT_DESC::get_next()
...
@@ -2587,8 +2606,7 @@ int QUICK_SELECT_DESC::get_next()
continue
;
continue
;
}
}
if
(
range
->
flag
&
EQ_RANGE
&&
if
(
range
->
flag
&
EQ_RANGE
)
head
->
key_info
[
index
].
key_length
==
range
->
max_length
)
{
{
result
=
file
->
index_read
(
record
,
(
byte
*
)
range
->
max_key
,
result
=
file
->
index_read
(
record
,
(
byte
*
)
range
->
max_key
,
range
->
max_length
,
HA_READ_KEY_EXACT
);
range
->
max_length
,
HA_READ_KEY_EXACT
);
...
@@ -2598,9 +2616,10 @@ int QUICK_SELECT_DESC::get_next()
...
@@ -2598,9 +2616,10 @@ int QUICK_SELECT_DESC::get_next()
dbug_assert
(
range
->
flag
&
NEAR_MAX
||
range_reads_after_key
(
range
));
dbug_assert
(
range
->
flag
&
NEAR_MAX
||
range_reads_after_key
(
range
));
/* Note: even if max_key is only a prefix, HA_READ_AFTER_KEY will
/* Note: even if max_key is only a prefix, HA_READ_AFTER_KEY will
* do the right thing - go past all keys which match the prefix */
* do the right thing - go past all keys which match the prefix */
file
->
index_read
(
record
,
(
byte
*
)
range
->
max_key
,
range
->
max_length
,
result
=
file
->
index_read
(
record
,
(
byte
*
)
range
->
max_key
,
((
range
->
flag
&
NEAR_MAX
)
?
range
->
max_length
,
HA_READ_KEY_OR_PREV
:
HA_READ_AFTER_KEY
));
((
range
->
flag
&
NEAR_MAX
)
?
HA_READ_KEY_EXACT
:
HA_READ_AFTER_KEY
));
result
=
file
->
index_prev
(
record
);
result
=
file
->
index_prev
(
record
);
}
}
if
(
result
)
if
(
result
)
...
@@ -2629,7 +2648,7 @@ int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range)
...
@@ -2629,7 +2648,7 @@ int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range)
if
(
range
->
flag
&
NO_MIN_RANGE
)
if
(
range
->
flag
&
NO_MIN_RANGE
)
return
(
0
);
/* key can't be to small */
return
(
0
);
/* key can't be to small */
KEY_PART
*
key_part
=
quick
->
key_parts
;
KEY_PART
*
key_part
=
key_parts
;
for
(
char
*
key
=
range
->
min_key
,
*
end
=
key
+
range
->
min_length
;
for
(
char
*
key
=
range
->
min_key
,
*
end
=
key
+
range
->
min_length
;
key
<
end
;
key
<
end
;
key
+=
key_part
++->
part_length
)
key
+=
key_part
++->
part_length
)
...
@@ -2659,15 +2678,64 @@ int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range)
...
@@ -2659,15 +2678,64 @@ int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range)
/*
/*
* True if this range will require using HA_READ_AFTER_KEY
* True if this range will require using HA_READ_AFTER_KEY
See comment in get_next() about this
*/
*/
bool
QUICK_SELECT_DESC
::
range_reads_after_key
(
QUICK_RANGE
*
range
)
bool
QUICK_SELECT_DESC
::
range_reads_after_key
(
QUICK_RANGE
*
range
)
{
{
// See comment in get_next()
return
((
range
->
flag
&
(
NO_MAX_RANGE
|
NEAR_MAX
))
||
return
range
->
flag
&
(
NO_MAX_RANGE
|
NEAR_MAX
)
?
1
:
!
(
range
->
flag
&
EQ_RANGE
)
||
(
range
->
flag
&
EQ_RANGE
&&
head
->
key_info
[
index
].
key_length
!=
range
->
max_length
)
?
1
:
0
;
head
->
key_info
[
index
].
key_length
==
range
->
max_length
)
?
0
:
1
;
}
}
/* True if we are reading over a key that may have a NULL value */
bool
QUICK_SELECT_DESC
::
test_if_null_range
(
QUICK_RANGE
*
range
,
uint
used_key_parts
)
{
uint
offset
,
end
;
KEY_PART
*
key_part
=
key_parts
,
*
key_part_end
=
key_part
+
used_key_parts
;
for
(
offset
=
0
,
end
=
min
(
range
->
min_length
,
range
->
max_length
)
;
offset
<
end
&&
key_part
!=
key_part_end
;
offset
+=
key_part
++->
part_length
)
{
uint
null_length
=
test
(
key_part
->
null_bit
);
if
(
!
memcmp
((
char
*
)
range
->
min_key
+
offset
,
(
char
*
)
range
->
max_key
+
offset
,
key_part
->
part_length
+
null_length
))
{
offset
+=
null_length
;
continue
;
}
if
(
null_length
&&
range
->
min_key
[
offset
])
return
1
;
// min_key is null and max_key isn't
// Range doesn't cover NULL. This is ok if there is no more null parts
break
;
}
/*
If the next min_range is > NULL, then we can use this, even if
it's a NULL key
Example: SELECT * FROM t1 WHERE a = 2 AND b >0 ORDER BY a DESC,b DESC;
*/
if
(
key_part
!=
key_part_end
&&
key_part
->
null_bit
)
{
if
(
offset
>=
range
->
min_length
||
range
->
min_key
[
offset
])
return
1
;
// Could be null
key_part
++
;
}
/*
If any of the key parts used in the ORDER BY could be NULL, we can't
use the key to sort the data.
*/
for
(;
key_part
!=
key_part_end
;
key_part
++
)
if
(
key_part
->
null_bit
)
return
1
;
// Covers null part
return
0
;
}
/*****************************************************************************
/*****************************************************************************
** Print a quick range for debugging
** Print a quick range for debugging
** TODO:
** TODO:
...
...
sql/opt_range.h
View file @
f0dc1892
...
@@ -54,9 +54,10 @@ class QUICK_RANGE :public Sql_alloc {
...
@@ -54,9 +54,10 @@ class QUICK_RANGE :public Sql_alloc {
{}
{}
};
};
class
QUICK_SELECT
{
class
QUICK_SELECT
{
public:
public:
bool
next
;
bool
next
,
dont_free
;
int
error
;
int
error
;
uint
index
,
max_used_key_length
;
uint
index
,
max_used_key_length
;
TABLE
*
head
;
TABLE
*
head
;
...
@@ -80,16 +81,17 @@ public:
...
@@ -80,16 +81,17 @@ public:
bool
unique_key_range
();
bool
unique_key_range
();
};
};
class
QUICK_SELECT_DESC
:
public
QUICK_SELECT
class
QUICK_SELECT_DESC
:
public
QUICK_SELECT
{
{
public:
public:
QUICK_SELECT_DESC
(
QUICK_SELECT
*
q
);
QUICK_SELECT_DESC
(
QUICK_SELECT
*
q
,
uint
used_key_parts
);
int
get_next
();
int
get_next
();
private:
private:
int
cmp_prev
(
QUICK_RANGE
*
range
);
int
cmp_prev
(
QUICK_RANGE
*
range
);
bool
range_reads_after_key
(
QUICK_RANGE
*
range
);
bool
range_reads_after_key
(
QUICK_RANGE
*
range
);
bool
test_if_null_range
(
QUICK_RANGE
*
range
,
uint
used_key_parts
);
QUICK_SELECT
*
quick
;
void
reset
(
void
)
{
next
=
0
;
rev_it
.
rewind
();
}
List
<
QUICK_RANGE
>
rev_ranges
;
List
<
QUICK_RANGE
>
rev_ranges
;
List_iterator
<
QUICK_RANGE
>
rev_it
;
List_iterator
<
QUICK_RANGE
>
rev_it
;
};
};
...
...
sql/sql_delete.cc
View file @
f0dc1892
...
@@ -290,11 +290,7 @@ int mysql_delete(THD *thd,
...
@@ -290,11 +290,7 @@ int mysql_delete(THD *thd,
** delete multiple tables from join
** delete multiple tables from join
***************************************************************************/
***************************************************************************/
#ifndef DBUG_OFF
#define MEM_STRIP_BUF_SIZE sortbuff_size
#define MEM_STRIP_BUF_SIZE 2048
#else
#define MEM_STRIP_BUF_SIZE sortbuffer_size
#endif
#ifndef SINISAS_STRIP
#ifndef SINISAS_STRIP
int
refposcmp2
(
void
*
arg
,
const
void
*
a
,
const
void
*
b
)
int
refposcmp2
(
void
*
arg
,
const
void
*
a
,
const
void
*
b
)
...
...
sql/sql_select.cc
View file @
f0dc1892
...
@@ -5153,9 +5153,11 @@ part_of_refkey(TABLE *table,Field *field)
...
@@ -5153,9 +5153,11 @@ part_of_refkey(TABLE *table,Field *field)
** Returns: 1 if key is ok.
** Returns: 1 if key is ok.
** 0 if key can't be used
** 0 if key can't be used
** -1 if reverse key can be used
** -1 if reverse key can be used
** used_key_parts is set to key parts used if length != 0
*****************************************************************************/
*****************************************************************************/
static
int
test_if_order_by_key
(
ORDER
*
order
,
TABLE
*
table
,
uint
idx
)
static
int
test_if_order_by_key
(
ORDER
*
order
,
TABLE
*
table
,
uint
idx
,
uint
*
used_key_parts
)
{
{
KEY_PART_INFO
*
key_part
,
*
key_part_end
;
KEY_PART_INFO
*
key_part
,
*
key_part_end
;
key_part
=
table
->
key_info
[
idx
].
key_part
;
key_part
=
table
->
key_info
[
idx
].
key_part
;
...
@@ -5187,6 +5189,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx)
...
@@ -5187,6 +5189,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx)
reverse
=
flag
;
// Remember if reverse
reverse
=
flag
;
// Remember if reverse
key_part
++
;
key_part
++
;
}
}
*
used_key_parts
=
(
uint
)
(
key_part
-
table
->
key_info
[
idx
].
key_part
);
return
reverse
;
return
reverse
;
}
}
...
@@ -5249,16 +5252,37 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
...
@@ -5249,16 +5252,37 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
if
(
ref_key
>=
0
)
if
(
ref_key
>=
0
)
{
{
int
order_direction
;
int
order_direction
;
uint
used_key_parts
;
/* Check if we get the rows in requested sorted order by using the key */
/* Check if we get the rows in requested sorted order by using the key */
if
((
usable_keys
&
((
key_map
)
1
<<
ref_key
))
&&
if
((
usable_keys
&
((
key_map
)
1
<<
ref_key
))
&&
(
order_direction
=
test_if_order_by_key
(
order
,
table
,
ref_key
)))
(
order_direction
=
test_if_order_by_key
(
order
,
table
,
ref_key
,
&
used_key_parts
)))
{
{
if
(
order_direction
==
-
1
&&
select
&&
select
->
quick
)
if
(
order_direction
==
-
1
)
{
{
// ORDER BY ref_key DESC
if
(
select
&&
select
->
quick
)
select
->
quick
=
new
QUICK_SELECT_DESC
(
select
->
quick
);
{
if
(
select
->
quick
->
error
)
// ORDER BY ref_key DESC
QUICK_SELECT_DESC
*
tmp
=
new
QUICK_SELECT_DESC
(
select
->
quick
,
used_key_parts
);
if
(
!
tmp
||
tmp
->
error
)
{
delete
tmp
;
DBUG_RETURN
(
0
);
// Reverse sort not supported
}
select
->
quick
=
tmp
;
DBUG_RETURN
(
1
);
}
if
(
tab
->
ref
.
key_parts
<
used_key_parts
)
{
/*
SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC
TODO:
Add a new traversal function to read last matching row and
traverse backwards.
*/
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
}
}
}
DBUG_RETURN
(
1
);
/* No need to sort */
DBUG_RETURN
(
1
);
/* No need to sort */
}
}
...
@@ -5280,10 +5304,11 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
...
@@ -5280,10 +5304,11 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
for
(
nr
=
0
;
keys
;
keys
>>=
1
,
nr
++
)
for
(
nr
=
0
;
keys
;
keys
>>=
1
,
nr
++
)
{
{
uint
not_used
;
if
(
keys
&
1
)
if
(
keys
&
1
)
{
{
int
flag
;
int
flag
;
if
((
flag
=
test_if_order_by_key
(
order
,
table
,
nr
)))
if
((
flag
=
test_if_order_by_key
(
order
,
table
,
nr
,
&
not_used
)))
{
{
if
(
!
no_changes
)
if
(
!
no_changes
)
{
{
...
...
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