From 1cda4726ca6bc4d43c3545c744a5b0a4357e7dba Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 24 Sep 2024 10:23:34 +0300 Subject: [PATCH] MDEV-34993, part2: backport optimizer_adjust_secondary_key_costs ...and make the fix for MDEV-34993 switchable. It is enabled by default and controlled with @optimizer_adjust_secondary_key_costs=fix_card_multiplier --- mysql-test/main/mysqld--help.result | 7 +++ .../selectivity_innodb_notembedded.result | 54 +++++++++++++++++++ .../main/selectivity_notembedded.result | 54 +++++++++++++++++++ mysql-test/main/selectivity_notembedded.test | 18 +++++++ .../r/sysvars_server_notembedded.result | 10 ++++ sql/opt_range.cc | 4 +- sql/sql_class.h | 5 ++ sql/sql_priv.h | 5 ++ sql/sys_vars.cc | 19 +++++++ 9 files changed, 175 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result index 43377506eba..83a93a197a6 100644 --- a/mysql-test/main/mysqld--help.result +++ b/mysql-test/main/mysqld--help.result @@ -682,6 +682,12 @@ The following specify which files/extra groups are read (specified before remain max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of file descriptors (Automatically configured unless set explicitly) + --optimizer-adjust-secondary-key-costs=name + A bit field with the following values: + fix_card_multiplier = Fix the computation in + selectivity_for_indexes. selectivity_multiplier. This + variable will be deleted in MariaDB 11.0 as it is not + needed with the new 11.0 optimizer. --optimizer-max-sel-arg-weight=# The maximum weight of the SEL_ARG graph. Set to 0 for no limit @@ -1642,6 +1648,7 @@ old-alter-table DEFAULT old-mode old-passwords FALSE old-style-user-limits FALSE +optimizer-adjust-secondary-key-costs fix_card_multiplier optimizer-max-sel-arg-weight 32000 optimizer-prune-level 1 optimizer-search-depth 62 diff --git a/mysql-test/main/selectivity_innodb_notembedded.result b/mysql-test/main/selectivity_innodb_notembedded.result index 5f8e9e85d5e..0ed8908063e 100644 --- a/mysql-test/main/selectivity_innodb_notembedded.result +++ b/mysql-test/main/selectivity_innodb_notembedded.result @@ -280,7 +280,61 @@ JS } } ] +# Disable the fix and try the same: +set @@optimizer_adjust_secondary_key_costs=''; +explain select * from t1 +where +pk in (1,2,3,4,5) and +key1 <= 4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY,key1 PRIMARY 4 NULL 5 Using where drop table t1; +# Shows a high multiplier, without a "note": +select +json_detailed(json_extract(trace,'$**.selectivity_for_indexes')) as JS +from +information_schema.optimizer_trace; +JS +[ + [ + { + "index_name": "PRIMARY", + "selectivity_from_index": 0.005 + }, + { + "index_name": "key1", + "selectivity_from_index": 0.399, + "selectivity_multiplier": 90.9091 + } + ] +] +# Includes 1.79...e308 as cost: +select +json_detailed(json_extract(trace,'$**.best_access_path')) as JS +from +information_schema.optimizer_trace; +JS +[ + { + "considered_access_paths": + [ + { + "access_type": "range", + "resulting_rows": 181.3636545, + "cost": 1.79769e308, + "chosen": true + } + ], + "chosen_access_method": + { + "type": "range", + "records": 181.3636545, + "cost": 1.79769e308, + "uses_join_buffering": false + } + } +] +set optimizer_adjust_secondary_key_costs=default; # # Clean up # diff --git a/mysql-test/main/selectivity_notembedded.result b/mysql-test/main/selectivity_notembedded.result index 995ef1681a4..77ae626f567 100644 --- a/mysql-test/main/selectivity_notembedded.result +++ b/mysql-test/main/selectivity_notembedded.result @@ -275,7 +275,61 @@ JS } } ] +# Disable the fix and try the same: +set @@optimizer_adjust_secondary_key_costs=''; +explain select * from t1 +where +pk in (1,2,3,4,5) and +key1 <= 4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY,key1 PRIMARY 4 NULL 5 Using index condition; Using where drop table t1; +# Shows a high multiplier, without a "note": +select +json_detailed(json_extract(trace,'$**.selectivity_for_indexes')) as JS +from +information_schema.optimizer_trace; +JS +[ + [ + { + "index_name": "PRIMARY", + "selectivity_from_index": 0.005 + }, + { + "index_name": "key1", + "selectivity_from_index": 0.391, + "selectivity_multiplier": 90.9091 + } + ] +] +# Includes 1.79...e308 as cost: +select +json_detailed(json_extract(trace,'$**.best_access_path')) as JS +from +information_schema.optimizer_trace; +JS +[ + { + "considered_access_paths": + [ + { + "access_type": "range", + "resulting_rows": 177.7272905, + "cost": 1.79769e308, + "chosen": true + } + ], + "chosen_access_method": + { + "type": "range", + "records": 177.7272905, + "cost": 1.79769e308, + "uses_join_buffering": false + } + } +] +set optimizer_adjust_secondary_key_costs=default; # # Clean up # diff --git a/mysql-test/main/selectivity_notembedded.test b/mysql-test/main/selectivity_notembedded.test index b5f004502eb..2c4431adb23 100644 --- a/mysql-test/main/selectivity_notembedded.test +++ b/mysql-test/main/selectivity_notembedded.test @@ -257,7 +257,25 @@ select from information_schema.optimizer_trace; +--echo # Disable the fix and try the same: +set @@optimizer_adjust_secondary_key_costs=''; +explain select * from t1 +where + pk in (1,2,3,4,5) and + key1 <= 4; drop table t1; +--echo # Shows a high multiplier, without a "note": +select + json_detailed(json_extract(trace,'$**.selectivity_for_indexes')) as JS +from + information_schema.optimizer_trace; + +--echo # Includes 1.79...e308 as cost: +select + json_detailed(json_extract(trace,'$**.best_access_path')) as JS +from + information_schema.optimizer_trace; +set optimizer_adjust_secondary_key_costs=default; --echo # --echo # Clean up diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index ea1dd7af53b..50dd4ae23a3 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -2402,6 +2402,16 @@ NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME OPTIMIZER_ADJUST_SECONDARY_KEY_COSTS +VARIABLE_SCOPE SESSION +VARIABLE_TYPE SET +VARIABLE_COMMENT A bit field with the following values: fix_card_multiplier = Fix the computation in selectivity_for_indexes. selectivity_multiplier. This variable will be deleted in MariaDB 11.0 as it is not needed with the new 11.0 optimizer. +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST fix_card_multiplier +READ_ONLY NO +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME OPTIMIZER_MAX_SEL_ARG_WEIGHT VARIABLE_SCOPE SESSION VARIABLE_TYPE BIGINT UNSIGNED diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 15a9dfb2e0f..8d36fdb4a18 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3521,7 +3521,9 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) multiplied by quick_cond_selectivity above, so we will only multiply it with selectivity_mult). */ - if (selectivity_mult > 1.0 / quick_cond_selectivity) + if ((thd->variables.optimizer_adjust_secondary_key_costs & + OPTIMIZER_ADJ_FIX_CARD_MULT) && + selectivity_mult > 1.0 / quick_cond_selectivity) { selectivity_for_index.add("note", "multiplier too high, clipping"); selectivity_mult= 1.0/quick_cond_selectivity; diff --git a/sql/sql_class.h b/sql/sql_class.h index 93c5850ae3d..3048e27daf8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -672,6 +672,11 @@ typedef struct system_variables ulonglong sortbuff_size; ulonglong default_regex_flags; ulonglong max_mem_used; + /* + A bitmap of OPTIMIZER_ADJ_* flags (defined in sql_priv.h). + See sys_vars.cc:adjust_secondary_key_cost for symbolic names. + */ + ulonglong optimizer_adjust_secondary_key_costs; /** Place holders to store Multi-source variables in sys_var.cc during diff --git a/sql/sql_priv.h b/sql/sql_priv.h index 2335c6ba516..f7367e93edf 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -266,6 +266,11 @@ OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING | \ OPTIMIZER_SWITCH_OPTIMIZE_JOIN_BUFFER_SIZE) +/* + See adjust_secondary_key_cost in sys_vars.cc for symbolic names. +*/ +#define OPTIMIZER_ADJ_FIX_CARD_MULT (1) + /* Replication uses 8 bytes to store SQL_MODE in the binary log. The day you use strictly more than 64 bits by adding one more define above, you should diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 44302b3a507..93298ff7b04 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2777,6 +2777,25 @@ static Sys_var_ulong Sys_optimizer_trace_max_mem_size( SESSION_VAR(optimizer_trace_max_mem_size), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, ULONG_MAX), DEFAULT(1024 * 1024), BLOCK_SIZE(1)); +/* + Symbolic names for OPTIMIZER_ADJ_* flags in sql_priv.h +*/ +static const char *adjust_secondary_key_cost[]= +{ + "fix_card_multiplier", 0 +}; + +static Sys_var_set Sys_optimizer_adjust_secondary_key_costs( + "optimizer_adjust_secondary_key_costs", + "A bit field with the following values: " + "fix_card_multiplier = Fix the computation in selectivity_for_indexes." + " selectivity_multiplier. " + "This variable will be deleted in MariaDB 11.0 as it is not needed with the " + "new 11.0 optimizer.", + SESSION_VAR(optimizer_adjust_secondary_key_costs), CMD_LINE(REQUIRED_ARG), + adjust_secondary_key_cost, DEFAULT(OPTIMIZER_ADJ_FIX_CARD_MULT)); + + static Sys_var_charptr_fscs Sys_pid_file( "pid_file", "Pid file used by safe_mysqld", READ_ONLY GLOBAL_VAR(pidfile_name_ptr), CMD_LINE(REQUIRED_ARG),