1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-5.1-opt

into  mysql.com:/home/psergey/mysql-5.1-bug14940-r10a


sql/sql_select.cc:
  Auto merged
This commit is contained in:
unknown
2006-09-29 18:35:03 +04:00
4 changed files with 160 additions and 13 deletions

View File

@@ -70,7 +70,7 @@ static int join_tab_cmp_straight(const void* ptr1, const void* ptr2);
static void find_best(JOIN *join,table_map rest_tables,uint index,
double record_count,double read_time);
static uint cache_record_length(JOIN *join,uint index);
static double prev_record_reads(JOIN *join,table_map found_ref);
static double prev_record_reads(JOIN *join, uint idx, table_map found_ref);
static bool get_best_combination(JOIN *join);
static store_key *get_store_key(THD *thd,
KEYUSE *keyuse, table_map used_tables,
@@ -3426,6 +3426,7 @@ set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
join->positions[idx].table= table;
join->positions[idx].key=key;
join->positions[idx].records_read=1.0; /* This is a const table */
join->positions[idx].ref_depend_map= 0;
/* Move the const table as down as possible in best_ref */
JOIN_TAB **pos=join->best_ref+idx+1;
@@ -3483,6 +3484,7 @@ best_access_path(JOIN *join,
double best= DBL_MAX;
double best_time= DBL_MAX;
double records= DBL_MAX;
table_map best_ref_depends_map;
double tmp;
ha_rows rec;
@@ -3511,13 +3513,20 @@ best_access_path(JOIN *join,
/* Calculate how many key segments of the current key we can use */
start_key= keyuse;
do
{ /* for each keypart */
do /* For each keypart */
{
uint keypart= keyuse->keypart;
table_map best_part_found_ref= 0;
double best_prev_record_reads= DBL_MAX;
do
do /* For each way to access the keypart */
{
/*
if 1. expression doesn't refer to forward tables
2. we won't get two ref-or-null's
*/
if (!(remaining_tables & keyuse->used_tables) &&
!(ref_or_null_part && (keyuse->optimize &
KEY_OPTIMIZE_REF_OR_NULL)))
@@ -3525,8 +3534,9 @@ best_access_path(JOIN *join,
found_part|= keyuse->keypart_map;
if (!(keyuse->used_tables & ~join->const_table_map))
const_part|= keyuse->keypart_map;
double tmp= prev_record_reads(join, (found_ref |
keyuse->used_tables));
double tmp= prev_record_reads(join, idx, (found_ref |
keyuse->used_tables));
if (tmp < best_prev_record_reads)
{
best_part_found_ref= keyuse->used_tables & ~join->const_table_map;
@@ -3565,7 +3575,7 @@ best_access_path(JOIN *join,
Really, there should be records=0.0 (yes!)
but 1.0 would be probably safer
*/
tmp= prev_record_reads(join, found_ref);
tmp= prev_record_reads(join, idx, found_ref);
records= 1.0;
}
else
@@ -3580,7 +3590,7 @@ best_access_path(JOIN *join,
max_key_part= (uint) ~0;
if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
{
tmp = prev_record_reads(join, found_ref);
tmp = prev_record_reads(join, idx, found_ref);
records=1.0;
}
else
@@ -3833,6 +3843,7 @@ best_access_path(JOIN *join,
best_records= records;
best_key= start_key;
best_max_key_part= max_key_part;
best_ref_depends_map= found_ref;
}
}
records= best_records;
@@ -3961,6 +3972,8 @@ best_access_path(JOIN *join,
best= tmp;
records= rows2double(rnd_records);
best_key= 0;
/* range/index_merge/ALL/index access method are "independent", so: */
best_ref_depends_map= 0;
}
}
@@ -3969,6 +3982,7 @@ best_access_path(JOIN *join,
join->positions[idx].read_time= best;
join->positions[idx].key= best_key;
join->positions[idx].table= s;
join->positions[idx].ref_depend_map= best_ref_depends_map;
if (!best_key &&
idx == join->const_tables &&
@@ -4736,17 +4750,85 @@ cache_record_length(JOIN *join,uint idx)
}
/*
Get the number of different row combinations for subset of partial join
SYNOPSIS
prev_record_reads()
join The join structure
idx Number of tables in the partial join order (i.e. the
partial join order is in join->positions[0..idx-1])
found_ref Bitmap of tables for which we need to find # of distinct
row combinations.
DESCRIPTION
Given a partial join order (in join->positions[0..idx-1]) and a subset of
tables within that join order (specified in found_ref), find out how many
distinct row combinations of subset tables will be in the result of the
partial join order.
This is used as follows: Suppose we have a table accessed with a ref-based
method. The ref access depends on current rows of tables in found_ref.
We want to count # of different ref accesses. We assume two ref accesses
will be different if at least one of access parameters is different.
Example: consider a query
SELECT * FROM t1, t2, t3 WHERE t1.key=c1 AND t2.key=c2 AND t3.key=t1.field
and a join order:
t1, ref access on t1.key=c1
t2, ref access on t2.key=c2
t3, ref access on t3.key=t1.field
For t1: n_ref_scans = 1, n_distinct_ref_scans = 1
For t2: n_ref_scans = records_read(t1), n_distinct_ref_scans=1
For t3: n_ref_scans = records_read(t1)*records_read(t2)
n_distinct_ref_scans = #records_read(t1)
The reason for having this function (at least the latest version of it)
is that we need to account for buffering in join execution.
An edge-case example: if we have a non-first table in join accessed via
ref(const) or ref(param) where there is a small number of different
values of param, then the access will likely hit the disk cache and will
not require any disk seeks.
The proper solution would be to assume an LRU disk cache of some size,
calculate probability of cache hits, etc. For now we just count
identical ref accesses as one.
RETURN
Expected number of row combinations
*/
static double
prev_record_reads(JOIN *join,table_map found_ref)
prev_record_reads(JOIN *join, uint idx, table_map found_ref)
{
double found=1.0;
found_ref&= ~OUTER_REF_TABLE_BIT;
for (POSITION *pos=join->positions ; found_ref ; pos++)
POSITION *pos_end= join->positions - 1;
for (POSITION *pos= join->positions + idx - 1; pos != pos_end; pos--)
{
if (pos->table->table->map & found_ref)
{
found_ref&= ~pos->table->table->map;
found*=pos->records_read;
found_ref|= pos->ref_depend_map;
/*
For the case of "t1 LEFT JOIN t2 ON ..." where t2 is a const table
with no matching row we will get position[t2].records_read==0.
Actually the size of output is one null-complemented row, therefore
we will use value of 1 whenever we get records_read==0.
Note
- the above case can't occur if inner part of outer join has more
than one table: table with no matches will not be marked as const.
- Ideally we should add 1 to records_read for every possible null-
complemented row. We're not doing it because: 1. it will require
non-trivial code and add overhead. 2. The value of records_read
is an inprecise estimate and adding 1 (or, in the worst case,
#max_nested_outer_joins=64-1) will not make it any more precise.
*/
if (pos->records_read)
found*= pos->records_read;
}
}
return found;
@@ -10496,6 +10578,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
tab->info="const row not found";
/* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0;
pos->ref_depend_map= 0;
if (!table->maybe_null || error > 0)
DBUG_RETURN(error);
}
@@ -10521,6 +10604,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
tab->info="unique row not found";
/* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0;
pos->ref_depend_map= 0;
if (!table->maybe_null || error > 0)
DBUG_RETURN(error);
}