mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-17096 Pushdown of simple derived tables to storage engines
Resolved the problem of forming a proper query string for FEDERATEDX. Added test cases. Cleanup of extra spaces.
This commit is contained in:
@@ -190,7 +190,114 @@ id select_type table type possible_keys key key_len ref rows r_rows filtered r_f
|
|||||||
1 PRIMARY t3 ALL NULL NULL NULL NULL 7 7.00 100.00 100.00
|
1 PRIMARY t3 ALL NULL NULL NULL NULL 7 7.00 100.00 100.00
|
||||||
1 PRIMARY <derived2> ref key0 key0 18 federated.t3.name 2 0.00 100.00 100.00
|
1 PRIMARY <derived2> ref key0 key0 18 federated.t3.name 2 0.00 100.00 100.00
|
||||||
2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
|
2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
|
||||||
DROP TABLE federated.t1, federated.t2;
|
SELECT *
|
||||||
|
FROM federated.t3, (SELECT t1.name FROM federated.t1
|
||||||
|
WHERE id IN (SELECT count(*)
|
||||||
|
FROM federated.t2 GROUP BY name)) t
|
||||||
|
WHERE federated.t3.name=t.name;
|
||||||
|
name name
|
||||||
|
xxx xxx
|
||||||
|
EXPLAIN
|
||||||
|
SELECT *
|
||||||
|
FROM federated.t3, (SELECT t1.name FROM federated.t1
|
||||||
|
WHERE id IN (SELECT count(*)
|
||||||
|
FROM federated.t2 GROUP BY name)) t
|
||||||
|
WHERE federated.t3.name=t.name;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t3 ALL NULL NULL NULL NULL 7
|
||||||
|
1 PRIMARY <derived2> ref key0 key0 18 federated.t3.name 2
|
||||||
|
2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL
|
||||||
|
3 MATERIALIZED t2 ALL NULL NULL NULL NULL 7 Using temporary
|
||||||
|
ANALYZE FORMAT=JSON
|
||||||
|
SELECT *
|
||||||
|
FROM federated.t3, (SELECT t1.name FROM federated.t1
|
||||||
|
WHERE id IN (SELECT count(*)
|
||||||
|
FROM federated.t2 GROUP BY name)) t
|
||||||
|
WHERE federated.t3.name=t.name;
|
||||||
|
ANALYZE
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"table": {
|
||||||
|
"table_name": "t3",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 1,
|
||||||
|
"rows": 7,
|
||||||
|
"r_rows": 7,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": 100
|
||||||
|
},
|
||||||
|
"table": {
|
||||||
|
"table_name": "<derived2>",
|
||||||
|
"access_type": "ref",
|
||||||
|
"possible_keys": ["key0"],
|
||||||
|
"key": "key0",
|
||||||
|
"key_length": "18",
|
||||||
|
"used_key_parts": ["name"],
|
||||||
|
"ref": ["federated.t3.name"],
|
||||||
|
"r_loops": 7,
|
||||||
|
"rows": 2,
|
||||||
|
"r_rows": 0,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": 100,
|
||||||
|
"materialized": {
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 2,
|
||||||
|
"table": {
|
||||||
|
"message": "Pushed derived"
|
||||||
|
},
|
||||||
|
"subqueries": [
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 3,
|
||||||
|
"temporary_table": {
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 0,
|
||||||
|
"rows": 7,
|
||||||
|
"r_rows": null,
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SELECT t.id, federated.t3.name
|
||||||
|
FROM federated.t3,
|
||||||
|
( SELECT * FROM federated.t1 WHERE id < 3
|
||||||
|
UNION
|
||||||
|
SELECT * FROM federated.t1 WHERE id >= 5) t
|
||||||
|
WHERE federated.t3.name=t.name;
|
||||||
|
id name
|
||||||
|
5 yyy
|
||||||
|
7 yyy
|
||||||
|
5 yyy
|
||||||
|
7 yyy
|
||||||
|
5 yyy
|
||||||
|
7 yyy
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t.id, federated.t3.name
|
||||||
|
FROM federated.t3,
|
||||||
|
( SELECT * FROM federated.t1 WHERE id < 3
|
||||||
|
UNION
|
||||||
|
SELECT * FROM federated.t1 WHERE id >= 5) t
|
||||||
|
WHERE federated.t3.name=t.name;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t3 ALL NULL NULL NULL NULL 7
|
||||||
|
1 PRIMARY <derived2> ref key0 key0 18 federated.t3.name 2
|
||||||
|
2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL
|
||||||
|
DROP TABLE federated.t1, federated.t2, federated.t3;
|
||||||
connection slave;
|
connection slave;
|
||||||
DROP TABLE federated.t1, federated.t2;
|
DROP TABLE federated.t1, federated.t2;
|
||||||
connection default;
|
connection default;
|
||||||
|
@@ -76,6 +76,7 @@ SELECT id FROM federated.t1 WHERE id < 5;
|
|||||||
ANALYZE
|
ANALYZE
|
||||||
SELECT id FROM federated.t1 WHERE id < 5;
|
SELECT id FROM federated.t1 WHERE id < 5;
|
||||||
|
|
||||||
|
--source include/analyze-format.inc
|
||||||
ANALYZE FORMAT=JSON
|
ANALYZE FORMAT=JSON
|
||||||
SELECT id FROM federated.t1 WHERE id < 5;
|
SELECT id FROM federated.t1 WHERE id < 5;
|
||||||
|
|
||||||
@@ -106,7 +107,44 @@ SELECT *
|
|||||||
FROM federated.t3, (SELECT * FROM federated.t1 WHERE id > 3) t
|
FROM federated.t3, (SELECT * FROM federated.t1 WHERE id > 3) t
|
||||||
WHERE federated.t3.name=t.name;
|
WHERE federated.t3.name=t.name;
|
||||||
|
|
||||||
DROP TABLE federated.t1, federated.t2;
|
SELECT *
|
||||||
|
FROM federated.t3, (SELECT t1.name FROM federated.t1
|
||||||
|
WHERE id IN (SELECT count(*)
|
||||||
|
FROM federated.t2 GROUP BY name)) t
|
||||||
|
WHERE federated.t3.name=t.name;
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT *
|
||||||
|
FROM federated.t3, (SELECT t1.name FROM federated.t1
|
||||||
|
WHERE id IN (SELECT count(*)
|
||||||
|
FROM federated.t2 GROUP BY name)) t
|
||||||
|
WHERE federated.t3.name=t.name;
|
||||||
|
|
||||||
|
--source include/analyze-format.inc
|
||||||
|
ANALYZE FORMAT=JSON
|
||||||
|
SELECT *
|
||||||
|
FROM federated.t3, (SELECT t1.name FROM federated.t1
|
||||||
|
WHERE id IN (SELECT count(*)
|
||||||
|
FROM federated.t2 GROUP BY name)) t
|
||||||
|
WHERE federated.t3.name=t.name;
|
||||||
|
|
||||||
|
SELECT t.id, federated.t3.name
|
||||||
|
FROM federated.t3,
|
||||||
|
( SELECT * FROM federated.t1 WHERE id < 3
|
||||||
|
UNION
|
||||||
|
SELECT * FROM federated.t1 WHERE id >= 5) t
|
||||||
|
WHERE federated.t3.name=t.name;
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t.id, federated.t3.name
|
||||||
|
FROM federated.t3,
|
||||||
|
( SELECT * FROM federated.t1 WHERE id < 3
|
||||||
|
UNION
|
||||||
|
SELECT * FROM federated.t1 WHERE id >= 5) t
|
||||||
|
WHERE federated.t3.name=t.name;
|
||||||
|
|
||||||
|
|
||||||
|
DROP TABLE federated.t1, federated.t2, federated.t3;
|
||||||
|
|
||||||
connection slave;
|
connection slave;
|
||||||
DROP TABLE federated.t1, federated.t2;
|
DROP TABLE federated.t1, federated.t2;
|
||||||
|
@@ -1215,8 +1215,13 @@ bool Item_in_optimizer::eval_not_null_tables(void *opt_arg)
|
|||||||
|
|
||||||
void Item_in_optimizer::print(String *str, enum_query_type query_type)
|
void Item_in_optimizer::print(String *str, enum_query_type query_type)
|
||||||
{
|
{
|
||||||
|
if (query_type & QT_PARSABLE)
|
||||||
|
args[1]->print(str, query_type);
|
||||||
|
else
|
||||||
|
{
|
||||||
restore_first_argument();
|
restore_first_argument();
|
||||||
Item_func::print(str, query_type);
|
Item_func::print(str, query_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -3272,7 +3272,8 @@ out:
|
|||||||
|
|
||||||
void Item_in_subselect::print(String *str, enum_query_type query_type)
|
void Item_in_subselect::print(String *str, enum_query_type query_type)
|
||||||
{
|
{
|
||||||
if (test_strategy(SUBS_IN_TO_EXISTS))
|
if (test_strategy(SUBS_IN_TO_EXISTS) &&
|
||||||
|
!(query_type & QT_PARSABLE))
|
||||||
str->append(STRING_WITH_LEN("<exists>"));
|
str->append(STRING_WITH_LEN("<exists>"));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3499,7 +3500,8 @@ Item_allany_subselect::select_transformer(JOIN *join)
|
|||||||
|
|
||||||
void Item_allany_subselect::print(String *str, enum_query_type query_type)
|
void Item_allany_subselect::print(String *str, enum_query_type query_type)
|
||||||
{
|
{
|
||||||
if (test_strategy(SUBS_IN_TO_EXISTS))
|
if (test_strategy(SUBS_IN_TO_EXISTS) &&
|
||||||
|
!(query_type & QT_PARSABLE))
|
||||||
str->append(STRING_WITH_LEN("<exists>"));
|
str->append(STRING_WITH_LEN("<exists>"));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -745,6 +745,8 @@ enum enum_query_type
|
|||||||
/// SHOW CREATE {VIEW|PROCEDURE|FUNCTION} and other cases where the
|
/// SHOW CREATE {VIEW|PROCEDURE|FUNCTION} and other cases where the
|
||||||
/// original representation is required, should set this flag.
|
/// original representation is required, should set this flag.
|
||||||
QT_ITEM_ORIGINAL_FUNC_NULLIF= (1 << 7),
|
QT_ITEM_ORIGINAL_FUNC_NULLIF= (1 << 7),
|
||||||
|
/// good for parsing
|
||||||
|
QT_PARSABLE= (1 << 8),
|
||||||
|
|
||||||
/// This value means focus on readability, not on ability to parse back, etc.
|
/// This value means focus on readability, not on ability to parse back, etc.
|
||||||
QT_EXPLAIN= QT_TO_SYSTEM_CHARSET |
|
QT_EXPLAIN= QT_TO_SYSTEM_CHARSET |
|
||||||
|
@@ -385,7 +385,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
|
|||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((derived->dt_handler= derived->find_derived_handler(thd)))
|
if (derived->dt_handler)
|
||||||
{
|
{
|
||||||
derived->change_refs_to_fields();
|
derived->change_refs_to_fields();
|
||||||
derived->set_materialized_derived();
|
derived->set_materialized_derived();
|
||||||
@@ -820,6 +820,24 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
|
|||||||
if (derived->is_derived() && derived->is_merged_derived())
|
if (derived->is_derived() && derived->is_merged_derived())
|
||||||
first_select->mark_as_belong_to_derived(derived);
|
first_select->mark_as_belong_to_derived(derived);
|
||||||
|
|
||||||
|
derived->dt_handler= derived->find_derived_handler(thd);
|
||||||
|
if (derived->dt_handler)
|
||||||
|
{
|
||||||
|
char query_buff[4096];
|
||||||
|
String derived_query(query_buff, sizeof(query_buff), thd->charset());
|
||||||
|
derived_query.length(0);
|
||||||
|
derived->derived->print(&derived_query,
|
||||||
|
enum_query_type(QT_VIEW_INTERNAL |
|
||||||
|
QT_ITEM_ORIGINAL_FUNC_NULLIF |
|
||||||
|
QT_PARSABLE));
|
||||||
|
if (!thd->make_lex_string(&derived->derived_spec,
|
||||||
|
derived_query.ptr(), derived_query.length()))
|
||||||
|
{
|
||||||
|
delete derived->dt_handler;
|
||||||
|
derived->dt_handler= NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
/* Hide "Unknown column" or "Unknown function" error */
|
/* Hide "Unknown column" or "Unknown function" error */
|
||||||
if (derived->view)
|
if (derived->view)
|
||||||
@@ -912,16 +930,14 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived)
|
|||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (derived->is_materialized_derived() && !derived->dt_handler)
|
if (derived->is_materialized_derived() && derived->dt_handler)
|
||||||
derived->dt_handler= derived->find_derived_handler(thd);
|
|
||||||
if (derived->dt_handler)
|
|
||||||
{
|
{
|
||||||
if (!(derived->pushdown_derived=
|
if (!(derived->pushdown_derived=
|
||||||
new (thd->mem_root) Pushdown_derived(derived, derived->dt_handler)))
|
new (thd->mem_root) Pushdown_derived(derived, derived->dt_handler)))
|
||||||
{
|
{
|
||||||
delete derived->dt_handler;
|
delete derived->dt_handler;
|
||||||
derived->dt_handler= NULL;
|
derived->dt_handler= NULL;
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2137,6 +2137,7 @@ struct TABLE_LIST
|
|||||||
bool is_derived_with_recursive_reference;
|
bool is_derived_with_recursive_reference;
|
||||||
bool block_handle_derived;
|
bool block_handle_derived;
|
||||||
derived_handler *dt_handler;
|
derived_handler *dt_handler;
|
||||||
|
LEX_CSTRING derived_spec;
|
||||||
Pushdown_derived *pushdown_derived;
|
Pushdown_derived *pushdown_derived;
|
||||||
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
|
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
|
||||||
st_select_lex *schema_select_lex;
|
st_select_lex *schema_select_lex;
|
||||||
|
@@ -62,7 +62,6 @@ ha_federatedx_derived_handler::~ha_federatedx_derived_handler() {}
|
|||||||
|
|
||||||
int ha_federatedx_derived_handler::init_scan()
|
int ha_federatedx_derived_handler::init_scan()
|
||||||
{
|
{
|
||||||
char query_buff[4096];
|
|
||||||
THD *thd;
|
THD *thd;
|
||||||
int rc= 0;
|
int rc= 0;
|
||||||
|
|
||||||
@@ -77,11 +76,7 @@ int ha_federatedx_derived_handler::init_scan()
|
|||||||
if ((rc= txn->acquire(share, thd, TRUE, iop)))
|
if ((rc= txn->acquire(share, thd, TRUE, iop)))
|
||||||
DBUG_RETURN(rc);
|
DBUG_RETURN(rc);
|
||||||
|
|
||||||
String derived_query(query_buff, sizeof(query_buff), thd->charset());
|
if ((*iop)->query(derived->derived_spec.str, derived->derived_spec.length))
|
||||||
derived_query.length(0);
|
|
||||||
derived->derived->print(&derived_query, QT_ORDINARY);
|
|
||||||
|
|
||||||
if ((*iop)->query(derived_query.ptr(), derived_query.length()))
|
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
stored_result= (*iop)->store_result();
|
stored_result= (*iop)->store_result();
|
||||||
|
Reference in New Issue
Block a user