Skip to content

Commit

Permalink
PS-5783: New thread variables: innodb_(force_index_)records_in_range
Browse files Browse the repository at this point in the history
These variables make it possible to override reconds_in_range, effectively
skipping its computation. This could be useful in some cases where reconds_in_range
takes up most of the query cost.
  • Loading branch information
dutow authored and inikep committed Sep 12, 2024
1 parent c575df0 commit 7a3825d
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
SELECT @@GLOBAL.innodb_force_index_records_in_range;
@@GLOBAL.innodb_force_index_records_in_range
0
0 Expected
SET @@GLOBAL.innodb_force_index_records_in_range=100;
1 Expected
SELECT @@GLOBAL.innodb_force_index_records_in_range;
@@GLOBAL.innodb_force_index_records_in_range
100
100 Expected
SET @@GLOBAL.innodb_force_index_records_in_range=DEFAULT;
1 Expected
SELECT @@GLOBAL.innodb_force_index_records_in_range;
@@GLOBAL.innodb_force_index_records_in_range
0
0 Expected
SELECT @@GLOBAL.innodb_force_index_records_in_range = VARIABLE_VALUE
FROM performance_schema.global_variables
WHERE VARIABLE_NAME='innodb_force_index_records_in_range';
@@GLOBAL.innodb_force_index_records_in_range = VARIABLE_VALUE
1
1 Expected
SELECT @@GLOBAL.innodb_force_index_records_in_range;
@@GLOBAL.innodb_force_index_records_in_range
0
0 Expected
SELECT VARIABLE_VALUE
FROM performance_schema.global_variables
WHERE VARIABLE_NAME='innodb_force_index_records_in_range';
VARIABLE_VALUE
0
0 Expected
SELECT @@innodb_force_index_records_in_range = VARIABLE_VALUE
FROM performance_schema.session_variables
WHERE VARIABLE_NAME='innodb_force_index_records_in_range';
@@innodb_force_index_records_in_range = VARIABLE_VALUE
1
1 Expected
SELECT VARIABLE_VALUE
FROM performance_schema.session_variables
WHERE VARIABLE_NAME='innodb_force_index_records_in_range';
VARIABLE_VALUE
0
0 Expected
SELECT @@innodb_force_index_records_in_range = @@GLOBAL.innodb_force_index_records_in_range;
@@innodb_force_index_records_in_range = @@GLOBAL.innodb_force_index_records_in_range
1
1 Expected
SELECT @@innodb_force_index_records_in_range;
@@innodb_force_index_records_in_range
0
0 Expected
SELECT @@local.innodb_force_index_records_in_range;
@@local.innodb_force_index_records_in_range
0
0 Expected
SELECT @@SESSION.innodb_force_index_records_in_range;
@@SESSION.innodb_force_index_records_in_range
0
0 Expected
SELECT @@GLOBAL.innodb_force_index_records_in_range;
@@GLOBAL.innodb_force_index_records_in_range
0
0 Expected
SELECT innodb_force_index_records_in_range;
ERROR 42S22: Unknown column 'innodb_force_index_records_in_range' in 'field list'
Expected error 'Unknow column in field list'
67 changes: 67 additions & 0 deletions mysql-test/suite/sys_vars/r/innodb_records_in_range_basic.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
SELECT @@GLOBAL.innodb_records_in_range;
@@GLOBAL.innodb_records_in_range
0
0 Expected
SET @@GLOBAL.innodb_records_in_range=100;
1 Expected
SELECT @@GLOBAL.innodb_records_in_range;
@@GLOBAL.innodb_records_in_range
100
100 Expected
SET @@GLOBAL.innodb_records_in_range=DEFAULT;
1 Expected
SELECT @@GLOBAL.innodb_records_in_range;
@@GLOBAL.innodb_records_in_range
0
0 Expected
SELECT @@GLOBAL.innodb_records_in_range = VARIABLE_VALUE
FROM performance_schema.global_variables
WHERE VARIABLE_NAME='innodb_records_in_range';
@@GLOBAL.innodb_records_in_range = VARIABLE_VALUE
1
1 Expected
SELECT @@GLOBAL.innodb_records_in_range;
@@GLOBAL.innodb_records_in_range
0
0 Expected
SELECT VARIABLE_VALUE
FROM performance_schema.global_variables
WHERE VARIABLE_NAME='innodb_records_in_range';
VARIABLE_VALUE
0
0 Expected
SELECT @@innodb_records_in_range = VARIABLE_VALUE
FROM performance_schema.session_variables
WHERE VARIABLE_NAME='innodb_records_in_range';
@@innodb_records_in_range = VARIABLE_VALUE
1
1 Expected
SELECT VARIABLE_VALUE
FROM performance_schema.session_variables
WHERE VARIABLE_NAME='innodb_records_in_range';
VARIABLE_VALUE
0
0 Expected
SELECT @@innodb_records_in_range = @@GLOBAL.innodb_records_in_range;
@@innodb_records_in_range = @@GLOBAL.innodb_records_in_range
1
1 Expected
SELECT @@innodb_records_in_range;
@@innodb_records_in_range
0
0 Expected
SELECT @@local.innodb_records_in_range;
@@local.innodb_records_in_range
0
0 Expected
SELECT @@SESSION.innodb_records_in_range;
@@SESSION.innodb_records_in_range
0
0 Expected
SELECT @@GLOBAL.innodb_records_in_range;
@@GLOBAL.innodb_records_in_range
0
0 Expected
SELECT innodb_records_in_range;
ERROR 42S22: Unknown column 'innodb_records_in_range' in 'field list'
Expected error 'Unknow column in field list'
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Display default value
SELECT @@GLOBAL.innodb_force_index_records_in_range;
--echo 0 Expected

