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
3f5b4949
Commit
3f5b4949
authored
Aug 20, 2009
by
Sergey Petrunya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MWL#17: Table elimination
- Multiple-equality handling
parent
46c96776
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
299 additions
and
119 deletions
+299
-119
sql/item_cmpfunc.h
sql/item_cmpfunc.h
+1
-0
sql/opt_table_elimination.cc
sql/opt_table_elimination.cc
+298
-119
No files found.
sql/item_cmpfunc.h
View file @
3f5b4949
...
...
@@ -1578,6 +1578,7 @@ public:
uint
members
();
bool
contains
(
Field
*
field
);
Item_field
*
get_first
()
{
return
fields
.
head
();
}
uint
n_fields
()
{
return
fields
.
elements
;
}
void
merge
(
Item_equal
*
item
);
void
update_const
();
enum
Functype
functype
()
const
{
return
MULT_EQUAL_FUNC
;
}
...
...
sql/opt_table_elimination.cc
View file @
3f5b4949
...
...
@@ -175,7 +175,10 @@ public:
field_index
*/
Field_value
*
next_table_field
;
uint
bitmap_offset
;
/* Offset of our part of the bitmap */
/*
Offset of our part of the bitmap psergey-todo: better comment!
*/
uint
bitmap_offset
;
/*
Field became known. Check out
...
...
@@ -214,10 +217,6 @@ public:
class
Module_dep
:
public
Sql_alloc
{
public:
enum
{
MODULE_OUTER_JOIN
}
type
;
/* Type of the object */
virtual
bool
now_bound
(
Func_dep_analyzer
*
fda
,
Value_dep
**
bound_modules
)
=
0
;
virtual
~
Module_dep
(){}
/*
...
...
@@ -232,8 +231,10 @@ public:
/*
A "tbl.column= expr" equality dependency. tbl.column depends on fields
used in expr.
This represents either
- "tbl.column= expr" equality dependency, i.e. tbl.column depends on fields
used in the expression, or
- tbl1.col1=tbl2.col2=... multi-equality.
*/
class
Equality_module
:
public
Module_dep
{
...
...
@@ -241,6 +242,8 @@ public:
Field_value
*
field
;
Item
*
expression
;
List
<
Field_value
>
*
mult_equal_fields
;
/* Used during condition analysis only, similar to KEYUSE::level */
uint
level
;
bool
now_bound
(
Func_dep_analyzer
*
fda
,
Value_dep
**
bound_values
);
...
...
@@ -331,7 +334,7 @@ bool check_func_dependency(JOIN *join,
Item
*
cond
);
static
void
build_eq_mods_for_cond
(
Func_dep_analyzer
*
fda
,
Equality_module
**
fdeps
,
void
build_eq_mods_for_cond
(
Func_dep_analyzer
*
fda
,
Equality_module
**
eq_mod
,
uint
*
and_level
,
Item
*
cond
);
static
void
add_eq_mod
(
Func_dep_analyzer
*
fda
,
Equality_module
**
eq_mod
,
...
...
@@ -346,6 +349,9 @@ static Table_value *get_table_value(Func_dep_analyzer *fda, TABLE *table);
static
Field_value
*
get_field_value
(
Func_dep_analyzer
*
fda
,
Field
*
field
);
static
void
mark_as_eliminated
(
JOIN
*
join
,
TABLE_LIST
*
tbl
);
static
void
add_eq_mod2
(
Func_dep_analyzer
*
fda
,
Equality_module
**
eq_mod
,
uint
and_level
,
Field_value
*
field_val
,
Item
*
right
,
List
<
Field_value
>*
mult_equal_fields
);
#ifndef DBUG_OFF
...
...
@@ -360,7 +366,7 @@ static void dbug_print_deps(Func_dep_analyzer *fda);
SYNOPSIS
build_eq_mods_for_cond()
fda Table elimination context
fdeps
INOUT Put produced equality conditions here
eq_mod
INOUT Put produced equality conditions here
and_level INOUT AND-level (like in add_key_fields)
cond Condition to process
...
...
@@ -369,34 +375,34 @@ static void dbug_print_deps(Func_dep_analyzer *fda);
*/
static
void
build_eq_mods_for_cond
(
Func_dep_analyzer
*
fda
,
Equality_module
**
fdeps
,
void
build_eq_mods_for_cond
(
Func_dep_analyzer
*
fda
,
Equality_module
**
eq_mod
,
uint
*
and_level
,
Item
*
cond
)
{
if
(
cond
->
type
()
==
Item_func
::
COND_ITEM
)
{
List_iterator_fast
<
Item
>
li
(
*
((
Item_cond
*
)
cond
)
->
argument_list
());
Equality_module
*
org_key_fields
=
*
fdeps
;
Equality_module
*
org_key_fields
=
*
eq_mod
;
/* AND/OR */
if
(((
Item_cond
*
)
cond
)
->
functype
()
==
Item_func
::
COND_AND_FUNC
)
{
Item
*
item
;
while
((
item
=
li
++
))
build_eq_mods_for_cond
(
fda
,
fdeps
,
and_level
,
item
);
for
(;
org_key_fields
!=
*
fdeps
;
org_key_fields
++
)
build_eq_mods_for_cond
(
fda
,
eq_mod
,
and_level
,
item
);
for
(;
org_key_fields
!=
*
eq_mod
;
org_key_fields
++
)
org_key_fields
->
level
=
*
and_level
;
}
else
{
Item
*
item
;
(
*
and_level
)
++
;
build_eq_mods_for_cond
(
fda
,
fdeps
,
and_level
,
li
++
);
build_eq_mods_for_cond
(
fda
,
eq_mod
,
and_level
,
li
++
);
while
((
item
=
li
++
))
{
Equality_module
*
start_key_fields
=
*
fdeps
;
Equality_module
*
start_key_fields
=
*
eq_mod
;
(
*
and_level
)
++
;
build_eq_mods_for_cond
(
fda
,
fdeps
,
and_level
,
item
);
*
fdeps
=
merge_func_deps
(
org_key_fields
,
start_key_fields
,
*
fdeps
,
build_eq_mods_for_cond
(
fda
,
eq_mod
,
and_level
,
item
);
*
eq_mod
=
merge_func_deps
(
org_key_fields
,
start_key_fields
,
*
eq_mod
,
++
(
*
and_level
));
}
}
...
...
@@ -414,8 +420,8 @@ void build_eq_mods_for_cond(Func_dep_analyzer *fda, Equality_module **fdeps,
{
if
(
cond_func
->
argument_count
()
==
2
)
{
add_eq_mod
(
fda
,
fdeps
,
*
and_level
,
cond_func
,
args
[
0
],
args
[
1
]);
add_eq_mod
(
fda
,
fdeps
,
*
and_level
,
cond_func
,
args
[
1
],
args
[
0
]);
add_eq_mod
(
fda
,
eq_mod
,
*
and_level
,
cond_func
,
args
[
0
],
args
[
1
]);
add_eq_mod
(
fda
,
eq_mod
,
*
and_level
,
cond_func
,
args
[
1
],
args
[
0
]);
}
break
;
}
...
...
@@ -426,62 +432,72 @@ void build_eq_mods_for_cond(Func_dep_analyzer *fda, Equality_module **fdeps,
(
fld
=
args
[
0
]
->
real_item
())
->
type
()
==
Item
::
FIELD_ITEM
&&
args
[
1
]
->
eq
(
args
[
2
],
((
Item_field
*
)
fld
)
->
field
->
binary
()))
{
add_eq_mod
(
fda
,
fdeps
,
*
and_level
,
cond_func
,
args
[
0
],
args
[
1
]);
add_eq_mod
(
fda
,
fdeps
,
*
and_level
,
cond_func
,
args
[
1
],
args
[
0
]);
add_eq_mod
(
fda
,
eq_mod
,
*
and_level
,
cond_func
,
args
[
0
],
args
[
1
]);
add_eq_mod
(
fda
,
eq_mod
,
*
and_level
,
cond_func
,
args
[
1
],
args
[
0
]);
}
break
;
}
case
Item_func
:
:
EQ_FUNC
:
case
Item_func
:
:
EQUAL_FUNC
:
{
add_eq_mod
(
fda
,
fdeps
,
*
and_level
,
cond_func
,
args
[
0
],
args
[
1
]);
add_eq_mod
(
fda
,
fdeps
,
*
and_level
,
cond_func
,
args
[
1
],
args
[
0
]);
add_eq_mod
(
fda
,
eq_mod
,
*
and_level
,
cond_func
,
args
[
0
],
args
[
1
]);
add_eq_mod
(
fda
,
eq_mod
,
*
and_level
,
cond_func
,
args
[
1
],
args
[
0
]);
break
;
}
case
Item_func
:
:
ISNULL_FUNC
:
{
Item
*
tmp
=
new
Item_null
;
if
(
tmp
)
add_eq_mod
(
fda
,
fdeps
,
*
and_level
,
cond_func
,
args
[
0
],
args
[
1
]);
add_eq_mod
(
fda
,
eq_mod
,
*
and_level
,
cond_func
,
args
[
0
],
args
[
1
]);
break
;
}
case
Item_func
:
:
MULT_EQUAL_FUNC
:
{
Item_equal
*
item_equal
=
(
Item_equal
*
)
cond
;
Item
*
const_item
=
item_equal
->
get_const
();
Item_equal
*
item_equal
=
(
Item_equal
*
)
cond
;
// const item is 'item', field -> NULL. mult_equal_fields <-- an ordered
// list of
List
<
Field_value
>
*
fvl
;
if
(
!
(
fvl
=
new
List
<
Field_value
>
))
break
;
Item_equal_iterator
it
(
*
item_equal
);
Item_field
*
item
;
if
(
const_item
)
{
/*
For each field field1 from item_equal consider the equality
field1=const_item as a condition allowing an index access of the table
with field1 by the keys value of field1.
*/
Item
*
bound_item
=
item_equal
->
get_const
();
while
((
item
=
it
++
))
add_eq_mod
(
fda
,
fdeps
,
*
and_level
,
cond_func
,
item
,
const_item
);
}
else
{
/*
Consider all pairs of different fields included into item_equal.
For each of them (field1, field1) consider the equality
field1=field2 as a condition allowing an index access of the table
with field1 by the keys value of field2.
*/
Item_equal_iterator
fi
(
*
item_equal
);
while
((
item
=
fi
++
))
if
((
item
->
used_tables
()
&
fda
->
usable_tables
))
{
Field
*
field
=
item
->
field
;
Item_field
*
item2
;
while
((
item2
=
it
++
))
Field_value
*
field_val
;
if
((
field_val
=
get_field_value
(
fda
,
item
->
field
)))
{
if
(
!
field
->
eq
(
item2
->
field
))
add_eq_mod
(
fda
,
fdeps
,
*
and_level
,
cond_func
,
item
,
item2
);
List_iterator
<
Field_value
>
it2
(
*
fvl
);
Field_value
*
other_f
;
uint
field_val_ratio
=
field_val
->
field
->
table
->
tablenr
*
MAX_FIELDS
+
field_val
->
field
->
field_index
;
bool
added
=
FALSE
;
while
((
other_f
=
it2
++
))
{
uint
other_f_ratio
=
other_f
->
field
->
table
->
tablenr
*
MAX_FIELDS
+
other_f
->
field
->
field_index
;
if
(
other_f_ratio
>
field_val_ratio
)
{
*
(
it2
.
ref
())
=
field_val
;
it2
.
after
(
other_f
);
added
=
TRUE
;
break
;
}
}
if
(
!
added
)
fvl
->
push_back
(
field_val
);
}
it
.
rewind
();
}
else
{
if
(
!
bound_item
)
bound_item
=
item
;
}
}
add_eq_mod2
(
fda
,
eq_mod
,
*
and_level
,
NULL
,
bound_item
,
fvl
);
break
;
}
default:
...
...
@@ -490,6 +506,39 @@ void build_eq_mods_for_cond(Func_dep_analyzer *fda, Equality_module **fdeps,
}
/*
The only requirement of this function is to order fields in some
deterministic way.
*/
int
cmp_equal_fields
(
Item_field
*
field1
,
Item_field
*
field2
,
void
*
arg
)
{
int
cmp
=
0
;
bool
outer_ref
=
0
;
if
(
field2
->
used_tables
()
&
OUTER_REF_TABLE_BIT
)
{
outer_ref
=
1
;
cmp
=
-
1
;
}
if
(
field2
->
used_tables
()
&
OUTER_REF_TABLE_BIT
)
{
outer_ref
=
1
;
cmp
++
;
}
if
(
outer_ref
)
return
cmp
;
cmp
=
(
int
)
field2
->
field
->
table
->
tablenr
-
(
int
)
field1
->
field
->
table
->
tablenr
;
if
(
cmp
)
return
cmp
<
0
?
-
1
:
1
;
cmp
=
(
int
)
field2
->
field
->
field_index
-
(
int
)
field1
->
field
->
field_index
;
return
cmp
<
0
?
-
1
:
(
cmp
?
1
:
0
);
}
/*
Perform an OR operation on two (adjacent) Equality_module arrays.
...
...
@@ -551,22 +600,101 @@ Equality_module *merge_func_deps(Equality_module *start, Equality_module *new_fi
for
(
Equality_module
*
old
=
start
;
old
!=
first_free
;
old
++
)
{
/*
TODO: does it make sense to attempt to merging multiple-equalities?
Merge multiple-equalities:
A: YES.
(a=b=c) OR (a=b=d) produce "a=b".
QQ:
What to use for merging? Trivial N*M algorithm or pre-sort and then
merge ordered sequences?
TODO:
sort by (table_ptr, column_index)
then run along the two and produce an intersection
Q: What about constants?
a=b=3 OR a=b=5 -> a=b= (either 3 or 5)
a=b OR a=b=5 -> a=b= (any constant)
A: keep the constant iff it is present in both sides and is the same.
class Multi_equality
{
Item *const_item;
List<...) list;
};
*/
if
(
old
->
field
==
new_fields
->
field
)
{
if
(
!
new_fields
->
expression
->
const_item
())
if
(
!
old
->
field
)
{
/*
OR-ing two multiple equalities. We must compute an intersection of
used fields, and check the constants according to these rules:
a=b=c=d OR a=c=e=f -> a=c (compute intersection)
a=const1 OR a=b -> (nothing)
a=const1 OR a=const1 -> a=const1
a=const1 OR a=const2 -> (nothing)
If we're performing an OR operation over multiple equalities, e.g.
(a=b=c AND p=q) OR (a=b AND v=z)
then we'll need to try combining each equality with each. ANDed
equalities are guaranteed to be disjoint, so we'll only get one
hit.
*/
if
(
old
->
expression
&&
new_fields
->
expression
&&
old
->
expression
->
eq_by_collation
(
new_fields
->
expression
,
old
->
mult_equal_fields
->
head
()
->
field
->
binary
(),
old
->
mult_equal_fields
->
head
()
->
field
->
charset
()))
{
/* Ok, keep */
}
else
{
// no single constant/bound item.
old
->
expression
=
NULL
;
}
List
<
Field_value
>
*
fv
;
if
(
!
(
fv
=
new
List
<
Field_value
>
))
break
;
List_iterator
<
Field_value
>
it1
(
*
old
->
mult_equal_fields
);
List_iterator
<
Field_value
>
it2
(
*
new_fields
->
mult_equal_fields
);
Field_value
*
lfield
=
it1
++
;
Field_value
*
rfield
=
it2
++
;
// Merge
while
(
lfield
&&
rfield
)
{
if
(
lfield
==
rfield
)
fv
->
push_back
(
lfield
);
else
{
uint
left_ratio
=
lfield
->
field
->
table
->
tablenr
*
MAX_FIELDS
+
lfield
->
field
->
field_index
;
uint
right_ratio
=
rfield
->
field
->
table
->
tablenr
*
MAX_FIELDS
+
rfield
->
field
->
field_index
;
if
(
left_ratio
<
right_ratio
)
lfield
=
it1
++
;
else
rfield
=
it2
++
;
}
}
if
(
fv
->
elements
+
test
(
old
->
expression
)
>
1
)
{
old
->
mult_equal_fields
=
fv
;
old
->
level
=
and_level
;
}
}
else
if
(
!
new_fields
->
expression
->
const_item
())
{
/*
If the value matches, we can use the key reference.
If not, we keep it until we have examined all new values
*/
if
(
old
->
expression
->
eq
(
new_fields
->
expression
,
old
->
field
->
field
->
binary
()))
if
(
old
->
expression
->
eq
(
new_fields
->
expression
,
old
->
field
->
field
->
binary
()))
{
old
->
level
=
and_level
;
}
...
...
@@ -659,7 +787,18 @@ void add_eq_mod(Func_dep_analyzer *fda, Equality_module **eq_mod,
return
;
}
}
Field_value
*
field_val
;
if
((
field_val
=
get_field_value
(
fda
,
field
)))
add_eq_mod2
(
fda
,
eq_mod
,
and_level
,
field_val
,
right
,
NULL
);
}
}
/* Just add eq_mod w/o any checks */
static
void
add_eq_mod2
(
Func_dep_analyzer
*
fda
,
Equality_module
**
eq_mod
,
uint
and_level
,
Field_value
*
field_val
,
Item
*
right
,
List
<
Field_value
>*
mult_equal_fields
)
{
if
(
*
eq_mod
==
fda
->
equality_mods
+
fda
->
n_equality_mods_alloced
)
{
/*
...
...
@@ -677,15 +816,13 @@ void add_eq_mod(Func_dep_analyzer *fda, Equality_module **eq_mod,
*
eq_mod
=
new_arr
+
(
*
eq_mod
-
fda
->
equality_mods
);
}
if
(
!
((
*
eq_mod
)
->
field
=
get_field_value
(
fda
,
field
)))
return
;
(
*
eq_mod
)
->
field
=
field_val
;
(
*
eq_mod
)
->
expression
=
right
;
(
*
eq_mod
)
->
level
=
and_level
;
(
*
eq_mod
)
->
mult_equal_fields
=
mult_equal_fields
;
(
*
eq_mod
)
++
;
}
}
/*
Get a Table_value object for the given table, creating it if necessary.
*/
...
...
@@ -782,11 +919,15 @@ public:
*/
fda
->
equality_mods
[
expr_offset
].
unknown_args
++
;
}
else
saw_other_tbl
=
TRUE
;
}
Func_dep_analyzer
*
fda
;
/* Offset of the expression we're processing in the dependency bitmap */
uint
expr_offset
;
bool
saw_other_tbl
;
};
...
...
@@ -858,9 +999,21 @@ bool setup_equality_modules_deps(Func_dep_analyzer *fda,
eq_mod
++
)
{
deps_recorder
.
expr_offset
=
eq_mod
-
fda
->
equality_mods
;
deps_recorder
.
saw_other_tbl
=
FALSE
;
eq_mod
->
unknown_args
=
0
;
/* Regular tbl.col=expr(tblX1.col1, tblY1.col2, ...) */
eq_mod
->
expression
->
walk
(
&
Item
::
check_column_usage_processor
,
FALSE
,
(
uchar
*
)
&
deps_recorder
);
if
(
!
eq_mod
->
field
)
{
if
(
eq_mod
->
unknown_args
)
eq_mod
->
unknown_args
=
1
;
if
(
deps_recorder
.
saw_other_tbl
)
eq_mod
->
unknown_args
=
0
;
}
if
(
!
eq_mod
->
unknown_args
)
{
eq_mod
->
next
=
bound_dep
;
...
...
@@ -1235,6 +1388,23 @@ bool Equality_module::now_bound(Func_dep_analyzer *fda,
Value_dep
**
bound_values
)
{
/* For field=expr and we got to know the expr, so we know the field */
if
(
mult_equal_fields
)
{
List_iterator
<
Field_value
>
it
(
*
mult_equal_fields
);
Field_value
*
fv
;
while
((
fv
=
it
++
))
{
if
(
!
fv
->
bound
)
{
/* Mark as bound and add to the list */
fv
->
bound
=
TRUE
;
fv
->
next
=
*
bound_values
;
*
bound_values
=
fv
;
}
}
}
else
{
if
(
!
field
->
bound
)
{
/* Mark as bound and add to the list */
...
...
@@ -1242,6 +1412,7 @@ bool Equality_module::now_bound(Func_dep_analyzer *fda,
field
->
next
=
*
bound_values
;
*
bound_values
=
field
;
}
}
return
FALSE
;
}
...
...
@@ -1313,12 +1484,20 @@ void dbug_print_deps(Func_dep_analyzer *fda)
String
str
(
buf
,
sizeof
(
buf
),
&
my_charset_bin
);
str
.
length
(
0
);
eq_mod
->
expression
->
print
(
&
str
,
QT_ORDINARY
);
if
(
eq_mod
->
field
)
{
fprintf
(
DBUG_FILE
,
" equality%d: %s -> %s.%s
\n
"
,
eq_mod
-
fda
->
equality_mods
,
str
.
c_ptr
(),
eq_mod
->
field
->
table
->
table
->
alias
,
eq_mod
->
field
->
field
->
field_name
);
}
else
{
fprintf
(
DBUG_FILE
,
" equality%d: multi-equality"
,
eq_mod
-
fda
->
equality_mods
);
}
}
fprintf
(
DBUG_FILE
,
"
\n
"
);
/* Then tables and their fields */
...
...
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