MWL#17: Table elimination
- Continue addressing review feedback: remove "unusable KEYUSEs" extension as it is no longer needed. sql/item.h: MWL#17: Table elimination - Code cleanup sql/opt_table_elimination.cc: MWL#17: Table elimination - Code cleanup
This commit is contained in:
parent
854bb82bd8
commit
b032c7d833
12
sql/item.h
12
sql/item.h
@ -1017,18 +1017,6 @@ public:
|
|||||||
bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs);
|
bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs);
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
TABLE *table; /* Table of interest */
|
|
||||||
uint keyno; /* Index of interest */
|
|
||||||
uint forbidden_part; /* key part which one is not allowed to refer to */
|
|
||||||
/* [Set by processor] used tables, besides the table of interest */
|
|
||||||
table_map used_tables;
|
|
||||||
/* [Set by processor] Parts of index of interest that expression refers to */
|
|
||||||
uint needed_key_parts;
|
|
||||||
} Field_processor_info;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Data for Item::check_column_usage_processor */
|
/* Data for Item::check_column_usage_processor */
|
||||||
class Field_enumerator
|
class Field_enumerator
|
||||||
|
@ -1119,7 +1119,6 @@ void eliminate_tables(JOIN *join)
|
|||||||
case Func_dep::FD_OUTER_JOIN:
|
case Func_dep::FD_OUTER_JOIN:
|
||||||
{
|
{
|
||||||
Outer_join_dep *outer_join_dep= (Outer_join_dep*)bound_dep;
|
Outer_join_dep *outer_join_dep= (Outer_join_dep*)bound_dep;
|
||||||
/* TODO what do here? Stop if eliminated the top-level? */
|
|
||||||
mark_as_eliminated(te.join, outer_join_dep->table_list);
|
mark_as_eliminated(te.join, outer_join_dep->table_list);
|
||||||
Outer_join_dep *parent= outer_join_dep->parent;
|
Outer_join_dep *parent= outer_join_dep->parent;
|
||||||
if (parent &&
|
if (parent &&
|
||||||
@ -1236,38 +1235,6 @@ void dbug_print_deps(Table_elimination *te)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/***********************************************************************************************/
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void dbug_print_fdep(FUNC_DEP *fd)
|
|
||||||
{
|
|
||||||
switch (fd->type) {
|
|
||||||
case FUNC_DEP::FD_OUTER_JOIN:
|
|
||||||
{
|
|
||||||
fprintf(DBUG_FILE, "outer_join(");
|
|
||||||
if (fd->table_list->nested_join)
|
|
||||||
{
|
|
||||||
bool first= TRUE;
|
|
||||||
List_iterator<TABLE_LIST> it(fd->table_list->nested_join->join_list);
|
|
||||||
TABLE_LIST *tbl;
|
|
||||||
while ((tbl= it++))
|
|
||||||
{
|
|
||||||
fprintf(DBUG_FILE, "%s%s", first?"":" ",
|
|
||||||
tbl->table? tbl->table->alias : "...");
|
|
||||||
first= FALSE;
|
|
||||||
}
|
|
||||||
fprintf(DBUG_FILE, ")");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
fprintf(DBUG_FILE, "%s", fd->table_list->table->alias);
|
|
||||||
fprintf(DBUG_FILE, ")");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@} (end of group Table_Elimination)
|
@} (end of group Table_Elimination)
|
||||||
*/
|
*/
|
||||||
|
@ -2474,7 +2474,6 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
|
|||||||
DBUG_RETURN(HA_POS_ERROR); /* This shouldn't happend */
|
DBUG_RETURN(HA_POS_ERROR); /* This shouldn't happend */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This structure is used to collect info on potentially sargable
|
This structure is used to collect info on potentially sargable
|
||||||
predicates in order to check whether they become sargable after
|
predicates in order to check whether they become sargable after
|
||||||
@ -2762,16 +2761,14 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
|
|||||||
{
|
{
|
||||||
start_keyuse=keyuse;
|
start_keyuse=keyuse;
|
||||||
key=keyuse->key;
|
key=keyuse->key;
|
||||||
if (keyuse->type == KEYUSE_USABLE)
|
s->keys.set_bit(key); // QQ: remove this ?
|
||||||
s->keys.set_bit(key); // QQ: remove this ?
|
|
||||||
|
|
||||||
refs=0;
|
refs=0;
|
||||||
const_ref.clear_all();
|
const_ref.clear_all();
|
||||||
eq_part.clear_all();
|
eq_part.clear_all();
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (keyuse->type == KEYUSE_USABLE &&
|
if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
|
||||||
keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
|
|
||||||
{
|
{
|
||||||
if (!((~found_const_table_map) & keyuse->used_tables))
|
if (!((~found_const_table_map) & keyuse->used_tables))
|
||||||
const_ref.set_bit(keyuse->keypart);
|
const_ref.set_bit(keyuse->keypart);
|
||||||
@ -2971,9 +2968,11 @@ typedef struct key_field_t {
|
|||||||
*/
|
*/
|
||||||
bool null_rejecting;
|
bool null_rejecting;
|
||||||
bool *cond_guard; /* See KEYUSE::cond_guard */
|
bool *cond_guard; /* See KEYUSE::cond_guard */
|
||||||
enum keyuse_type type; /* See KEYUSE::type */
|
|
||||||
} KEY_FIELD;
|
} KEY_FIELD;
|
||||||
|
|
||||||
|
/* Values in optimize */
|
||||||
|
#define KEY_OPTIMIZE_EXISTS 1
|
||||||
|
#define KEY_OPTIMIZE_REF_OR_NULL 2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Merge new key definitions to old ones, remove those not used in both.
|
Merge new key definitions to old ones, remove those not used in both.
|
||||||
@ -3064,18 +3063,13 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
|
|||||||
KEY_OPTIMIZE_REF_OR_NULL));
|
KEY_OPTIMIZE_REF_OR_NULL));
|
||||||
old->null_rejecting= (old->null_rejecting &&
|
old->null_rejecting= (old->null_rejecting &&
|
||||||
new_fields->null_rejecting);
|
new_fields->null_rejecting);
|
||||||
/*
|
|
||||||
The conditions are the same, hence their usabilities should
|
|
||||||
be, too (TODO: shouldn't that apply to the above
|
|
||||||
null_rejecting and optimize attributes?)
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(old->type == new_fields->type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (old->eq_func && new_fields->eq_func &&
|
else if (old->eq_func && new_fields->eq_func &&
|
||||||
old->val->eq_by_collation(new_fields->val,
|
old->val->eq_by_collation(new_fields->val,
|
||||||
old->field->binary(),
|
old->field->binary(),
|
||||||
old->field->charset()))
|
old->field->charset()))
|
||||||
|
|
||||||
{
|
{
|
||||||
old->level= and_level;
|
old->level= and_level;
|
||||||
old->optimize= ((old->optimize & new_fields->optimize &
|
old->optimize= ((old->optimize & new_fields->optimize &
|
||||||
@ -3084,15 +3078,10 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
|
|||||||
KEY_OPTIMIZE_REF_OR_NULL));
|
KEY_OPTIMIZE_REF_OR_NULL));
|
||||||
old->null_rejecting= (old->null_rejecting &&
|
old->null_rejecting= (old->null_rejecting &&
|
||||||
new_fields->null_rejecting);
|
new_fields->null_rejecting);
|
||||||
// "t.key_col=const" predicates are always usable
|
|
||||||
DBUG_ASSERT(old->type == KEYUSE_USABLE &&
|
|
||||||
new_fields->type == KEYUSE_USABLE);
|
|
||||||
}
|
}
|
||||||
else if (old->eq_func && new_fields->eq_func &&
|
else if (old->eq_func && new_fields->eq_func &&
|
||||||
((new_fields->type == KEYUSE_USABLE &&
|
((old->val->const_item() && old->val->is_null()) ||
|
||||||
old->val->const_item() && old->val->is_null()) ||
|
new_fields->val->is_null()))
|
||||||
((old->type == KEYUSE_USABLE && new_fields->val->is_null()))))
|
|
||||||
/* TODO ^ why is the above asymmetric, why const_item()? */
|
|
||||||
{
|
{
|
||||||
/* field = expression OR field IS NULL */
|
/* field = expression OR field IS NULL */
|
||||||
old->level= and_level;
|
old->level= and_level;
|
||||||
@ -3163,7 +3152,6 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
|
|||||||
table_map usable_tables, SARGABLE_PARAM **sargables)
|
table_map usable_tables, SARGABLE_PARAM **sargables)
|
||||||
{
|
{
|
||||||
uint exists_optimize= 0;
|
uint exists_optimize= 0;
|
||||||
bool optimizable=0;
|
|
||||||
if (!(field->flags & PART_KEY_FLAG))
|
if (!(field->flags & PART_KEY_FLAG))
|
||||||
{
|
{
|
||||||
// Don't remove column IS NULL on a LEFT JOIN table
|
// Don't remove column IS NULL on a LEFT JOIN table
|
||||||
@ -3176,12 +3164,15 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
table_map used_tables=0;
|
table_map used_tables=0;
|
||||||
|
bool optimizable=0;
|
||||||
for (uint i=0; i<num_values; i++)
|
for (uint i=0; i<num_values; i++)
|
||||||
{
|
{
|
||||||
used_tables|=(value[i])->used_tables();
|
used_tables|=(value[i])->used_tables();
|
||||||
if (!((value[i])->used_tables() & (field->table->map | RAND_TABLE_BIT)))
|
if (!((value[i])->used_tables() & (field->table->map | RAND_TABLE_BIT)))
|
||||||
optimizable=1;
|
optimizable=1;
|
||||||
}
|
}
|
||||||
|
if (!optimizable)
|
||||||
|
return;
|
||||||
if (!(usable_tables & field->table->map))
|
if (!(usable_tables & field->table->map))
|
||||||
{
|
{
|
||||||
if (!eq_func || (*value)->type() != Item::NULL_ITEM ||
|
if (!eq_func || (*value)->type() != Item::NULL_ITEM ||
|
||||||
@ -3194,8 +3185,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
|
|||||||
JOIN_TAB *stat=field->table->reginfo.join_tab;
|
JOIN_TAB *stat=field->table->reginfo.join_tab;
|
||||||
key_map possible_keys=field->key_start;
|
key_map possible_keys=field->key_start;
|
||||||
possible_keys.intersect(field->table->keys_in_use_for_query);
|
possible_keys.intersect(field->table->keys_in_use_for_query);
|
||||||
if (optimizable)
|
stat[0].keys.merge(possible_keys); // Add possible keys
|
||||||
stat[0].keys.merge(possible_keys); // Add possible keys
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Save the following cases:
|
Save the following cases:
|
||||||
@ -3288,7 +3278,6 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
|
|||||||
(*key_fields)->val= *value;
|
(*key_fields)->val= *value;
|
||||||
(*key_fields)->level= and_level;
|
(*key_fields)->level= and_level;
|
||||||
(*key_fields)->optimize= exists_optimize;
|
(*key_fields)->optimize= exists_optimize;
|
||||||
(*key_fields)->type= optimizable? KEYUSE_USABLE : KEYUSE_UNKNOWN;
|
|
||||||
/*
|
/*
|
||||||
If the condition has form "tbl.keypart = othertbl.field" and
|
If the condition has form "tbl.keypart = othertbl.field" and
|
||||||
othertbl.field can be NULL, there will be no matches if othertbl.field
|
othertbl.field can be NULL, there will be no matches if othertbl.field
|
||||||
@ -3600,7 +3589,6 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
|
|||||||
keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL;
|
keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL;
|
||||||
keyuse.null_rejecting= key_field->null_rejecting;
|
keyuse.null_rejecting= key_field->null_rejecting;
|
||||||
keyuse.cond_guard= key_field->cond_guard;
|
keyuse.cond_guard= key_field->cond_guard;
|
||||||
keyuse.type= key_field->type;
|
|
||||||
VOID(insert_dynamic(keyuse_array,(uchar*) &keyuse));
|
VOID(insert_dynamic(keyuse_array,(uchar*) &keyuse));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3609,6 +3597,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define FT_KEYPART (MAX_REF_PARTS+10)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
|
add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
|
||||||
@ -3667,7 +3656,6 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
|
|||||||
keyuse.used_tables=cond_func->key_item()->used_tables();
|
keyuse.used_tables=cond_func->key_item()->used_tables();
|
||||||
keyuse.optimize= 0;
|
keyuse.optimize= 0;
|
||||||
keyuse.keypart_map= 0;
|
keyuse.keypart_map= 0;
|
||||||
keyuse.type= KEYUSE_USABLE;
|
|
||||||
VOID(insert_dynamic(keyuse_array,(uchar*) &keyuse));
|
VOID(insert_dynamic(keyuse_array,(uchar*) &keyuse));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3682,13 +3670,6 @@ sort_keyuse(KEYUSE *a,KEYUSE *b)
|
|||||||
return (int) (a->key - b->key);
|
return (int) (a->key - b->key);
|
||||||
if (a->keypart != b->keypart)
|
if (a->keypart != b->keypart)
|
||||||
return (int) (a->keypart - b->keypart);
|
return (int) (a->keypart - b->keypart);
|
||||||
|
|
||||||
// Usable ones go before the unusable
|
|
||||||
int a_ok= test(a->type == KEYUSE_USABLE);
|
|
||||||
int b_ok= test(b->type == KEYUSE_USABLE);
|
|
||||||
if (a_ok != b_ok)
|
|
||||||
return a_ok? -1 : 1;
|
|
||||||
|
|
||||||
// Place const values before other ones
|
// Place const values before other ones
|
||||||
if ((res= test((a->used_tables & ~OUTER_REF_TABLE_BIT)) -
|
if ((res= test((a->used_tables & ~OUTER_REF_TABLE_BIT)) -
|
||||||
test((b->used_tables & ~OUTER_REF_TABLE_BIT))))
|
test((b->used_tables & ~OUTER_REF_TABLE_BIT))))
|
||||||
@ -3899,8 +3880,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||||||
found_eq_constant=0;
|
found_eq_constant=0;
|
||||||
for (i=0 ; i < keyuse->elements-1 ; i++,use++)
|
for (i=0 ; i < keyuse->elements-1 ; i++,use++)
|
||||||
{
|
{
|
||||||
if (use->type == KEYUSE_USABLE && !use->used_tables &&
|
if (!use->used_tables && use->optimize != KEY_OPTIMIZE_REF_OR_NULL)
|
||||||
use->optimize != KEY_OPTIMIZE_REF_OR_NULL)
|
|
||||||
use->table->const_key_parts[use->key]|= use->keypart_map;
|
use->table->const_key_parts[use->key]|= use->keypart_map;
|
||||||
if (use->keypart != FT_KEYPART)
|
if (use->keypart != FT_KEYPART)
|
||||||
{
|
{
|
||||||
@ -3924,8 +3904,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||||||
/* Save ptr to first use */
|
/* Save ptr to first use */
|
||||||
if (!use->table->reginfo.join_tab->keyuse)
|
if (!use->table->reginfo.join_tab->keyuse)
|
||||||
use->table->reginfo.join_tab->keyuse=save_pos;
|
use->table->reginfo.join_tab->keyuse=save_pos;
|
||||||
if (use->type == KEYUSE_USABLE)
|
use->table->reginfo.join_tab->checked_keys.set_bit(use->key);
|
||||||
use->table->reginfo.join_tab->checked_keys.set_bit(use->key);
|
|
||||||
save_pos++;
|
save_pos++;
|
||||||
}
|
}
|
||||||
i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
|
i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
|
||||||
@ -3955,7 +3934,7 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
|
|||||||
To avoid bad matches, we don't make ref_table_rows less than 100.
|
To avoid bad matches, we don't make ref_table_rows less than 100.
|
||||||
*/
|
*/
|
||||||
keyuse->ref_table_rows= ~(ha_rows) 0; // If no ref
|
keyuse->ref_table_rows= ~(ha_rows) 0; // If no ref
|
||||||
if (keyuse->type == KEYUSE_USABLE && keyuse->used_tables &
|
if (keyuse->used_tables &
|
||||||
(map= (keyuse->used_tables & ~join->const_table_map &
|
(map= (keyuse->used_tables & ~join->const_table_map &
|
||||||
~OUTER_REF_TABLE_BIT)))
|
~OUTER_REF_TABLE_BIT)))
|
||||||
{
|
{
|
||||||
@ -4147,8 +4126,7 @@ best_access_path(JOIN *join,
|
|||||||
if 1. expression doesn't refer to forward tables
|
if 1. expression doesn't refer to forward tables
|
||||||
2. we won't get two ref-or-null's
|
2. we won't get two ref-or-null's
|
||||||
*/
|
*/
|
||||||
if (keyuse->type == KEYUSE_USABLE &&
|
if (!(remaining_tables & keyuse->used_tables) &&
|
||||||
!(remaining_tables & keyuse->used_tables) &&
|
|
||||||
!(ref_or_null_part && (keyuse->optimize &
|
!(ref_or_null_part && (keyuse->optimize &
|
||||||
KEY_OPTIMIZE_REF_OR_NULL)))
|
KEY_OPTIMIZE_REF_OR_NULL)))
|
||||||
{
|
{
|
||||||
@ -5602,8 +5580,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
|||||||
*/
|
*/
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!(~used_tables & keyuse->used_tables) &&
|
if (!(~used_tables & keyuse->used_tables))
|
||||||
keyuse->type == KEYUSE_USABLE)
|
|
||||||
{
|
{
|
||||||
if (keyparts == keyuse->keypart &&
|
if (keyparts == keyuse->keypart &&
|
||||||
!(found_part_ref_or_null & keyuse->optimize))
|
!(found_part_ref_or_null & keyuse->optimize))
|
||||||
@ -5653,11 +5630,9 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
|||||||
uint i;
|
uint i;
|
||||||
for (i=0 ; i < keyparts ; keyuse++,i++)
|
for (i=0 ; i < keyparts ; keyuse++,i++)
|
||||||
{
|
{
|
||||||
while (keyuse->keypart != i || ((~used_tables) & keyuse->used_tables) ||
|
while (keyuse->keypart != i ||
|
||||||
!(keyuse->type == KEYUSE_USABLE))
|
((~used_tables) & keyuse->used_tables))
|
||||||
{
|
|
||||||
keyuse++; /* Skip other parts */
|
keyuse++; /* Skip other parts */
|
||||||
}
|
|
||||||
|
|
||||||
uint maybe_null= test(keyinfo->key_part[i].null_bit);
|
uint maybe_null= test(keyinfo->key_part[i].null_bit);
|
||||||
j->ref.items[i]=keyuse->val; // Save for cond removal
|
j->ref.items[i]=keyuse->val; // Save for cond removal
|
||||||
|
@ -28,45 +28,6 @@
|
|||||||
#include "procedure.h"
|
#include "procedure.h"
|
||||||
#include <myisam.h>
|
#include <myisam.h>
|
||||||
|
|
||||||
#define FT_KEYPART (MAX_REF_PARTS+10)
|
|
||||||
/* Values in optimize */
|
|
||||||
#define KEY_OPTIMIZE_EXISTS 1
|
|
||||||
#define KEY_OPTIMIZE_REF_OR_NULL 2
|
|
||||||
|
|
||||||
/* KEYUSE element types */
|
|
||||||
enum keyuse_type
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
val refers to the same table, this is either KEYUSE_BIND or KEYUSE_NO_BIND
|
|
||||||
type, we didn't determine which one yet.
|
|
||||||
*/
|
|
||||||
KEYUSE_UNKNOWN= 0,
|
|
||||||
/*
|
|
||||||
'regular' keyuse, i.e. it represents one of the following
|
|
||||||
* t.keyXpartY = func(constants, other-tables)
|
|
||||||
* t.keyXpartY IS NULL
|
|
||||||
* t.keyXpartY = func(constants, other-tables) OR t.keyXpartY IS NULL
|
|
||||||
and can be used to construct ref acces
|
|
||||||
*/
|
|
||||||
KEYUSE_USABLE,
|
|
||||||
/*
|
|
||||||
The keyuse represents a condition in form:
|
|
||||||
|
|
||||||
t.uniq_keyXpartY = func(other parts of uniq_keyX)
|
|
||||||
|
|
||||||
This can't be used to construct uniq_keyX but we could use it to determine
|
|
||||||
that the table will produce at most one match.
|
|
||||||
*/
|
|
||||||
KEYUSE_BIND,
|
|
||||||
/*
|
|
||||||
Keyuse that's not usable for ref access and doesn't meet the criteria of
|
|
||||||
KEYUSE_BIND. Examples:
|
|
||||||
t.keyXpartY = func(t.keyXpartY)
|
|
||||||
t.keyXpartY = func(column of t that's not covered by keyX)
|
|
||||||
*/
|
|
||||||
KEYUSE_NO_BIND
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct keyuse_t {
|
typedef struct keyuse_t {
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
Item *val; /**< or value if no field */
|
Item *val; /**< or value if no field */
|
||||||
@ -90,15 +51,6 @@ typedef struct keyuse_t {
|
|||||||
NULL - Otherwise (the source equality can't be turned off)
|
NULL - Otherwise (the source equality can't be turned off)
|
||||||
*/
|
*/
|
||||||
bool *cond_guard;
|
bool *cond_guard;
|
||||||
/*
|
|
||||||
1 <=> This keyuse can be used to construct key access.
|
|
||||||
0 <=> Otherwise. Currently unusable KEYUSEs represent equalities
|
|
||||||
where one table column refers to another one, like this:
|
|
||||||
t.keyXpartA=func(t.keyXpartB)
|
|
||||||
This equality cannot be used for index access but is useful
|
|
||||||
for table elimination.
|
|
||||||
*/
|
|
||||||
enum keyuse_type type;
|
|
||||||
} KEYUSE;
|
} KEYUSE;
|
||||||
|
|
||||||
class store_key;
|
class store_key;
|
||||||
@ -258,7 +210,7 @@ typedef struct st_join_table {
|
|||||||
JOIN *join;
|
JOIN *join;
|
||||||
/** Bitmap of nested joins this table is part of */
|
/** Bitmap of nested joins this table is part of */
|
||||||
nested_join_map embedding_map;
|
nested_join_map embedding_map;
|
||||||
|
|
||||||
void cleanup();
|
void cleanup();
|
||||||
inline bool is_using_loose_index_scan()
|
inline bool is_using_loose_index_scan()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user