# Check if value can be set
SET @@GLOBAL.innodb_force_index_records_in_range=100;
--echo 1 Expected

SELECT @@GLOBAL.innodb_force_index_records_in_range;
--echo 100 Expected

SET @@GLOBAL.innodb_force_index_records_in_range=DEFAULT;
--echo 1 Expected

SELECT @@GLOBAL.innodb_force_index_records_in_range;
--echo 0 Expected

# Check if the value in GLOBAL TABLE matches value in variable
SELECT @@GLOBAL.innodb_force_index_records_in_range = VARIABLE_VALUE
FROM performance_schema.global_variables
WHERE VARIABLE_NAME='innodb_force_index_records_in_range';
--echo 1 Expected

SELECT @@GLOBAL.innodb_force_index_records_in_range;
--echo 0 Expected

SELECT VARIABLE_VALUE
FROM performance_schema.global_variables
WHERE VARIABLE_NAME='innodb_force_index_records_in_range';
--echo 0 Expected

SELECT @@innodb_force_index_records_in_range = VARIABLE_VALUE
FROM performance_schema.session_variables
WHERE VARIABLE_NAME='innodb_force_index_records_in_range';
--echo 1 Expected

SELECT VARIABLE_VALUE
FROM performance_schema.session_variables
WHERE VARIABLE_NAME='innodb_force_index_records_in_range';
--echo 0 Expected

# Check if accessing variable with and without GLOBAL point to same variable
SELECT @@innodb_force_index_records_in_range = @@GLOBAL.innodb_force_index_records_in_range;
--echo 1 Expected

# Check if innodb_force_index_records_in_range can be accessed with and without @@ sign
SELECT @@innodb_force_index_records_in_range;
--echo 0 Expected

SELECT @@local.innodb_force_index_records_in_range;
--echo 0 Expected

SELECT @@SESSION.innodb_force_index_records_in_range;
--echo 0 Expected

SELECT @@GLOBAL.innodb_force_index_records_in_range;
--echo 0 Expected

--Error ER_BAD_FIELD_ERROR
SELECT innodb_force_index_records_in_range;
--echo Expected error 'Unknow column in field list'
61 changes: 61 additions & 0 deletions mysql-test/suite/sys_vars/t/innodb_records_in_range_basic.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Display default value
SELECT @@GLOBAL.innodb_records_in_range;
--echo 0 Expected

# Check if value can be set
SET @@GLOBAL.innodb_records_in_range=100;
--echo 1 Expected

SELECT @@GLOBAL.innodb_records_in_range;
--echo 100 Expected

SET @@GLOBAL.innodb_records_in_range=DEFAULT;
--echo 1 Expected

SELECT @@GLOBAL.innodb_records_in_range;
--echo 0 Expected

