1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +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:
Igor Babaev
2019-02-09 22:54:26 -08:00
parent 3f9040085a
commit d11be23933
14 changed files with 233 additions and 67 deletions

View File

@ -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 <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
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;
DROP TABLE federated.t1, federated.t2;
connection default;

View File

@ -76,6 +76,7 @@ SELECT id FROM federated.t1 WHERE id < 5;
ANALYZE
SELECT id FROM federated.t1 WHERE id < 5;
--source include/analyze-format.inc
ANALYZE FORMAT=JSON
SELECT id FROM federated.t1 WHERE id < 5;
@ -106,7 +107,44 @@ SELECT *
FROM federated.t3, (SELECT * FROM federated.t1 WHERE id > 3) t
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;
DROP TABLE federated.t1, federated.t2;

View File

@ -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)
{
restore_first_argument();
Item_func::print(str, query_type);
if (query_type & QT_PARSABLE)
args[1]->print(str, query_type);
else
{
restore_first_argument();
Item_func::print(str, query_type);
}
}

View File

@ -3272,7 +3272,8 @@ out:
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>"));
else
{
@ -3499,7 +3500,8 @@ Item_allany_subselect::select_transformer(JOIN *join)
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>"));
else
{

View File

@ -745,6 +745,8 @@ enum enum_query_type
/// SHOW CREATE {VIEW|PROCEDURE|FUNCTION} and other cases where the
/// original representation is required, should set this flag.
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.
QT_EXPLAIN= QT_TO_SYSTEM_CHARSET |

View File

@ -385,7 +385,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_RETURN(FALSE);
}
if ((derived->dt_handler= derived->find_derived_handler(thd)))
if (derived->dt_handler)
{
derived->change_refs_to_fields();
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())
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:
/* Hide "Unknown column" or "Unknown function" error */
if (derived->view)
@ -912,16 +930,14 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_RETURN(FALSE);
}
if (derived->is_materialized_derived() && !derived->dt_handler)
derived->dt_handler= derived->find_derived_handler(thd);
if (derived->dt_handler)
if (derived->is_materialized_derived() && derived->dt_handler)
{
if (!(derived->pushdown_derived=
new (thd->mem_root) Pushdown_derived(derived, derived->dt_handler)))
{
delete derived->dt_handler;
derived->dt_handler= NULL;
DBUG_RETURN(1);
DBUG_RETURN(TRUE);
}
}

View File

@ -2137,6 +2137,7 @@ struct TABLE_LIST
bool is_derived_with_recursive_reference;
bool block_handle_derived;
derived_handler *dt_handler;
LEX_CSTRING derived_spec;
Pushdown_derived *pushdown_derived;
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
st_select_lex *schema_select_lex;

View File

@ -62,7 +62,6 @@ ha_federatedx_derived_handler::~ha_federatedx_derived_handler() {}
int ha_federatedx_derived_handler::init_scan()
{
char query_buff[4096];
THD *thd;
int rc= 0;
@ -77,11 +76,7 @@ int ha_federatedx_derived_handler::init_scan()
if ((rc= txn->acquire(share, thd, TRUE, iop)))
DBUG_RETURN(rc);
String derived_query(query_buff, sizeof(query_buff), thd->charset());
derived_query.length(0);
derived->derived->print(&derived_query, QT_ORDINARY);
if ((*iop)->query(derived_query.ptr(), derived_query.length()))
if ((*iop)->query(derived->derived_spec.str, derived->derived_spec.length))
goto err;
stored_result= (*iop)->store_result();