Commit 8041013f authored by Igor Babaev's avatar Igor Babaev

Back-ported the patch for bug #59696 from mysql-5.6 code line.

The patch fixed the following optimizer defect: when performing
substitution for best equal fields into where conditions to be
able to do their evaluations as soon as possible the optimizer 
skipped conditions over views. That could lead to suboptimal 
execution of queries that used views.  
Slightly changed the test case to demonstrate the performance
improvements if this fix.
parent 9ea80ac4
......@@ -3885,3 +3885,57 @@ DROP TABLE t1;
# -----------------------------------------------------------------
# -- End of 5.1 tests.
# -----------------------------------------------------------------
#
# Bug #59696 Optimizer does not use equalities for conditions over view
#
CREATE TABLE t1 (a int NOT NULL);
INSERT INTO t1 VALUES
(9), (2), (8), (1), (3), (4), (2), (5),
(9), (2), (8), (1), (3), (4), (2), (5);
CREATE TABLE t2 (pk int PRIMARY KEY, c int NOT NULL);
INSERT INTO t2 VALUES
(9,90), (16, 160), (11,110), (1,10), (18,180), (2,20),
(14,140), (15, 150), (12,120), (3,30), (17,170), (19,190);
EXPLAIN EXTENDED
SELECT t1.a,t2.c FROM t1,t2 WHERE t2.pk = t1.a AND t2.pk > 8;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 16 100.00 Using where
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 100.00
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`pk` = `test`.`t1`.`a`) and (`test`.`t1`.`a` > 8))
FLUSH STATUS;
SELECT t1.a,t2.c FROM t1,t2 WHERE t2.pk = t1.a AND t2.pk > 8;
a c
9 90
9 90
SHOW STATUS LIKE 'Handler_read_%';
Variable_name Value
Handler_read_first 0
Handler_read_key 1
Handler_read_next 0
Handler_read_prev 0
Handler_read_rnd 0
Handler_read_rnd_next 17
CREATE VIEW v AS SELECT * FROM t2;
EXPLAIN EXTENDED
SELECT t1.a,v.c FROM t1,v WHERE v.pk = t1.a AND v.pk > 8;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 16 100.00 Using where
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 100.00
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`pk` = `test`.`t1`.`a`) and (`test`.`t1`.`a` > 8))
FLUSH STATUS;
SELECT t1.a,v.c FROM t1,v WHERE v.pk = t1.a AND v.pk > 8;
a c
9 90
9 90
SHOW STATUS LIKE 'Handler_read_%';
Variable_name Value
Handler_read_first 0
Handler_read_key 1
Handler_read_next 0
Handler_read_prev 0
Handler_read_rnd 0
Handler_read_rnd_next 17
DROP VIEW v;
DROP TABLE t1, t2;
......@@ -3928,3 +3928,34 @@ DROP TABLE t1;
--echo # -----------------------------------------------------------------
--echo # -- End of 5.1 tests.
--echo # -----------------------------------------------------------------
--echo #
--echo # Bug #59696 Optimizer does not use equalities for conditions over view
--echo #
CREATE TABLE t1 (a int NOT NULL);
INSERT INTO t1 VALUES
(9), (2), (8), (1), (3), (4), (2), (5),
(9), (2), (8), (1), (3), (4), (2), (5);
CREATE TABLE t2 (pk int PRIMARY KEY, c int NOT NULL);
INSERT INTO t2 VALUES
(9,90), (16, 160), (11,110), (1,10), (18,180), (2,20),
(14,140), (15, 150), (12,120), (3,30), (17,170), (19,190);
EXPLAIN EXTENDED
SELECT t1.a,t2.c FROM t1,t2 WHERE t2.pk = t1.a AND t2.pk > 8;
FLUSH STATUS;
SELECT t1.a,t2.c FROM t1,t2 WHERE t2.pk = t1.a AND t2.pk > 8;
SHOW STATUS LIKE 'Handler_read_%';
CREATE VIEW v AS SELECT * FROM t2;
EXPLAIN EXTENDED
SELECT t1.a,v.c FROM t1,v WHERE v.pk = t1.a AND v.pk > 8;
FLUSH STATUS;
SELECT t1.a,v.c FROM t1,v WHERE v.pk = t1.a AND v.pk > 8;
SHOW STATUS LIKE 'Handler_read_%';
DROP VIEW v;
DROP TABLE t1, t2;
......@@ -6307,6 +6307,85 @@ void Item_ref::cleanup()
}
/**
Transform an Item_ref object with a transformer callback function.
The function first applies the transform method to the item
referenced by this Item_reg object. If this returns a new item the
old item is substituted for a new one. After this the transformer
is applied to the Item_ref object.
@param transformer the transformer callback function to be applied to
the nodes of the tree of the object
@param argument parameter to be passed to the transformer
@return Item returned as the result of transformation of the Item_ref object
@retval !NULL The transformation was successful
@retval NULL Out of memory error
*/
Item* Item_ref::transform(Item_transformer transformer, uchar *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
DBUG_ASSERT((*ref) != NULL);
/* Transform the object we are referencing. */
Item *new_item= (*ref)->transform(transformer, arg);
if (!new_item)
return NULL;
/*
THD::change_item_tree() should be called only if the tree was
really transformed, i.e. when a new item has been created.
Otherwise we'll be allocating a lot of unnecessary memory for
change records at each execution.
*/
if (*ref != new_item)
current_thd->change_item_tree(ref, new_item);
/* Transform the item ref object. */
return (this->*transformer)(arg);
}
/**
Compile an Item_ref object with a processor and a transformer
callback functions.
First the function applies the analyzer to the Item_ref object. Then
if the analizer succeeeds we first applies the compile method to the
object the Item_ref object is referencing. If this returns a new
item the old item is substituted for a new one. After this the
transformer is applied to the Item_ref object itself.
@param analyzer the analyzer callback function to be applied to the
nodes of the tree of the object
@param[in,out] arg_p parameter to be passed to the processor
@param transformer the transformer callback function to be applied to the
nodes of the tree of the object
@param arg_t parameter to be passed to the transformer
@return Item returned as the result of transformation of the Item_ref object
*/
Item* Item_ref::compile(Item_analyzer analyzer, uchar **arg_p,
Item_transformer transformer, uchar *arg_t)
{
/* Analyze this Item object. */
if (!(this->*analyzer)(arg_p))
return NULL;
/* Compile the Item we are referencing. */
DBUG_ASSERT((*ref) != NULL);
Item *new_item= (*ref)->compile(analyzer, arg_p, transformer, arg_t);
if (new_item && *ref != new_item)
current_thd->change_item_tree(ref, new_item);
/* Transform this Item object. */
return (this->*transformer)(arg_t);
}
void Item_ref::print(String *str, enum_query_type query_type)
{
if (ref)
......
......@@ -2493,6 +2493,9 @@ class Item_ref :public Item_ident
else
return FALSE;
}
Item* transform(Item_transformer, uchar *arg);
Item* compile(Item_analyzer analyzer, uchar **arg_p,
Item_transformer transformer, uchar *arg_t);
bool enumerate_field_refs_processor(uchar *arg)
{ return (*ref)->enumerate_field_refs_processor(arg); }
void no_rows_in_result()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment