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
65af63b0
Commit
65af63b0
authored
14 years ago
by
Igor Babaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Addressed the feedback from the review of Monty on the cumulative patch for
mwl#21.
parent
91f950b1
No related merge requests found
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
527 additions
and
412 deletions
+527
-412
include/my_tree.h
include/my_tree.h
+9
-0
sql/filesort.cc
sql/filesort.cc
+44
-38
sql/mysql_priv.h
sql/mysql_priv.h
+3
-0
sql/opt_range.cc
sql/opt_range.cc
+409
-313
sql/opt_range.h
sql/opt_range.h
+60
-60
sql/sql_class.h
sql/sql_class.h
+2
-1
No files found.
include/my_tree.h
View file @
65af63b0
...
...
@@ -30,6 +30,15 @@ extern "C" {
#define tree_set_pointer(element,ptr) *((uchar **) (element+1))=((uchar*) (ptr))
/*
A tree with its flag set to TREE_ONLY_DUPS behaves differently on inserting
an element that is not in the tree:
the element is not added at all, but instead tree_insert() returns a special
address TREE_ELEMENT_UNIQUE as an indication that the function has not failed
due to lack of memory.
*/
#define TREE_ELEMENT_UNIQUE ((TREE_ELEMENT *) 1)
#define TREE_NO_DUPS 1
#define TREE_ONLY_DUPS 2
...
...
This diff is collapsed.
Click to expand it.
sql/filesort.cc
View file @
65af63b0
...
...
@@ -141,9 +141,6 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
/* filesort cannot handle zero-length records. */
DBUG_ASSERT
(
param
.
sort_length
);
param
.
ref_length
=
table
->
file
->
ref_length
;
param
.
min_dupl_count
=
0
;
param
.
addon_field
=
0
;
param
.
addon_length
=
0
;
if
(
!
(
table
->
file
->
ha_table_flags
()
&
HA_FAST_KEY_READ
)
&&
!
table
->
fulltext_searched
&&
!
sort_positions
)
{
...
...
@@ -1197,8 +1194,11 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
QUEUE
queue
;
qsort2_cmp
cmp
;
void
*
first_cmp_arg
;
volatile
THD
::
killed_state
*
killed
=
&
current_thd
->
killed
;
element_count
dupl_count
;
uchar
*
src
;
THD
::
killed_state
not_killable
;
uchar
*
unique_buff
=
param
->
unique_buff
;
volatile
THD
::
killed_state
*
killed
=
&
current_thd
->
killed
;
DBUG_ENTER
(
"merge_buffers"
);
status_var_increment
(
current_thd
->
status_var
.
filesort_merge_passes
);
...
...
@@ -1213,13 +1213,13 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
rec_length
=
param
->
rec_length
;
res_length
=
param
->
res_length
;
sort_length
=
param
->
sort_length
;
element_count
dupl_count
;
uchar
*
src
;
uint
dupl_count_ofs
=
rec_length
-
sizeof
(
element_count
);
uint
min_dupl_count
=
param
->
min_dupl_count
;
offset
=
rec_length
-
(
flag
&&
min_dupl_count
?
sizeof
(
dupl_count
)
:
0
)
-
res_length
;
bool
check_dupl_count
=
flag
&&
min_dupl_count
;
offset
=
(
rec_length
-
(
flag
&&
min_dupl_count
?
sizeof
(
dupl_count
)
:
0
)
-
res_length
);
uint
wr_len
=
flag
?
res_length
:
rec_length
;
uint
wr_offset
=
flag
?
offset
:
0
;
maxcount
=
(
ulong
)
(
param
->
keys
/
((
uint
)
(
Tb
-
Fb
)
+
1
));
to_start_filepos
=
my_b_tell
(
to_file
);
strpos
=
sort_buffer
;
...
...
@@ -1228,7 +1228,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
/* The following will fire if there is not enough space in sort_buffer */
DBUG_ASSERT
(
maxcount
!=
0
);
if
(
param
->
unique_buff
)
if
(
unique_buff
)
{
cmp
=
param
->
compare
;
first_cmp_arg
=
(
void
*
)
&
param
->
cmp_context
;
...
...
@@ -1253,25 +1253,22 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
queue_insert
(
&
queue
,
(
uchar
*
)
buffpek
);
}
if
(
param
->
unique_buff
)
if
(
unique_buff
)
{
/*
Called by Unique::get()
Copy the first argument to
param->
unique_buff for unique removal.
Copy the first argument to unique_buff for unique removal.
Store it also in 'to_file'.
This is safe as we know that there is always more than one element
in each block to merge (This is guaranteed by the Unique:: algorithm
*/
buffpek
=
(
BUFFPEK
*
)
queue_top
(
&
queue
);
memcpy
(
param
->
unique_buff
,
buffpek
->
key
,
rec_length
);
memcpy
(
unique_buff
,
buffpek
->
key
,
rec_length
);
if
(
min_dupl_count
)
memcpy
(
&
dupl_count
,
param
->
unique_buff
+
dupl_count_ofs
,
memcpy
(
&
dupl_count
,
unique_buff
+
dupl_count_ofs
,
sizeof
(
dupl_count
));
buffpek
->
key
+=
rec_length
;
if
(
!
--
buffpek
->
mem_count
)
{
if
(
!
(
error
=
(
int
)
read_to_buffer
(
from_file
,
buffpek
,
if
(
!
(
error
=
(
int
)
read_to_buffer
(
from_file
,
buffpek
,
rec_length
)))
{
VOID
(
queue_remove
(
&
queue
,
0
));
...
...
@@ -1297,7 +1294,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
src
=
buffpek
->
key
;
if
(
cmp
)
// Remove duplicates
{
if
(
!
(
*
cmp
)(
first_cmp_arg
,
&
(
param
->
unique_buff
)
,
if
(
!
(
*
cmp
)(
first_cmp_arg
,
&
unique_buff
,
(
uchar
**
)
&
buffpek
->
key
))
{
if
(
min_dupl_count
)
...
...
@@ -1310,24 +1307,32 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
}
if
(
min_dupl_count
)
{
memcpy
(
param
->
unique_buff
+
dupl_count_ofs
,
&
dupl_count
,
memcpy
(
unique_buff
+
dupl_count_ofs
,
&
dupl_count
,
sizeof
(
dupl_count
));
}
src
=
param
->
unique_buff
;
src
=
unique_buff
;
}
if
(
!
flag
||
!
min_dupl_count
||
dupl_count
>=
min_dupl_count
)
/*
Do not write into the output file if this is the final merge called
for a Unique object used for intersection and dupl_count is less
than min_dupl_count.
If the Unique object is used to intersect N sets of unique elements
then for any element:
dupl_count >= N <=> the element is occurred in each of these N sets.
*/
if
(
!
check_dupl_count
||
dupl_count
>=
min_dupl_count
)
{
if
(
my_b_write
(
to_file
,
src
+
(
flag
?
offset
:
0
)
,
wr_len
))
if
(
my_b_write
(
to_file
,
src
+
wr_offset
,
wr_len
))
{
error
=
1
;
goto
err
;
/* purecov: inspected */
}
}
if
(
cmp
)
{
memcpy
(
param
->
unique_buff
,
(
uchar
*
)
buffpek
->
key
,
rec_length
);
memcpy
(
unique_buff
,
(
uchar
*
)
buffpek
->
key
,
rec_length
);
if
(
min_dupl_count
)
memcpy
(
&
dupl_count
,
param
->
unique_buff
+
dupl_count_ofs
,
memcpy
(
&
dupl_count
,
unique_buff
+
dupl_count_ofs
,
sizeof
(
dupl_count
));
}
if
(
!--
max_rows
)
...
...
@@ -1340,7 +1345,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
buffpek
->
key
+=
rec_length
;
if
(
!
--
buffpek
->
mem_count
)
{
if
(
!
(
error
=
(
int
)
read_to_buffer
(
from_file
,
buffpek
,
if
(
!
(
error
=
(
int
)
read_to_buffer
(
from_file
,
buffpek
,
rec_length
)))
{
VOID
(
queue_remove
(
&
queue
,
0
));
...
...
@@ -1363,7 +1368,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
*/
if
(
cmp
)
{
if
(
!
(
*
cmp
)(
first_cmp_arg
,
&
(
param
->
unique_buff
)
,
(
uchar
**
)
&
buffpek
->
key
))
if
(
!
(
*
cmp
)(
first_cmp_arg
,
&
unique_buff
,
(
uchar
**
)
&
buffpek
->
key
))
{
if
(
min_dupl_count
)
{
...
...
@@ -1376,13 +1381,13 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
}
if
(
min_dupl_count
)
memcpy
(
param
->
unique_buff
+
dupl_count_ofs
,
&
dupl_count
,
memcpy
(
unique_buff
+
dupl_count_ofs
,
&
dupl_count
,
sizeof
(
dupl_count
));
if
(
!
flag
||
!
min
_dupl_count
||
dupl_count
>=
min_dupl_count
)
if
(
!
check
_dupl_count
||
dupl_count
>=
min_dupl_count
)
{
src
=
param
->
unique_buff
;
if
(
my_b_write
(
to_file
,
src
+
(
flag
?
offset
:
0
)
,
wr_len
))
src
=
unique_buff
;
if
(
my_b_write
(
to_file
,
src
+
wr_offset
,
wr_len
))
{
error
=
1
;
goto
err
;
/* purecov: inspected */
}
...
...
@@ -1404,7 +1409,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
max_rows
-=
buffpek
->
mem_count
;
if
(
flag
==
0
)
{
if
(
my_b_write
(
to_file
,(
uchar
*
)
buffpek
->
key
,
if
(
my_b_write
(
to_file
,
(
uchar
*
)
buffpek
->
key
,
(
rec_length
*
buffpek
->
mem_count
)))
{
error
=
1
;
goto
err
;
/* purecov: inspected */
...
...
@@ -1418,11 +1423,12 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
src
!=
end
;
src
+=
rec_length
)
{
if
(
flag
&&
min_dupl_count
&&
memcmp
(
&
min_dupl_count
,
src
+
dupl_count_ofs
,
sizeof
(
dupl_count_ofs
))
<
0
)
continue
;
if
(
check_dupl_count
)
{
memcpy
((
uchar
*
)
&
dupl_count
,
src
+
dupl_count_ofs
,
sizeof
(
dupl_count
));
if
(
dupl_count
<
min_dupl_count
)
continue
;
}
if
(
my_b_write
(
to_file
,
src
,
wr_len
))
{
error
=
1
;
goto
err
;
...
...
@@ -1430,7 +1436,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
}
}
}
while
((
error
=
(
int
)
read_to_buffer
(
from_file
,
buffpek
,
rec_length
))
while
((
error
=
(
int
)
read_to_buffer
(
from_file
,
buffpek
,
rec_length
))
!=
-
1
&&
error
!=
0
);
end:
...
...
This diff is collapsed.
Click to expand it.
sql/mysql_priv.h
View file @
65af63b0
...
...
@@ -340,6 +340,9 @@ protected:
*/
#define TIME_FOR_COMPARE_ROWID (TIME_FOR_COMPARE*100)
/* cost1 is better that cost2 only if cost1 + COST_EPS < cost2 */
#define COST_EPS 0.001
/*
For sequential disk seeks the cost formula is:
DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST * #blocks_to_skip
...
...
This diff is collapsed.
Click to expand it.
sql/opt_range.cc
View file @
65af63b0
This diff is collapsed.
Click to expand it.
sql/opt_range.h
View file @
65af63b0
...
...
@@ -328,6 +328,7 @@ public:
selects output and/or can produce output suitable for merging.
*/
virtual
void
add_info_string
(
String
*
str
)
{}
/*
Return 1 if any index used by this quick select
uses field which is marked in passed bitmap.
...
...
@@ -406,9 +407,11 @@ protected:
QUICK_RANGE_SELECT
*
pk_quick_select
,
READ_RECORD
*
read_record
,
bool
intersection
,
key_map
*
filtered_scans
,
Unique
**
unique_ptr
);
friend
class
QUICK_SELECT_DESC
;
friend
class
QUICK_INDEX_SORT_SELECT
;
friend
class
QUICK_INDEX_MERGE_SELECT
;
friend
class
QUICK_INDEX_INTERSECT_SELECT
;
friend
class
QUICK_ROR_INTERSECT_SELECT
;
...
...
@@ -464,40 +467,44 @@ public:
/*
QUICK_INDEX_MERGE_SELECT - index_merge access method quick select.
QUICK_INDEX_SORT_SELECT is the base class for the common functionality of:
- QUICK_INDEX_MERGE_SELECT, access based on multi-index merge/union
- QUICK_INDEX_INTERSECT_SELECT, access based on multi-index intersection
QUICK_INDEX_
MERGE
_SELECT uses
QUICK_INDEX_
SORT
_SELECT uses
* QUICK_RANGE_SELECTs to get rows
* Unique class to remove duplicate rows
* Unique class
- to remove duplicate rows for QUICK_INDEX_MERGE_SELECT
- to intersect rows for QUICK_INDEX_INTERSECT_SELECT
INDEX MERGE OPTIMIZER
Current implementation doesn't detect all cases where index
_
merge could
Current implementation doesn't detect all cases where index
merge could
be used, in particular:
* index_merge will never be used if range scan is possible (even if
range scan is more expensive)
* index
_
merge+'using index' is not supported (this the consequence of
* index
merge+'using index' is not supported (this the consequence of
the above restriction)
* If WHERE part contains complex nested AND and OR conditions, some ways
to retrieve rows using index
_
merge will not be considered. The choice
to retrieve rows using index
merge will not be considered. The choice
of read plan may depend on the order of conjuncts/disjuncts in WHERE
part of the query, see comments near imerge_list_or_list and
SEL_IMERGE::or_sel_tree_with_checks functions for details.
* There is no "index_merge_ref" method (but index
_
merge on non-first
* There is no "index_merge_ref" method (but index
merge on non-first
table in join is possible with 'range checked for each record').
See comments around SEL_IMERGE class and test_quick_select for more
details.
ROW RETRIEVAL ALGORITHM
index_merge uses Unique class for duplicates removal. index_merge takes
advantage of Clustered Primary Key (CPK) if the table has one.
The index_merge algorithm consists of two phases:
index merge/intersection uses Unique class for duplicates removal.
index merge/intersection takes advantage of Clustered Primary Key (CPK)
if the table has one.
The index merge/intersection algorithm consists of two phases:
Phase 1
(implemented by a QUICK_INDEX_MERGE_SELECT::read_keys_and_merge call):
Phase 1 (implemented in QUICK_INDEX_MERGE_SELECT::prepare_unique):
prepare()
{
activate 'index only';
...
...
@@ -511,32 +518,31 @@ public:
deactivate 'index only';
}
Phase 2
(implemented as sequence of QUICK_INDEX_MERGE_SELECT::get_next
calls):
Phase 2
(implemented as sequence of QUICK_INDEX_MERGE_SELECT::get_next
calls):
fetch()
{
retrieve all rows from row pointers stored in Unique;
retrieve all rows from row pointers stored in Unique
(merging/intersecting them);
free Unique;
retrieve all rows for CPK scan;
if (! intersection)
retrieve all rows for CPK scan;
}
*/
class
QUICK_INDEX_
MERGE
_SELECT
:
public
QUICK_SELECT_I
class
QUICK_INDEX_
SORT
_SELECT
:
public
QUICK_SELECT_I
{
protected:
Unique
*
unique
;
public:
QUICK_INDEX_
MERGE
_SELECT
(
THD
*
thd
,
TABLE
*
table
);
~
QUICK_INDEX_
MERGE
_SELECT
();
QUICK_INDEX_
SORT
_SELECT
(
THD
*
thd
,
TABLE
*
table
);
~
QUICK_INDEX_
SORT
_SELECT
();
int
init
();
int
reset
(
void
);
int
get_next
();
bool
reverse_sorted
()
{
return
false
;
}
bool
unique_key_range
()
{
return
false
;
}
int
get_type
()
{
return
QS_TYPE_INDEX_MERGE
;
}
void
add_keys_and_lengths
(
String
*
key_names
,
String
*
used_lengths
);
void
add_info_string
(
String
*
str
);
bool
is_keys_used
(
const
MY_BITMAP
*
fields
);
#ifndef DBUG_OFF
void
dbug_dump
(
int
indent
,
bool
verbose
);
...
...
@@ -544,60 +550,54 @@ public:
bool
push_quick_back
(
QUICK_RANGE_SELECT
*
quick_sel_range
);
/* range quick selects this index
_merge read
consists of */
/* range quick selects this index
merge/intersect
consists of */
List
<
QUICK_RANGE_SELECT
>
quick_selects
;
/* quick select that uses clustered primary key (NULL if none) */
QUICK_RANGE_SELECT
*
pk_quick_select
;
/* true if this select is currently doing a clustered PK scan */
bool
doing_pk_scan
;
MEM_ROOT
alloc
;
THD
*
thd
;
int
read_keys_and_merge
()
;
virtual
int
read_keys_and_merge
()
=
0
;
/* used to get rows collected in Unique */
READ_RECORD
read_record
;
};
class
QUICK_INDEX_INTERSECT_SELECT
:
public
QUICK_SELECT_I
class
QUICK_INDEX_MERGE_SELECT
:
public
QUICK_INDEX_SORT_SELECT
{
Unique
*
unique
;
private:
/* true if this select is currently doing a clustered PK scan */
bool
doing_pk_scan
;
protected:
int
read_keys_and_merge
();
public:
QUICK_INDEX_
INTERSECT_SELECT
(
THD
*
thd
,
TABLE
*
table
);
~
QUICK_INDEX_INTERSECT_SELECT
();
QUICK_INDEX_
MERGE_SELECT
(
THD
*
thd
,
TABLE
*
table
)
:
QUICK_INDEX_SORT_SELECT
(
thd
,
table
)
{}
int
init
();
int
reset
(
void
);
int
get_next
();
bool
reverse_sorted
()
{
return
false
;
}
bool
unique_key_range
()
{
return
false
;
}
int
get_type
()
{
return
QS_TYPE_INDEX_INTERSECT
;
}
int
get_next
();
int
get_type
()
{
return
QS_TYPE_INDEX_MERGE
;
}
void
add_keys_and_lengths
(
String
*
key_names
,
String
*
used_lengths
);
void
add_info_string
(
String
*
str
);
bool
is_keys_used
(
const
MY_BITMAP
*
fields
);
#ifndef DBUG_OFF
void
dbug_dump
(
int
indent
,
bool
verbose
);
#endif
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 that uses clustered primary key (NULL if none) */
QUICK_RANGE_SELECT
*
pk_quick_select
;
/* true if this select is currently doing a clustered PK scan */
bool
doing_pk_scan
;
};
MEM_ROOT
alloc
;
THD
*
thd
;
class
QUICK_INDEX_INTERSECT_SELECT
:
public
QUICK_INDEX_SORT_SELECT
{
protected:
int
read_keys_and_merge
();
/* used to get rows collected in Unique */
READ_RECORD
read_record
;
public:
QUICK_INDEX_INTERSECT_SELECT
(
THD
*
thd
,
TABLE
*
table
)
:
QUICK_INDEX_SORT_SELECT
(
thd
,
table
)
{}
key_map
filtered_scans
;
int
get_next
();
int
get_type
()
{
return
QS_TYPE_INDEX_INTERSECT
;
}
void
add_keys_and_lengths
(
String
*
key_names
,
String
*
used_lengths
);
void
add_info_string
(
String
*
str
);
};
...
...
This diff is collapsed.
Click to expand it.
sql/sql_class.h
View file @
65af63b0
...
...
@@ -2998,7 +2998,7 @@ class Unique :public Sql_alloc
bool
flush
();
uint
size
;
uint
full_size
;
uint
min_dupl_count
;
uint
min_dupl_count
;
/* always 0 for unions, > 0 for intersections */
public:
ulong
elements
;
...
...
@@ -3022,6 +3022,7 @@ public:
bool
get
(
TABLE
*
table
);
/* Cost of searching for an element in the tree */
inline
static
double
get_search_cost
(
uint
tree_elems
,
uint
compare_factor
)
{
return
log
((
double
)
tree_elems
)
/
(
compare_factor
*
M_LN2
);
...
...
This diff is collapsed.
Click to expand it.
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