# Check if the value in GLOBAL TABLE matches value in variable
SELECT @@GLOBAL.innodb_records_in_range = VARIABLE_VALUE
FROM performance_schema.global_variables
WHERE VARIABLE_NAME='innodb_records_in_range';
--echo 1 Expected

SELECT @@GLOBAL.innodb_records_in_range;
--echo 0 Expected

SELECT VARIABLE_VALUE
FROM performance_schema.global_variables
WHERE VARIABLE_NAME='innodb_records_in_range';
--echo 0 Expected

SELECT @@innodb_records_in_range = VARIABLE_VALUE
FROM performance_schema.session_variables
WHERE VARIABLE_NAME='innodb_records_in_range';
--echo 1 Expected

SELECT VARIABLE_VALUE
FROM performance_schema.session_variables
WHERE VARIABLE_NAME='innodb_records_in_range';
--echo 0 Expected

# Check if accessing variable with and without GLOBAL point to same variable
SELECT @@innodb_records_in_range = @@GLOBAL.innodb_records_in_range;
--echo 1 Expected

# Check if innodb_records_in_range can be accessed with and without @@ sign
SELECT @@innodb_records_in_range;
--echo 0 Expected

SELECT @@local.innodb_records_in_range;
--echo 0 Expected

SELECT @@SESSION.innodb_records_in_range;
--echo 0 Expected

SELECT @@GLOBAL.innodb_records_in_range;
--echo 0 Expected

--Error ER_BAD_FIELD_ERROR
SELECT innodb_records_in_range;
--echo Expected error 'Unknow column in field list'
20 changes: 20 additions & 0 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,24 @@ static PSI_file_info all_innodb_files[] = {
#endif /* UNIV_PFS_IO */
#endif /* HAVE_PSI_INTERFACE */

static MYSQL_THDVAR_UINT(records_in_range, PLUGIN_VAR_RQCMDARG,
"Used to override the result of records_in_range(). "
"Set to a positive number to override",
NULL, NULL, 0,
/* min */ 0, /* max */ INT_MAX, 0);

static MYSQL_THDVAR_UINT(force_index_records_in_range, PLUGIN_VAR_RQCMDARG,
"Used to override the result of records_in_range() "
"when FORCE INDEX is used.",
NULL, NULL, 0,
/* min */ 0, /* max */ INT_MAX, 0);

uint innodb_force_index_records_in_range(THD *thd) {
return THDVAR(thd, force_index_records_in_range);
}

uint innodb_records_in_range(THD *thd) { return THDVAR(thd, records_in_range); }

/** Plugin update function to handle validation and then switch the
innodb_doublewrite mode
@param[in] thd thread handle
Expand Down Expand Up @@ -24354,6 +24372,8 @@ static SYS_VAR *innobase_system_variables[] = {
MYSQL_SYSVAR(compressed_columns_zip_level),
MYSQL_SYSVAR(compressed_columns_threshold),
MYSQL_SYSVAR(ft_ignore_stopwords),
MYSQL_SYSVAR(records_in_range),
MYSQL_SYSVAR(force_index_records_in_range),
nullptr};

mysql_declare_plugin(innobase){
Expand Down
3 changes: 3 additions & 0 deletions storage/innobase/handler/ha_innodb.h
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,9 @@ bool innobase_build_index_translation(const TABLE *table,
dict_table_t *ib_table,
INNOBASE_SHARE *share);

uint innodb_force_index_records_in_range(THD *thd);
uint innodb_records_in_range(THD *thd);

/** Free InnoDB session specific data.
@param[in,out] thd MySQL thread handler. */
void thd_free_innodb_session(THD *thd) noexcept;
Expand Down
11 changes: 11 additions & 0 deletions storage/innobase/handler/ha_innopart.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3340,6 +3340,17 @@ ha_rows ha_innopart::records_in_range(uint keynr, key_range *min_key,

ut_ad(m_prebuilt->trx == thd_to_trx(ha_thd()));

ha_rows ret = innodb_records_in_range(ha_thd());
if (ret) {
return ret;
}
if (table->force_index) {
const ha_rows force_rows = innodb_force_index_records_in_range(ha_thd());
if (force_rows) {
return force_rows;
}
}

m_prebuilt->trx->op_info = (char *)"estimating records in index range";

active_index = keynr;
Expand Down

0 comments on commit 7a3825d

Please sign in to comment.