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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
d89166cd
Commit
d89166cd
authored
Jan 18, 2005
by
sergefp@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/psergey/mysql-5.0-fix-vg1
parents
4aebc4b3
1eab462c
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
187 additions
and
174 deletions
+187
-174
include/my_bitmap.h
include/my_bitmap.h
+1
-1
mysql-test/r/index_merge_innodb.result
mysql-test/r/index_merge_innodb.result
+1
-1
mysql-test/r/index_merge_ror_cpk.result
mysql-test/r/index_merge_ror_cpk.result
+1
-1
mysql-test/t/index_merge_innodb.test
mysql-test/t/index_merge_innodb.test
+1
-1
sql/opt_range.cc
sql/opt_range.cc
+183
-170
No files found.
include/my_bitmap.h
View file @
d89166cd
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
typedef
struct
st_bitmap
typedef
struct
st_bitmap
{
{
uchar
*
bitmap
;
uchar
*
bitmap
;
uint
bitmap_size
;
uint
bitmap_size
;
/* number of bytes occupied by the above */
/*
/*
mutex will be acquired for the duration of each bitmap operation if
mutex will be acquired for the duration of each bitmap operation if
thread_safe flag in bitmap_init was set. Otherwise, we optimize by not
thread_safe flag in bitmap_init was set. Otherwise, we optimize by not
...
...
mysql-test/r/index_merge_innodb.result
View file @
d89166cd
drop table if exists t1;
drop table if exists t1
,t2
;
create table t1
create table t1
(
(
key1 int not null,
key1 int not null,
...
...
mysql-test/r/index_merge_ror_cpk.result
View file @
d89166cd
...
@@ -26,7 +26,7 @@ primary key (pk1, pk2)
...
@@ -26,7 +26,7 @@ primary key (pk1, pk2)
) engine=innodb;
) engine=innodb;
explain select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
explain select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 r
ef PRIMARY,key1 PRIMARY 4 const 1
Using where
1 SIMPLE t1 r
ange PRIMARY,key1 PRIMARY 8 NULL 9
Using where
select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
pk1 pk2 key1 key2 pktail1ok pktail2ok pktail3bad pktail4bad pktail5bad pk2copy badkey filler1 filler2
pk1 pk2 key1 key2 pktail1ok pktail2ok pktail3bad pktail4bad pktail5bad pk2copy badkey filler1 filler2
1 10 0 0 0 0 0 0 0 10 0 filler-data-10 filler2
1 10 0 0 0 0 0 0 0 10 0 filler-data-10 filler2
...
...
mysql-test/t/index_merge_innodb.test
View file @
d89166cd
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
--
source
include
/
have_innodb
.
inc
--
source
include
/
have_innodb
.
inc
--
disable_warnings
--
disable_warnings
drop
table
if
exists
t1
;
drop
table
if
exists
t1
,
t2
;
--
enable_warnings
--
enable_warnings
create
table
t1
create
table
t1
...
...
sql/opt_range.cc
View file @
d89166cd
...
@@ -50,6 +50,11 @@
...
@@ -50,6 +50,11 @@
#define test_use_count(A) {}
#define test_use_count(A) {}
#endif
#endif
/*
Convert double value to #rows. Currently this does floor(), and we
might consider using round() instead.
*/
#define double2rows(x) ((ha_rows)(x))
static
int
sel_cmp
(
Field
*
f
,
char
*
a
,
char
*
b
,
uint8
a_flag
,
uint8
b_flag
);
static
int
sel_cmp
(
Field
*
f
,
char
*
a
,
char
*
b
,
uint8
a_flag
,
uint8
b_flag
);
...
@@ -1628,6 +1633,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
...
@@ -1628,6 +1633,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
DBUG_PRINT
(
"enter"
,(
"keys_to_use: %lu prev_tables: %lu const_tables: %lu"
,
DBUG_PRINT
(
"enter"
,(
"keys_to_use: %lu prev_tables: %lu const_tables: %lu"
,
keys_to_use
.
to_ulonglong
(),
(
ulong
)
prev_tables
,
keys_to_use
.
to_ulonglong
(),
(
ulong
)
prev_tables
,
(
ulong
)
const_tables
));
(
ulong
)
const_tables
));
DBUG_PRINT
(
"info"
,
(
"records=%lu"
,
(
ulong
)
head
->
file
->
records
));
delete
quick
;
delete
quick
;
quick
=
0
;
quick
=
0
;
needed_reg
.
clear_all
();
needed_reg
.
clear_all
();
...
@@ -1874,6 +1880,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
...
@@ -1874,6 +1880,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
double
get_sweep_read_cost
(
const
PARAM
*
param
,
ha_rows
records
)
double
get_sweep_read_cost
(
const
PARAM
*
param
,
ha_rows
records
)
{
{
double
result
;
double
result
;
DBUG_ENTER
(
"get_sweep_read_cost"
);
if
(
param
->
table
->
file
->
primary_key_is_clustered
())
if
(
param
->
table
->
file
->
primary_key_is_clustered
())
{
{
result
=
param
->
table
->
file
->
read_time
(
param
->
table
->
s
->
primary_key
,
result
=
param
->
table
->
file
->
read_time
(
param
->
table
->
s
->
primary_key
,
...
@@ -1912,7 +1919,7 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records)
...
@@ -1912,7 +1919,7 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records)
}
}
}
}
DBUG_PRINT
(
"info"
,(
"returning cost=%g"
,
result
));
DBUG_PRINT
(
"info"
,(
"returning cost=%g"
,
result
));
return
result
;
DBUG_RETURN
(
result
)
;
}
}
...
@@ -2393,43 +2400,27 @@ typedef struct
...
@@ -2393,43 +2400,27 @@ typedef struct
{
{
const
PARAM
*
param
;
const
PARAM
*
param
;
MY_BITMAP
covered_fields
;
/* union of fields covered by all scans */
MY_BITMAP
covered_fields
;
/* union of fields covered by all scans */
/* TRUE if covered_fields is a superset of needed_fields */
bool
is_covering
;
double
index_scan_costs
;
/* SUM(cost of 'index-only' scans) */
double
total_cost
;
/*
/*
Fraction of table records that satisfies conditions of all scans.
Fraction of table records that satisfies conditions of all scans.
This is the number of full records that will be retrieved if a
This is the number of full records that will be retrieved if a
non-index_only index intersection will be employed.
non-index_only index intersection will be employed.
*/
*/
double
records_fract
;
double
out_rows
;
/* TRUE if covered_fields is a superset of needed_fields */
bool
is_covering
;
ha_rows
index_records
;
/* sum(#records to look in indexes) */
ha_rows
index_records
;
/* sum(#records to look in indexes) */
double
index_scan_costs
;
/* SUM(cost of 'index-only' scans) */
double
total_cost
;
}
ROR_INTERSECT_INFO
;
}
ROR_INTERSECT_INFO
;
/*
Re-initialize an allocated intersect info to contain zero scans.
SYNOPSIS
info Intersection info structure to re-initialize.
*/
static
void
ror_intersect_reinit
(
ROR_INTERSECT_INFO
*
info
)
{
info
->
is_covering
=
FALSE
;
info
->
index_scan_costs
=
0.0
f
;
info
->
records_fract
=
1.0
f
;
bitmap_clear_all
(
&
info
->
covered_fields
);
}
/*
/*
Allocate a ROR_INTERSECT_INFO and initialize it to contain zero scans.
Allocate a ROR_INTERSECT_INFO and initialize it to contain zero scans.
SYNOPSIS
SYNOPSIS
ror_intersect_init()
ror_intersect_init()
param Parameter from test_quick_select
param Parameter from test_quick_select
is_index_only If TRUE, set ROR_INTERSECT_INFO to be covering
RETURN
RETURN
allocated structure
allocated structure
...
@@ -2437,7 +2428,7 @@ static void ror_intersect_reinit(ROR_INTERSECT_INFO *info)
...
@@ -2437,7 +2428,7 @@ static void ror_intersect_reinit(ROR_INTERSECT_INFO *info)
*/
*/
static
static
ROR_INTERSECT_INFO
*
ror_intersect_init
(
const
PARAM
*
param
,
bool
is_index_only
)
ROR_INTERSECT_INFO
*
ror_intersect_init
(
const
PARAM
*
param
)
{
{
ROR_INTERSECT_INFO
*
info
;
ROR_INTERSECT_INFO
*
info
;
uchar
*
buf
;
uchar
*
buf
;
...
@@ -2450,46 +2441,39 @@ ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param, bool is_index_only)
...
@@ -2450,46 +2441,39 @@ ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param, bool is_index_only)
if
(
bitmap_init
(
&
info
->
covered_fields
,
buf
,
param
->
fields_bitmap_size
*
8
,
if
(
bitmap_init
(
&
info
->
covered_fields
,
buf
,
param
->
fields_bitmap_size
*
8
,
FALSE
))
FALSE
))
return
NULL
;
return
NULL
;
ror_intersect_reinit
(
info
);
info
->
is_covering
=
FALSE
;
info
->
index_scan_costs
=
0.0
;
info
->
index_records
=
0
;
info
->
out_rows
=
param
->
table
->
file
->
records
;
bitmap_clear_all
(
&
info
->
covered_fields
);
return
info
;
return
info
;
}
}
void
ror_intersect_cpy
(
ROR_INTERSECT_INFO
*
dst
,
const
ROR_INTERSECT_INFO
*
src
)
{
dst
->
param
=
src
->
param
;
memcpy
(
dst
->
covered_fields
.
bitmap
,
src
->
covered_fields
.
bitmap
,
src
->
covered_fields
.
bitmap_size
);
dst
->
out_rows
=
src
->
out_rows
;
dst
->
is_covering
=
src
->
is_covering
;
dst
->
index_records
=
src
->
index_records
;
dst
->
index_scan_costs
=
src
->
index_scan_costs
;
dst
->
total_cost
=
src
->
total_cost
;
}
/*
/*
Check if adding a ROR scan to a ROR-intersection reduces its cost of
Get selectivity of a ROR scan wrt ROR-intersection.
ROR-intersection and if yes, update parameters of ROR-intersection,
including its cost.
SYNOPSIS
SYNOPSIS
ror_intersect_add()
ror_scan_selectivity()
param Parameter from test_quick_select
info ROR-interection
info ROR-intersection structure to add the scan to.
scan ROR scan
ror_scan ROR scan info to add.
is_cpk_scan If TRUE, add the scan as CPK scan (this can be inferred
from other parameters and is passed separately only to
avoid duplicating the inference code)
NOTES
NOTES
Adding a ROR scan to ROR-intersect "makes sense" iff the cost of ROR-
intersection decreases. The cost of ROR-intersection is caclulated as
follows:
cost= SUM_i(key_scan_cost_i) + cost_of_full_rows_retrieval
if (union of indexes used covers all needed fields)
cost_of_full_rows_retrieval= 0;
else
{
cost_of_full_rows_retrieval=
cost_of_sweep_read(E(rows_to_retrieve), rows_in_table);
}
E(rows_to_retrieve) is caclulated as follows:
Suppose we have a condition on several keys
Suppose we have a condition on several keys
cond=k_11=c_11 AND k_12=c_12 AND ... // parts of first key
cond=k_11=c_11 AND k_12=c_12 AND ... // parts of first key
k_21=c_21 AND k_22=c_22 AND ... // parts of second key
k_21=c_21 AND k_22=c_22 AND ... // parts of second key
...
...
k_n1=c_n1 AND k_n3=c_n3 AND ... (1)
k_n1=c_n1 AND k_n3=c_n3 AND ... (1)
//parts of the key used by *scan
where k_ij may be the same as any k_pq (i.e. keys may have common parts).
where k_ij may be the same as any k_pq (i.e. keys may have common parts).
...
@@ -2563,38 +2547,30 @@ ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param, bool is_index_only)
...
@@ -2563,38 +2547,30 @@ ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param, bool is_index_only)
and reduce adjacent fractions.
and reduce adjacent fractions.
RETURN
RETURN
TRUE ROR scan added to ROR-intersection, cost updated
.
Selectivity of given ROR scan
.
FALSE It doesn't make sense to add this ROR scan to this ROR-intersection.
*/
*/
bool
ror_intersect_add
(
const
PARAM
*
param
,
ROR_INTERSECT_INFO
*
info
,
static
double
ror_scan_selectivity
(
const
ROR_INTERSECT_INFO
*
info
,
ROR_SCAN_INFO
*
ror_scan
,
bool
is_cpk_scan
=
FALSE
)
const
ROR_SCAN_INFO
*
scan
)
{
{
int
i
;
SEL_ARG
*
sel_arg
;
KEY_PART_INFO
*
key_part
=
info
->
param
->
table
->
key_info
[
ror_scan
->
keynr
].
key_part
;
double
selectivity_mult
=
1.0
;
double
selectivity_mult
=
1.0
;
KEY_PART_INFO
*
key_part
=
info
->
param
->
table
->
key_info
[
scan
->
keynr
].
key_part
;
byte
key_val
[
MAX_KEY_LENGTH
+
MAX_FIELD_WIDTH
];
/* key values tuple */
byte
key_val
[
MAX_KEY_LENGTH
+
MAX_FIELD_WIDTH
];
/* key values tuple */
DBUG_ENTER
(
"ror_intersect_add"
);
DBUG_PRINT
(
"info"
,
(
"Current selectivity= %g"
,
info
->
records_fract
));
DBUG_PRINT
(
"info"
,
(
"Adding scan on %s"
,
info
->
param
->
table
->
key_info
[
ror_scan
->
keynr
].
name
));
SEL_ARG
*
tuple_arg
=
NULL
;
char
*
key_ptr
=
(
char
*
)
key_val
;
char
*
key_ptr
=
(
char
*
)
key_val
;
bool
cur_covered
,
prev_covered
=
SEL_ARG
*
sel_arg
,
*
tuple_arg
=
NULL
;
bitmap_is_set
(
&
info
->
covered_fields
,
key_part
->
fieldnr
);
bool
cur_covered
;
bool
prev_covered
=
bitmap_is_set
(
&
info
->
covered_fields
,
key_part
->
fieldnr
);
ha_rows
prev_records
=
param
->
table
->
file
->
records
;
key_range
min_range
;
key_range
min_range
;
key_range
max_range
;
key_range
max_range
;
min_range
.
key
=
(
byte
*
)
key_val
;
min_range
.
key
=
(
byte
*
)
key_val
;
min_range
.
flag
=
HA_READ_KEY_EXACT
;
min_range
.
flag
=
HA_READ_KEY_EXACT
;
max_range
.
key
=
(
byte
*
)
key_val
;
max_range
.
key
=
(
byte
*
)
key_val
;
max_range
.
flag
=
HA_READ_AFTER_KEY
;
max_range
.
flag
=
HA_READ_AFTER_KEY
;
ha_rows
prev_records
=
info
->
param
->
table
->
file
->
records
;
for
(
i
=
0
,
sel_arg
=
ror_scan
->
sel_arg
;
sel_arg
;
int
i
;
DBUG_ENTER
(
"ror_intersect_selectivity"
);
for
(
i
=
0
,
sel_arg
=
scan
->
sel_arg
;
sel_arg
;
i
++
,
sel_arg
=
sel_arg
->
next_key_part
)
i
++
,
sel_arg
=
sel_arg
->
next_key_part
)
{
{
cur_covered
=
bitmap_is_set
(
&
info
->
covered_fields
,
(
key_part
+
i
)
->
fieldnr
);
cur_covered
=
bitmap_is_set
(
&
info
->
covered_fields
,
(
key_part
+
i
)
->
fieldnr
);
...
@@ -2604,7 +2580,7 @@ bool ror_intersect_add(const PARAM *param, ROR_INTERSECT_INFO *info,
...
@@ -2604,7 +2580,7 @@ bool ror_intersect_add(const PARAM *param, ROR_INTERSECT_INFO *info,
{
{
if
(
!
tuple_arg
)
if
(
!
tuple_arg
)
{
{
tuple_arg
=
ror_
scan
->
sel_arg
;
tuple_arg
=
scan
->
sel_arg
;
tuple_arg
->
store_min
(
key_part
->
length
,
&
key_ptr
,
0
);
tuple_arg
->
store_min
(
key_part
->
length
,
&
key_ptr
,
0
);
}
}
while
(
tuple_arg
->
next_key_part
!=
sel_arg
)
while
(
tuple_arg
->
next_key_part
!=
sel_arg
)
...
@@ -2615,10 +2591,8 @@ bool ror_intersect_add(const PARAM *param, ROR_INTERSECT_INFO *info,
...
@@ -2615,10 +2591,8 @@ bool ror_intersect_add(const PARAM *param, ROR_INTERSECT_INFO *info,
}
}
ha_rows
records
;
ha_rows
records
;
min_range
.
length
=
max_range
.
length
=
((
char
*
)
key_ptr
-
(
char
*
)
key_val
);
min_range
.
length
=
max_range
.
length
=
((
char
*
)
key_ptr
-
(
char
*
)
key_val
);
records
=
param
->
table
->
file
->
records
=
info
->
param
->
table
->
file
->
records_in_range
(
ror_scan
->
keynr
,
records_in_range
(
scan
->
keynr
,
&
min_range
,
&
max_range
);
&
min_range
,
&
max_range
);
if
(
cur_covered
)
if
(
cur_covered
)
{
{
/* uncovered -> covered */
/* uncovered -> covered */
...
@@ -2637,49 +2611,105 @@ bool ror_intersect_add(const PARAM *param, ROR_INTERSECT_INFO *info,
...
@@ -2637,49 +2611,105 @@ bool ror_intersect_add(const PARAM *param, ROR_INTERSECT_INFO *info,
}
}
if
(
!
prev_covered
)
if
(
!
prev_covered
)
{
{
double
tmp
=
rows2double
(
param
->
table
->
quick_rows
[
ror_
scan
->
keynr
])
/
double
tmp
=
rows2double
(
info
->
param
->
table
->
quick_rows
[
scan
->
keynr
])
/
rows2double
(
prev_records
);
rows2double
(
prev_records
);
DBUG_PRINT
(
"info"
,
(
"Selectivity multiplier: %g"
,
tmp
));
DBUG_PRINT
(
"info"
,
(
"Selectivity multiplier: %g"
,
tmp
));
selectivity_mult
*=
tmp
;
selectivity_mult
*=
tmp
;
}
}
DBUG_PRINT
(
"info"
,
(
"Returning multiplier: %g"
,
selectivity_mult
));
DBUG_RETURN
(
selectivity_mult
);
}
/*
Check if adding a ROR scan to a ROR-intersection reduces its cost of
ROR-intersection and if yes, update parameters of ROR-intersection,
including its cost.
SYNOPSIS
ror_intersect_add()
param Parameter from test_quick_select
info ROR-intersection structure to add the scan to.
ror_scan ROR scan info to add.
is_cpk_scan If TRUE, add the scan as CPK scan (this can be inferred
from other parameters and is passed separately only to
avoid duplicating the inference code)
NOTES
Adding a ROR scan to ROR-intersect "makes sense" iff the cost of ROR-
intersection decreases. The cost of ROR-intersection is calculated as
follows:
cost= SUM_i(key_scan_cost_i) + cost_of_full_rows_retrieval
When we add a scan the first increases and the second decreases.
cost_of_full_rows_retrieval=
(union of indexes used covers all needed fields) ?
cost_of_sweep_read(E(rows_to_retrieve), rows_in_table) :
0
E(rows_to_retrieve) = #rows_in_table * ror_scan_selectivity(null, scan1) *
ror_scan_selectivity({scan1}, scan2) * ... *
ror_scan_selectivity({scan1,...}, scanN).
RETURN
TRUE ROR scan added to ROR-intersection, cost updated.
FALSE It doesn't make sense to add this ROR scan to this ROR-intersection.
*/
static
bool
ror_intersect_add
(
ROR_INTERSECT_INFO
*
info
,
ROR_SCAN_INFO
*
ror_scan
,
bool
is_cpk_scan
)
{
double
selectivity_mult
=
1.0
;
DBUG_ENTER
(
"ror_intersect_add"
);
DBUG_PRINT
(
"info"
,
(
"Current out_rows= %g"
,
info
->
out_rows
));
DBUG_PRINT
(
"info"
,
(
"Adding scan on %s"
,
info
->
param
->
table
->
key_info
[
ror_scan
->
keynr
].
name
));
DBUG_PRINT
(
"info"
,
(
"is_cpk_scan=%d"
,
is_cpk_scan
));
selectivity_mult
=
ror_scan_selectivity
(
info
,
ror_scan
);
if
(
selectivity_mult
==
1.0
)
if
(
selectivity_mult
==
1.0
)
{
{
/* Don't add this scan if it doesn't improve selectivity. */
/* Don't add this scan if it doesn't improve selectivity. */
DBUG_PRINT
(
"info"
,
(
"The scan doesn't improve selectivity."
));
DBUG_PRINT
(
"info"
,
(
"The scan doesn't improve selectivity."
));
DBUG_RETURN
(
FALSE
);
DBUG_RETURN
(
false
);
}
}
info
->
records_fract
*=
selectivity_mult
;
info
->
out_rows
*=
selectivity_mult
;
ha_rows
cur_scan_records
=
info
->
param
->
table
->
quick_rows
[
ror_scan
->
keynr
];
DBUG_PRINT
(
"info"
,
(
"info->total_cost= %g"
,
info
->
total_cost
));
if
(
is_cpk_scan
)
if
(
is_cpk_scan
)
{
{
info
->
index_scan_costs
+=
rows2double
(
cur_scan_records
)
*
/*
CPK scan is used to filter out rows. We apply filtering for
each record of every scan. Assuming 1/TIME_FOR_COMPARE_ROWID
per check this gives us:
*/
info
->
index_scan_costs
+=
rows2double
(
info
->
index_records
)
/
TIME_FOR_COMPARE_ROWID
;
TIME_FOR_COMPARE_ROWID
;
}
}
else
else
{
{
info
->
index_records
+=
cur_scan_records
;
info
->
index_records
+=
info
->
param
->
table
->
quick_rows
[
ror_scan
->
keynr
]
;
info
->
index_scan_costs
+=
ror_scan
->
index_read_cost
;
info
->
index_scan_costs
+=
ror_scan
->
index_read_cost
;
bitmap_union
(
&
info
->
covered_fields
,
&
ror_scan
->
covered_fields
);
bitmap_union
(
&
info
->
covered_fields
,
&
ror_scan
->
covered_fields
);
}
if
(
!
info
->
is_covering
&&
bitmap_is_subset
(
&
info
->
param
->
needed_fields
,
&
info
->
covered_fields
))
if
(
!
info
->
is_covering
&&
bitmap_is_subset
(
&
info
->
param
->
needed_fields
,
{
&
info
->
covered_fields
))
DBUG_PRINT
(
"info"
,
(
"ROR-intersect is covering now"
));
{
info
->
is_covering
=
TRUE
;
DBUG_PRINT
(
"info"
,
(
"ROR-intersect is covering now"
));
}
info
->
is_covering
=
TRUE
;
}
}
info
->
total_cost
=
info
->
index_scan_costs
;
info
->
total_cost
=
info
->
index_scan_costs
;
DBUG_PRINT
(
"info"
,
(
"info->total_cost= %g"
,
info
->
total_cost
));
if
(
!
info
->
is_covering
)
if
(
!
info
->
is_covering
)
{
{
ha_rows
table_recs
=
info
->
param
->
table
->
file
->
records
;
info
->
total_cost
+=
info
->
total_cost
+=
get_sweep_read_cost
(
info
->
param
,
double2rows
(
info
->
out_rows
));
get_sweep_read_cost
(
info
->
param
,
DBUG_PRINT
(
"info"
,
(
"info->total_cost= %g"
,
info
->
total_cost
));
(
ha_rows
)(
info
->
records_fract
*
table_recs
));
}
}
DBUG_PRINT
(
"info"
,
(
"New
selectivity= %g"
,
info
->
records_fract
));
DBUG_PRINT
(
"info"
,
(
"New
out_rows= %g"
,
info
->
out_rows
));
DBUG_PRINT
(
"info"
,
(
"New cost= %g, %scovering"
,
info
->
total_cost
,
DBUG_PRINT
(
"info"
,
(
"New cost= %g, %scovering"
,
info
->
total_cost
,
info
->
is_covering
?
""
:
"non-"
));
info
->
is_covering
?
""
:
"non-"
));
DBUG_RETURN
(
TRUE
);
DBUG_RETURN
(
TRUE
);
...
@@ -2701,9 +2731,13 @@ bool ror_intersect_add(const PARAM *param, ROR_INTERSECT_INFO *info,
...
@@ -2701,9 +2731,13 @@ bool ror_intersect_add(const PARAM *param, ROR_INTERSECT_INFO *info,
a covering ROR-intersection)
a covering ROR-intersection)
NOTES
NOTES
get_key_scans_params must be called before for the same SEL_TREE before
get_key_scans_params must be called before this function can be called.
this function can be called.
When this function is called by ROR-union construction algorithm it
assumes it is building an uncovered ROR-intersection (and thus # of full
records to be retrieved is wrong here). This is a hack.
IMPLEMENTATION
The approximate best non-covering plan search algorithm is as follows:
The approximate best non-covering plan search algorithm is as follows:
find_min_ror_intersection_scan()
find_min_ror_intersection_scan()
...
@@ -2717,11 +2751,11 @@ bool ror_intersect_add(const PARAM *param, ROR_INTERSECT_INFO *info,
...
@@ -2717,11 +2751,11 @@ bool ror_intersect_add(const PARAM *param, ROR_INTERSECT_INFO *info,
min_scan= make_scan(S);
min_scan= make_scan(S);
while (R is not empty)
while (R is not empty)
{
{
if (!selectivity(S + first(R) < selectivity(S)))
firstR= R - first(R);
if (!selectivity(S + firstR < selectivity(S)))
continue;
continue;
S= S + first(R);
S= S + first(R);
R= R - first(R);
if (cost(S) < min_cost)
if (cost(S) < min_cost)
{
{
min_cost= cost(S);
min_cost= cost(S);
...
@@ -2752,15 +2786,15 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
...
@@ -2752,15 +2786,15 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
bool
*
are_all_covering
)
bool
*
are_all_covering
)
{
{
uint
idx
;
uint
idx
;
double
min_cost
=
read_time
;
double
min_cost
=
DBL_MAX
;
DBUG_ENTER
(
"get_best_ror_intersect"
);
DBUG_ENTER
(
"get_best_ror_intersect"
);
if
((
tree
->
n_ror_scans
<
2
)
||
!
param
->
table
->
file
->
records
)
if
((
tree
->
n_ror_scans
<
2
)
||
!
param
->
table
->
file
->
records
)
DBUG_RETURN
(
NULL
);
DBUG_RETURN
(
NULL
);
/*
/*
Collect ROR-able SEL_ARGs and create ROR_SCAN_INFO for each of them.
Step1: Collect ROR-able SEL_ARGs and create ROR_SCAN_INFO for each of
Also find and save clustered PK scan if there is one.
them.
Also find and save clustered PK scan if there is one.
*/
*/
ROR_SCAN_INFO
**
cur_ror_scan
;
ROR_SCAN_INFO
**
cur_ror_scan
;
ROR_SCAN_INFO
*
cpk_scan
=
NULL
;
ROR_SCAN_INFO
*
cpk_scan
=
NULL
;
...
@@ -2796,8 +2830,8 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
...
@@ -2796,8 +2830,8 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
tree
->
ror_scans_end
););
tree
->
ror_scans_end
););
/*
/*
Ok, [ror_scans, ror_scans_end) is array of ptrs to initialized
Ok, [ror_scans, ror_scans_end) is array of ptrs to initialized
ROR_SCAN_INFOs.
ROR_SCAN_INFO
'
s.
Now, get a minimal key sca
n using an approximate algorithm.
Step 2: Get best ROR-intersectio
n using an approximate algorithm.
*/
*/
qsort
(
tree
->
ror_scans
,
tree
->
n_ror_scans
,
sizeof
(
ROR_SCAN_INFO
*
),
qsort
(
tree
->
ror_scans
,
tree
->
n_ror_scans
,
sizeof
(
ROR_SCAN_INFO
*
),
(
qsort_cmp
)
cmp_ror_scan_info
);
(
qsort_cmp
)
cmp_ror_scan_info
);
...
@@ -2814,45 +2848,41 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
...
@@ -2814,45 +2848,41 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
intersect_scans_end
=
intersect_scans
;
intersect_scans_end
=
intersect_scans
;
/* Create and incrementally update ROR intersection. */
/* Create and incrementally update ROR intersection. */
ROR_INTERSECT_INFO
*
intersect
;
ROR_INTERSECT_INFO
*
intersect
,
*
intersect_best
;
if
(
!
(
intersect
=
ror_intersect_init
(
param
,
FALSE
)))
if
(
!
(
intersect
=
ror_intersect_init
(
param
))
||
!
(
intersect_best
=
ror_intersect_init
(
param
)))
return
NULL
;
return
NULL
;
/* [intersect_scans,
intersect_scans_best) will hold the best combina
tion */
/* [intersect_scans,
intersect_scans_best) will hold the best intersec
tion */
ROR_SCAN_INFO
**
intersect_scans_best
;
ROR_SCAN_INFO
**
intersect_scans_best
;
ha_rows
best_rows
;
bool
is_best_covering
;
double
best_index_scan_costs
;
LINT_INIT
(
best_rows
);
/* protected by intersect_scans_best */
LINT_INIT
(
is_best_covering
);
LINT_INIT
(
best_index_scan_costs
);
cur_ror_scan
=
tree
->
ror_scans
;
cur_ror_scan
=
tree
->
ror_scans
;
/* Start with one scan */
intersect_scans_best
=
intersect_scans
;
intersect_scans_best
=
intersect_scans
;
while
(
cur_ror_scan
!=
tree
->
ror_scans_end
&&
!
intersect
->
is_covering
)
while
(
cur_ror_scan
!=
tree
->
ror_scans_end
&&
!
intersect
->
is_covering
)
{
{
/* S= S + first(R); */
/* S= S + first(R); R= R - first(R); */
if
(
ror_intersect_add
(
param
,
intersect
,
*
cur_ror_scan
))
if
(
!
ror_intersect_add
(
intersect
,
*
cur_ror_scan
,
false
))
*
(
intersect_scans_end
++
)
=
*
cur_ror_scan
;
{
/* R= R - first(R); */
cur_ror_scan
++
;
cur_ror_scan
++
;
continue
;
}
*
(
intersect_scans_end
++
)
=
*
(
cur_ror_scan
++
);
if
(
intersect
->
total_cost
<
min_cost
)
if
(
intersect
->
total_cost
<
min_cost
)
{
{
/* Local minimum found, save it */
/* Local minimum found, save it */
min_cost
=
intersect
->
total_cost
;
ror_intersect_cpy
(
intersect_best
,
intersect
);
best_rows
=
(
ha_rows
)(
intersect
->
records_fract
*
rows2double
(
param
->
table
->
file
->
records
));
/* Prevent divisons by zero */
if
(
!
best_rows
)
best_rows
=
1
;
is_best_covering
=
intersect
->
is_covering
;
intersect_scans_best
=
intersect_scans_end
;
intersect_scans_best
=
intersect_scans_end
;
best_index_scan_costs
=
intersect
->
index_scan_costs
;
min_cost
=
intersect
->
total_cost
;
}
}
}
}
if
(
intersect_scans_best
==
intersect_scans
)
{
DBUG_PRINT
(
"info"
,
(
"None of scans increase selectivity"
));
DBUG_RETURN
(
NULL
);
}
DBUG_EXECUTE
(
"info"
,
print_ror_scans_arr
(
param
->
table
,
DBUG_EXECUTE
(
"info"
,
print_ror_scans_arr
(
param
->
table
,
"best ROR-intersection"
,
"best ROR-intersection"
,
intersect_scans
,
intersect_scans
,
...
@@ -2860,48 +2890,26 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
...
@@ -2860,48 +2890,26 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
*
are_all_covering
=
intersect
->
is_covering
;
*
are_all_covering
=
intersect
->
is_covering
;
uint
best_num
=
intersect_scans_best
-
intersect_scans
;
uint
best_num
=
intersect_scans_best
-
intersect_scans
;
ror_intersect_cpy
(
intersect
,
intersect_best
);
/*
/*
Ok, found the best ROR-intersection of non-CPK key scans.
Ok, found the best ROR-intersection of non-CPK key scans.
Check if we should add a CPK scan.
Check if we should add a CPK scan. If the obtained ROR-intersection is
covering, it doesn't make sense to add CPK scan.
If the obtained ROR-intersection is covering, it doesn't make sense
to add CPK scan - Clustered PK contains all fields and if we're doing
CPK scan doing other CPK scans will only add more overhead.
*/
*/
if
(
cpk_scan
&&
!
intersect
->
is_covering
)
if
(
cpk_scan
&&
!
intersect
->
is_covering
)
{
{
/*
if
(
ror_intersect_add
(
intersect
,
cpk_scan
,
TRUE
)
&&
Handle the special case: ROR-intersect(PRIMARY, key1) is
(
intersect
->
total_cost
<
min_cost
))
the best, but cost(range(key1)) > cost(best_non_ror_range_scan)
*/
if
(
best_num
==
0
)
{
cur_ror_scan
=
tree
->
ror_scans
;
intersect_scans_end
=
intersect_scans
;
ror_intersect_reinit
(
intersect
);
if
(
!
ror_intersect_add
(
param
,
intersect
,
*
cur_ror_scan
))
DBUG_RETURN
(
NULL
);
/* shouldn't happen actually */
*
(
intersect_scans_end
++
)
=
*
cur_ror_scan
;
best_num
++
;
}
if
(
ror_intersect_add
(
param
,
intersect
,
cpk_scan
))
{
{
cpk_scan_used
=
TRUE
;
cpk_scan_used
=
TRUE
;
min_cost
=
intersect
->
total_cost
;
intersect_best
=
intersect
;
//just set pointer here
best_rows
=
(
ha_rows
)(
intersect
->
records_fract
*
rows2double
(
param
->
table
->
file
->
records
));
/* Prevent divisons by zero */
if
(
!
best_rows
)
best_rows
=
1
;
is_best_covering
=
intersect
->
is_covering
;
best_index_scan_costs
=
intersect
->
index_scan_costs
;
}
}
}
}
/* Ok, return ROR-intersect plan if we have found one */
/* Ok, return ROR-intersect plan if we have found one */
TRP_ROR_INTERSECT
*
trp
=
NULL
;
TRP_ROR_INTERSECT
*
trp
=
NULL
;
if
(
best_num
>
1
||
cpk_scan_used
)
if
(
min_cost
<
read_time
&&
(
cpk_scan_used
||
best_num
>
1
)
)
{
{
if
(
!
(
trp
=
new
(
param
->
mem_root
)
TRP_ROR_INTERSECT
))
if
(
!
(
trp
=
new
(
param
->
mem_root
)
TRP_ROR_INTERSECT
))
DBUG_RETURN
(
trp
);
DBUG_RETURN
(
trp
);
...
@@ -2911,14 +2919,18 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
...
@@ -2911,14 +2919,18 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
DBUG_RETURN
(
NULL
);
DBUG_RETURN
(
NULL
);
memcpy
(
trp
->
first_scan
,
intersect_scans
,
best_num
*
sizeof
(
ROR_SCAN_INFO
*
));
memcpy
(
trp
->
first_scan
,
intersect_scans
,
best_num
*
sizeof
(
ROR_SCAN_INFO
*
));
trp
->
last_scan
=
trp
->
first_scan
+
best_num
;
trp
->
last_scan
=
trp
->
first_scan
+
best_num
;
trp
->
is_covering
=
is_best_covering
;
trp
->
is_covering
=
intersect_best
->
is_covering
;
trp
->
read_cost
=
min_cost
;
trp
->
read_cost
=
intersect_best
->
total_cost
;
/* Prevent divisons by zero */
ha_rows
best_rows
=
double2rows
(
intersect_best
->
out_rows
);
if
(
!
best_rows
)
best_rows
=
1
;
trp
->
records
=
best_rows
;
trp
->
records
=
best_rows
;
trp
->
index_scan_costs
=
best_
index_scan_costs
;
trp
->
index_scan_costs
=
intersect_best
->
index_scan_costs
;
trp
->
cpk_scan
=
cpk_scan
;
trp
->
cpk_scan
=
cpk_scan
_used
?
cpk_scan
:
NULL
;
DBUG_PRINT
(
"info"
,
DBUG_PRINT
(
"info"
,
(
"Returning non-covering ROR-intersect plan:"
(
"Returning non-covering ROR-intersect plan:
cost %g, records %lu"
,
"
cost %g, records %lu"
,
trp
->
read_cost
,
(
ulong
)
trp
->
records
));
trp
->
read_cost
,
(
ulong
)
trp
->
records
));
}
}
DBUG_RETURN
(
trp
);
DBUG_RETURN
(
trp
);
}
}
...
@@ -3145,8 +3157,9 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
...
@@ -3145,8 +3157,9 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
found_records
)
+
found_records
)
+
cpu_cost
;
cpu_cost
;
DBUG_PRINT
(
"info"
,(
"read_time: %g found_read_time: %g"
,
DBUG_PRINT
(
"info"
,(
"key %s: found_read_time: %g (cur. read_time: %g)"
,
read_time
,
found_read_time
));
param
->
table
->
key_info
[
keynr
].
name
,
found_read_time
,
read_time
));
if
(
read_time
>
found_read_time
&&
found_records
!=
HA_POS_ERROR
if
(
read_time
>
found_read_time
&&
found_records
!=
HA_POS_ERROR
/*|| read_time == DBL_MAX*/
)
/*|| read_time == DBL_MAX*/
)
...
...
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