diff --git a/mysql-test/main/costs.test b/mysql-test/main/costs.test index 5de334c67d396..7de2c9cdd5e73 100644 --- a/mysql-test/main/costs.test +++ b/mysql-test/main/costs.test @@ -8,6 +8,7 @@ --source include/have_sequence.inc --source include/have_innodb.inc --source include/innodb_stable_estimates.inc +--disable_replay testfile Uses Last_query_cost for most queries create table t1 (a int primary key, b int, c int, d int, e int, key ba (b,a), key bda (b,d,a), key cba (c,b,a), key cb (c,b), key d (d)) engine=aria; insert into t1 select seq,seq,seq,seq,seq from seq_1_to_10; diff --git a/mysql-test/main/opt_context_replay_basic.result b/mysql-test/main/opt_context_replay_basic.result index 34f9b4d6d2271..f5c07c3baf95e 100644 --- a/mysql-test/main/opt_context_replay_basic.result +++ b/mysql-test/main/opt_context_replay_basic.result @@ -20,7 +20,79 @@ select @set_stmts; @set_stmts SET NAMES utf8mb4; - SET join_buffer_size=262144; + SET GLOBAL MyISAM.OPTIMIZER_DISK_READ_COST=10.24; + +SET GLOBAL MyISAM.OPTIMIZER_INDEX_BLOCK_COPY_COST=0.0356; + +SET GLOBAL MyISAM.OPTIMIZER_KEY_COMPARE_COST=0.011361; + +SET GLOBAL MyISAM.OPTIMIZER_KEY_COPY_COST=0.015685; + +SET GLOBAL MyISAM.OPTIMIZER_KEY_LOOKUP_COST=0.550142; + +SET GLOBAL MyISAM.OPTIMIZER_KEY_NEXT_FIND_COST=0.090585; + +SET GLOBAL MyISAM.OPTIMIZER_DISK_READ_RATIO=0.02; + +SET GLOBAL MyISAM.OPTIMIZER_ROW_COPY_COST=0.060866; + +SET GLOBAL MyISAM.OPTIMIZER_ROW_LOOKUP_COST=1.014818; + +SET GLOBAL MyISAM.OPTIMIZER_ROW_NEXT_FIND_COST=0.063539; + +SET GLOBAL MyISAM.OPTIMIZER_ROWID_COMPARE_COST=0.002653; + +SET GLOBAL MyISAM.OPTIMIZER_ROWID_COPY_COST=0.002653; + +SET GLOBAL heap.OPTIMIZER_DISK_READ_COST=0; + +SET GLOBAL heap.OPTIMIZER_INDEX_BLOCK_COPY_COST=0; + +SET GLOBAL heap.OPTIMIZER_KEY_COMPARE_COST=0.011361; + +SET GLOBAL heap.OPTIMIZER_KEY_COPY_COST=0; + +SET GLOBAL heap.OPTIMIZER_KEY_LOOKUP_COST=0; + +SET GLOBAL heap.OPTIMIZER_KEY_NEXT_FIND_COST=0; + +SET GLOBAL heap.OPTIMIZER_DISK_READ_RATIO=0; + +SET GLOBAL heap.OPTIMIZER_ROW_COPY_COST=0.002334; + +SET GLOBAL heap.OPTIMIZER_ROW_LOOKUP_COST=0; + +SET GLOBAL heap.OPTIMIZER_ROW_NEXT_FIND_COST=0.0080166; + +SET GLOBAL heap.OPTIMIZER_ROWID_COMPARE_COST=0.002653; + +SET GLOBAL heap.OPTIMIZER_ROWID_COPY_COST=0.002653; + +SET GLOBAL temp_table.OPTIMIZER_DISK_READ_COST=10.24; + +SET GLOBAL temp_table.OPTIMIZER_INDEX_BLOCK_COPY_COST=0.0356; + +SET GLOBAL temp_table.OPTIMIZER_KEY_COMPARE_COST=0.011361; + +SET GLOBAL temp_table.OPTIMIZER_KEY_COPY_COST=0.015685; + +SET GLOBAL temp_table.OPTIMIZER_KEY_LOOKUP_COST=0.435777; + +SET GLOBAL temp_table.OPTIMIZER_KEY_NEXT_FIND_COST=0.082347; + +SET GLOBAL temp_table.OPTIMIZER_DISK_READ_RATIO=0.02; + +SET GLOBAL temp_table.OPTIMIZER_ROW_COPY_COST=0.060866; + +SET GLOBAL temp_table.OPTIMIZER_ROW_LOOKUP_COST=0.130839; + +SET GLOBAL temp_table.OPTIMIZER_ROW_NEXT_FIND_COST=0.045916; + +SET GLOBAL temp_table.OPTIMIZER_ROWID_COMPARE_COST=0.002653; + +SET GLOBAL temp_table.OPTIMIZER_ROWID_COPY_COST=0.002653; + +SET join_buffer_size=262144; SET join_cache_level=2; @@ -87,6 +159,42 @@ dumpfile "dump1.sql" from information_schema.optimizer_context; ERROR HY000: The MariaDB server is running with the --secure-file-priv option so it cannot execute this statement drop table t1; SET NAMES utf8mb4; +SET GLOBAL MyISAM.OPTIMIZER_DISK_READ_COST=10.24; +SET GLOBAL MyISAM.OPTIMIZER_INDEX_BLOCK_COPY_COST=0.0356; +SET GLOBAL MyISAM.OPTIMIZER_KEY_COMPARE_COST=0.011361; +SET GLOBAL MyISAM.OPTIMIZER_KEY_COPY_COST=0.015685; +SET GLOBAL MyISAM.OPTIMIZER_KEY_LOOKUP_COST=0.550142; +SET GLOBAL MyISAM.OPTIMIZER_KEY_NEXT_FIND_COST=0.090585; +SET GLOBAL MyISAM.OPTIMIZER_DISK_READ_RATIO=0.02; +SET GLOBAL MyISAM.OPTIMIZER_ROW_COPY_COST=0.060866; +SET GLOBAL MyISAM.OPTIMIZER_ROW_LOOKUP_COST=1.014818; +SET GLOBAL MyISAM.OPTIMIZER_ROW_NEXT_FIND_COST=0.063539; +SET GLOBAL MyISAM.OPTIMIZER_ROWID_COMPARE_COST=0.002653; +SET GLOBAL MyISAM.OPTIMIZER_ROWID_COPY_COST=0.002653; +SET GLOBAL heap.OPTIMIZER_DISK_READ_COST=0; +SET GLOBAL heap.OPTIMIZER_INDEX_BLOCK_COPY_COST=0; +SET GLOBAL heap.OPTIMIZER_KEY_COMPARE_COST=0.011361; +SET GLOBAL heap.OPTIMIZER_KEY_COPY_COST=0; +SET GLOBAL heap.OPTIMIZER_KEY_LOOKUP_COST=0; +SET GLOBAL heap.OPTIMIZER_KEY_NEXT_FIND_COST=0; +SET GLOBAL heap.OPTIMIZER_DISK_READ_RATIO=0; +SET GLOBAL heap.OPTIMIZER_ROW_COPY_COST=0.002334; +SET GLOBAL heap.OPTIMIZER_ROW_LOOKUP_COST=0; +SET GLOBAL heap.OPTIMIZER_ROW_NEXT_FIND_COST=0.0080166; +SET GLOBAL heap.OPTIMIZER_ROWID_COMPARE_COST=0.002653; +SET GLOBAL heap.OPTIMIZER_ROWID_COPY_COST=0.002653; +SET GLOBAL temp_table.OPTIMIZER_DISK_READ_COST=10.24; +SET GLOBAL temp_table.OPTIMIZER_INDEX_BLOCK_COPY_COST=0.0356; +SET GLOBAL temp_table.OPTIMIZER_KEY_COMPARE_COST=0.011361; +SET GLOBAL temp_table.OPTIMIZER_KEY_COPY_COST=0.015685; +SET GLOBAL temp_table.OPTIMIZER_KEY_LOOKUP_COST=0.435777; +SET GLOBAL temp_table.OPTIMIZER_KEY_NEXT_FIND_COST=0.082347; +SET GLOBAL temp_table.OPTIMIZER_DISK_READ_RATIO=0.02; +SET GLOBAL temp_table.OPTIMIZER_ROW_COPY_COST=0.060866; +SET GLOBAL temp_table.OPTIMIZER_ROW_LOOKUP_COST=0.130839; +SET GLOBAL temp_table.OPTIMIZER_ROW_NEXT_FIND_COST=0.045916; +SET GLOBAL temp_table.OPTIMIZER_ROWID_COMPARE_COST=0.002653; +SET GLOBAL temp_table.OPTIMIZER_ROWID_COPY_COST=0.002653; SET join_buffer_size=262144; SET join_cache_level=2; SET optimizer_adjust_secondary_key_costs=0; diff --git a/sql/opt_context_store_replay.cc b/sql/opt_context_store_replay.cc index e0f9594a0dbca..25909d932d17a 100644 --- a/sql/opt_context_store_replay.cc +++ b/sql/opt_context_store_replay.cc @@ -156,6 +156,7 @@ class table_context_for_store : public Sql_alloc namespace Show { +extern ST_FIELD_INFO optimizer_costs_fields_info[]; ST_FIELD_INFO optimizer_context_capture_info[]= { Column("QUERY", Longtext(65535), NOT_NULL), @@ -397,6 +398,12 @@ static const char *opt_related_sys_vars[]= {"join_cache_level", static const char *excluded_sys_vars[]= {"optimizer_replay_context", "optimizer_record_context", NULL}; +struct sys_vars_ctx +{ + HASH *engines_hash; + String *script; +}; + static bool is_optimizer_related_var(const char **sys_vars, const char *var_name) { @@ -408,14 +415,57 @@ static bool is_optimizer_related_var(const char **sys_vars, return false; } +static void store_optimizer_costs(const char *engine, + const OPTIMIZER_COSTS *costs, String &script) +{ + char buf[64]; + for (uint i= 0; Show::optimizer_costs_fields_info[i + 1].name().str; i++) + { + const ST_FIELD_INFO *field_info= &Show::optimizer_costs_fields_info[i + 1]; + double cost_val= ((double *) costs)[i]; + + if (strcmp(field_info->name().str, "OPTIMIZER_DISK_READ_RATIO") != 0) + cost_val*= 1000.0; + + script.append(STRING_WITH_LEN("SET GLOBAL ")); + script.append(engine, strlen(engine)); + script.append(STRING_WITH_LEN(".")); + script.append(field_info->name()); + script.append(STRING_WITH_LEN("=")); + + size_t len= my_snprintf(buf, sizeof(buf), "%-.11lg", cost_val); + script.append(buf, len); + script.append(STRING_WITH_LEN(";\n\n")); + } +} + +static my_bool store_engine_costs_callback(THD *thd, plugin_ref plugin, + void *arg) +{ + struct sys_vars_ctx *ctx= (struct sys_vars_ctx *) arg; + handlerton *hton= plugin_hton(plugin); + if (hton->optimizer_costs && + my_hash_search(ctx->engines_hash, + (const uchar *) plugin_name(plugin)->str, + plugin_name(plugin)->length)) + { + store_optimizer_costs(plugin_name(plugin)->str, + (OPTIMIZER_COSTS *) hton->optimizer_costs, + *ctx->script); + } + return 0; +} + /* @brief - Save current values of optimizer variables: append to sql_script + Save current values of optimizer variables: append to script a set of "SET variable=value" statements. */ -static void store_system_variables(THD *thd, String &sql_script) +static void store_system_variables(THD *thd, struct sys_vars_ctx *ctx) { CHARSET_INFO *charset_info= system_charset_info; + String *script= ctx->script; + // hold the lock until the end of this method. // follows the same pattern as in sql_show.cc#fill_variables() mysql_prlock_rdlock(&LOCK_system_variables_hash); @@ -427,6 +477,13 @@ static void store_system_variables(THD *thd, String &sql_script) size_t len; StringBuffer<1024> buf; const char *pos; + + // store all plugin-engines optimizer cost values + plugin_foreach_with_mask(thd, store_engine_costs_callback, + MYSQL_STORAGE_ENGINE_PLUGIN, PLUGIN_IS_READY, ctx); + store_optimizer_costs("heap", &heap_optimizer_costs, *script); + store_optimizer_costs("temp_table", &tmp_table_optimizer_costs, *script); + for (SHOW_VAR *show_var= all_session_vars; show_var->name != NULL; show_var++) { @@ -440,13 +497,13 @@ static void store_system_variables(THD *thd, String &sql_script) pos= get_one_variable(thd, show_var, SHOW_OPT_SESSION, show_var->type, NULL, &charset_info, buf.c_ptr_safe(), &len); mysql_mutex_unlock(&LOCK_global_system_variables); - sql_script.append(STRING_WITH_LEN("SET ")); + script->append(STRING_WITH_LEN("SET ")); if (var->check_type(SHOW_OPT_SESSION)) - sql_script.append(STRING_WITH_LEN("GLOBAL ")); + script->append(STRING_WITH_LEN("GLOBAL ")); - sql_script.append(show_var->name, strlen(show_var->name)); - sql_script.append(STRING_WITH_LEN("=")); + script->append(show_var->name, strlen(show_var->name)); + script->append(STRING_WITH_LEN("=")); switch (var->show_type()) { case SHOW_DOUBLE: @@ -458,15 +515,15 @@ static void store_system_variables(THD *thd, String &sql_script) case SHOW_SLONG: case SHOW_SLONGLONG: case SHOW_SIZE_T: - sql_script.append(pos, len); + script->append(pos, len); break; default: - sql_script.append(STRING_WITH_LEN("'")); - sql_script.append(pos, len); - sql_script.append(STRING_WITH_LEN("'")); + script->append(STRING_WITH_LEN("'")); + script->append(pos, len); + script->append(STRING_WITH_LEN("'")); break; } - sql_script.append(STRING_WITH_LEN(";\n\n")); + script->append(STRING_WITH_LEN(";\n\n")); } } mysql_prlock_unlock(&LOCK_system_variables_hash); @@ -474,7 +531,7 @@ static void store_system_variables(THD *thd, String &sql_script) /* @brief - Append the "create database db_name" DDL statement to sql_script, if it is + Append the "create database db_name" DDL statement to script, if it is not already present in the db_name_hash. Also, append "use database db_name" if the flag req_use_db_stmt is set. @@ -482,7 +539,7 @@ static void store_system_variables(THD *thd, String &sql_script) 0 OK 1 OOM error */ -static bool store_db_ddl(THD *thd, HASH *db_name_hash, String &sql_script, +static bool store_db_ddl(THD *thd, HASH *db_name_hash, String &script, const char *db_name, bool req_use_db_stmt) { size_t db_name_len= strlen(db_name); @@ -500,15 +557,15 @@ static bool store_db_ddl(THD *thd, HASH *db_name_hash, String &sql_script, if (my_hash_insert(db_name_hash, (uchar *) db_name_key)) return true; // OOM - sql_script.append(STRING_WITH_LEN("CREATE DATABASE IF NOT EXISTS ")); - sql_script.append(db_name, db_name_len); - sql_script.append(STRING_WITH_LEN(";\n\n")); + script.append(STRING_WITH_LEN("CREATE DATABASE IF NOT EXISTS ")); + script.append(db_name, db_name_len); + script.append(STRING_WITH_LEN(";\n\n")); if (req_use_db_stmt) { - sql_script.append(STRING_WITH_LEN("USE ")); - sql_script.append(db_name, db_name_len); - sql_script.append(STRING_WITH_LEN(";\n\n")); + script.append(STRING_WITH_LEN("USE ")); + script.append(db_name, db_name_len); + script.append(STRING_WITH_LEN(";\n\n")); } } @@ -551,15 +608,17 @@ bool store_optimizer_context(THD *thd) return false; } String sql_script; + String qry_ctx_script; sql_script.set_charset(system_charset_info); Json_writer ctx_writer; Json_writer_object context(&ctx_writer); Json_writer_array context_list(&ctx_writer, "list_contexts"); sql_script.append(STRING_WITH_LEN("SET NAMES utf8mb4;\n\n ")); - store_system_variables(thd, sql_script); HASH table_name_hash; + HASH storage_engine_hash; HASH db_name_hash; List tables_list; + bool res= false; /* lex->query_tables lists the VIEWs before their underlying tables. @@ -582,17 +641,35 @@ bool store_optimizer_context(THD *thd) if (my_hash_init(key_memory_trace_ddl_info, &table_name_hash, system_charset_info, 16, 0, 0, get_table_name_key, NULL, HASH_UNIQUE) || + my_hash_init(key_memory_trace_ddl_info, &storage_engine_hash, + system_charset_info, 16, 0, 0, get_db_name_key, NULL, + HASH_UNIQUE) || my_hash_init(key_memory_trace_ddl_info, &db_name_hash, system_charset_info, 16, 0, 0, get_db_name_key, NULL, HASH_UNIQUE) || - store_db_ddl(thd, &db_name_hash, sql_script, thd->get_db(), true)) + store_db_ddl(thd, &db_name_hash, qry_ctx_script, thd->get_db(), true)) { - return true; + res= true; // OOM + } + + if (!res && thd->variables.table_plugin) + { + const LEX_CSTRING *engine_name= plugin_name(thd->variables.table_plugin); + DB_NAME_KEY *engine_name_key; + if (!(engine_name_key= (DB_NAME_KEY *) thd->alloc(sizeof(DB_NAME_KEY)))) + { + res= true; // OOM + } + engine_name_key->name= engine_name->str; + engine_name_key->name_len= engine_name->length; + if (my_hash_insert(&storage_engine_hash, (uchar *) engine_name_key)) + { + res= true; // OOM + } } - bool res= false; List uniq_tables_list; - for (TABLE_LIST *tbl= li++; tbl; tbl= li++) + for (TABLE_LIST *tbl= li++; !res && tbl; tbl= li++) { String ddl; String full_tbl_name; @@ -607,8 +684,8 @@ bool store_optimizer_context(THD *thd) full_tbl_name.length())) continue; - if (store_db_ddl(thd, &db_name_hash, sql_script, tbl->get_db_name().str, - false)) + if (store_db_ddl(thd, &db_name_hash, qry_ctx_script, + tbl->get_db_name().str, false)) { res= true; break; @@ -620,8 +697,8 @@ bool store_optimizer_context(THD *thd) drop.append(STRING_WITH_LEN("DROP VIEW IF EXISTS ")); drop.append(full_tbl_name); drop.append(STRING_WITH_LEN(";\n")); - sql_script.append(drop); - + qry_ctx_script.append(drop); + create_view_def(thd, tbl, &full_tbl_name, &ddl); } else @@ -630,7 +707,7 @@ bool store_optimizer_context(THD *thd) drop.append(STRING_WITH_LEN("DROP TABLE IF EXISTS ")); drop.append(full_tbl_name); drop.append(STRING_WITH_LEN(";\n")); - sql_script.append(drop); + qry_ctx_script.append(drop); if (show_create_table(thd, tbl, &ddl, NULL, WITH_DB_NAME)) { @@ -655,8 +732,8 @@ bool store_optimizer_context(THD *thd) break; } - sql_script.append(ddl); - sql_script.append(STRING_WITH_LEN(";\n\n")); + qry_ctx_script.append(ddl); + qry_ctx_script.append(STRING_WITH_LEN(";\n\n")); if (!tbl->is_view()) { @@ -668,23 +745,53 @@ bool store_optimizer_context(THD *thd) List_iterator inserts_li(table_context->const_tbl_ins_stmt_list); while (char *stmt= inserts_li++) { - sql_script.append(stmt, strlen(stmt)); - sql_script.append(STRING_WITH_LEN(";\n\n")); + qry_ctx_script.append(stmt, strlen(stmt)); + qry_ctx_script.append(STRING_WITH_LEN(";\n\n")); } } dump_table_stats(thd, tbl, (uchar *) tbl_name_key->name, tbl_name_key->name_len, ctx_wrapper, &ctx_writer); } uniq_tables_list.push_front(tbl); + + if (is_base_table(tbl)) + { + const LEX_CSTRING *engine_name= plugin_name(tbl->table->s->db_plugin); + if (!my_hash_search(&storage_engine_hash, (uchar *) engine_name->str, + engine_name->length)) + { + DB_NAME_KEY *engine_name_key; + if (!(engine_name_key= + (DB_NAME_KEY *) thd->alloc(sizeof(DB_NAME_KEY)))) + { + res= true; // OOM + break; + } + engine_name_key->name= engine_name->str; + engine_name_key->name_len= engine_name->length; + if (my_hash_insert(&storage_engine_hash, (uchar *) engine_name_key)) + { + res= true; // OOM + break; + } + } + } } context_list.end(); context.end(); if (!res) - res= dump_eits_stats(thd, &uniq_tables_list, sql_script); + res= dump_eits_stats(thd, &uniq_tables_list, qry_ctx_script); if (!res) { + String sys_vars_script; + struct sys_vars_ctx ctx; + ctx.engines_hash= &storage_engine_hash; + ctx.script= &sys_vars_script; + store_system_variables(thd, &ctx); + sql_script.append(sys_vars_script); + sql_script.append(qry_ctx_script); const char *SET_OPT_CONTEXT_VAR= "set @opt_context=\'\n"; const char *SET_REPLAY_CONTEXT_VAR= "set optimizer_replay_context=\'opt_context\'"; @@ -710,9 +817,10 @@ bool store_optimizer_context(THD *thd) sql_script.append(STRING_WITH_LEN("set optimizer_replay_context='';\n\n")); thd->captured_opt_ctx= new Optimizer_context_capture(thd, sql_script); if (!thd->captured_opt_ctx) - return true; // OOM + res= true; // OOM } my_hash_free(&table_name_hash); + my_hash_free(&storage_engine_hash); my_hash_free(&db_name_hash); return res; }