Commit 14fe6dd2 authored by Aditya A's avatar Aditya A Committed by Marko Mäkelä

Bug #23046302 COUNT(*) MUCH SLOWER ON 5.7 THAN 5.6

ANALYSIS

This is regression caused due to worklog 6742 which
implemented ha_innobase::records() which always
uses clustered index to get the row count. Previously
optimizer chose secondary index which was smaller in
size of clustered index to scan for rows and resulted in
a quicker scan.

FIX

After discussion it was decided to remove this feature in 5.7.

[#rb14040 Approved by Kevin and Oystein ]
parent 07f33115
......@@ -14230,116 +14230,6 @@ ha_innobase::rename_table(
DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
}
/*********************************************************************//**
Returns the exact number of records that this client can see using this
handler object.
@return Error code in case something goes wrong.
These errors will abort the current query:
case HA_ERR_LOCK_DEADLOCK:
case HA_ERR_LOCK_TABLE_FULL:
case HA_ERR_LOCK_WAIT_TIMEOUT:
case HA_ERR_QUERY_INTERRUPTED:
For other error codes, the server will fall back to counting records. */
#ifdef MYSQL_57_SELECT_COUNT_OPTIMIZATION
int
ha_innobase::records(
/*==================*/
ha_rows* num_rows) /*!< out: number of rows */
{
DBUG_ENTER("ha_innobase::records()");
dberr_t ret;
ulint n_rows = 0; /* Record count in this view */
update_thd();
if (dict_table_is_discarded(m_prebuilt->table)) {
ib_senderrf(
m_user_thd,
IB_LOG_LEVEL_ERROR,
ER_TABLESPACE_DISCARDED,
table->s->table_name.str);
*num_rows = HA_POS_ERROR;
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
} else if (m_prebuilt->table->ibd_file_missing) {
ib_senderrf(
m_user_thd, IB_LOG_LEVEL_ERROR,
ER_TABLESPACE_MISSING,
table->s->table_name.str);
*num_rows = HA_POS_ERROR;
DBUG_RETURN(HA_ERR_TABLESPACE_MISSING);
} else if (m_prebuilt->table->corrupted) {
ib_errf(m_user_thd, IB_LOG_LEVEL_WARN,
ER_INNODB_INDEX_CORRUPT,
"Table '%s' is corrupt.",
table->s->table_name.str);
*num_rows = HA_POS_ERROR;
DBUG_RETURN(HA_ERR_INDEX_CORRUPT);
}
TrxInInnoDB trx_in_innodb(m_prebuilt->trx);
m_prebuilt->trx->op_info = "counting records";
dict_index_t* index = dict_table_get_first_index(m_prebuilt->table);
ut_ad(dict_index_is_clust(index));
m_prebuilt->index_usable = row_merge_is_index_usable(
m_prebuilt->trx, index);
if (!m_prebuilt->index_usable) {
*num_rows = HA_POS_ERROR;
DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED);
}
/* (Re)Build the m_prebuilt->mysql_template if it is null to use
the clustered index and just the key, no off-record data. */
m_prebuilt->index = index;
dtuple_set_n_fields(m_prebuilt->search_tuple, 0);
m_prebuilt->read_just_key = 1;
build_template(false);
/* Count the records in the clustered index */
ret = row_scan_index_for_mysql(m_prebuilt, index, false, &n_rows);
reset_template();
switch (ret) {
case DB_SUCCESS:
break;
case DB_DEADLOCK:
case DB_LOCK_TABLE_FULL:
case DB_LOCK_WAIT_TIMEOUT:
*num_rows = HA_POS_ERROR;
DBUG_RETURN(convert_error_code_to_mysql(ret, 0, m_user_thd));
case DB_INTERRUPTED:
*num_rows = HA_POS_ERROR;
DBUG_RETURN(HA_ERR_QUERY_INTERRUPTED);
default:
/* No other error besides the three below is returned from
row_scan_index_for_mysql(). Make a debug catch. */
*num_rows = HA_POS_ERROR;
ut_ad(0);
DBUG_RETURN(-1);
}
m_prebuilt->trx->op_info = "";
if (thd_killed(m_user_thd)) {
*num_rows = HA_POS_ERROR;
DBUG_RETURN(HA_ERR_QUERY_INTERRUPTED);
}
*num_rows= n_rows;
DBUG_RETURN(0);
}
#endif /* MYSQL_57_SELECT_COUNT_OPTIMIZATION */
/*********************************************************************//**
Estimates the number of index records in a range.
@return estimated number of rows */
......@@ -15586,7 +15476,7 @@ ha_innobase::check(
ret = row_count_rtree_recs(m_prebuilt, &n_rows);
} else {
ret = row_scan_index_for_mysql(
m_prebuilt, index, true, &n_rows);
m_prebuilt, index, &n_rows);
}
DBUG_EXECUTE_IF(
......
/*****************************************************************************
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
......@@ -219,9 +219,6 @@ class ha_innobase: public handler
ha_rows estimate_rows_upper_bound();
// JAN: TODO: MySQL 5.7
// int records(ha_rows* num_rows);
void update_create_info(HA_CREATE_INFO* create_info);
int create(
......
/*****************************************************************************
Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2016, 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
......@@ -3004,41 +3004,6 @@ ha_innopart::truncate()
DBUG_RETURN(error);
}
/** Total number of rows in all used partitions.
Returns the exact number of records that this client can see using this
handler object.
@param[out] num_rows Number of rows.
@return 0 or error number. */
int
ha_innopart::records(
ha_rows* num_rows)
{
ha_rows n_rows;
int err;
DBUG_ENTER("ha_innopart::records()");
*num_rows = 0;
/* The index scan is probably so expensive, so the overhead
of the rest of the function is neglectable for each partition.
So no current reason for optimizing this further. */
for (uint i = m_part_info->get_first_used_partition();
i < m_tot_parts;
i = m_part_info->get_next_used_partition(i)) {
set_partition(i);
err = ha_innobase::records(&n_rows);
update_partition(i);
if (err != 0) {
*num_rows = HA_POS_ERROR;
DBUG_RETURN(err);
}
*num_rows += n_rows;
}
DBUG_RETURN(0);
}
/** Estimates the number of index records in a range.
@param[in] keynr Index number.
@param[in] min_key Start key value (or NULL).
......
......@@ -1221,10 +1221,6 @@ class ha_innopart:
uchar* record,
uchar* pos);
int
records(
ha_rows* num_rows);
int
index_next(
uchar* record)
......
......@@ -38,7 +38,6 @@ simple headers.
class THD;
// JAN: TODO missing features:
#undef MYSQL_57_SELECT_COUNT_OPTIMIZATION
#undef MYSQL_FT_INIT_EXT
#undef MYSQL_INNODB_PARTITIONING
#undef MYSQL_PFS
......
/*****************************************************************************
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
......@@ -540,9 +540,6 @@ row_scan_index_for_mysql(
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct
in MySQL handle */
const dict_index_t* index, /*!< in: index */
bool check_keys, /*!< in: true=check for mis-
ordered or duplicate records,
false=count the rows only */
ulint* n_rows) /*!< out: number of entries
seen in the consistent read */
MY_ATTRIBUTE((warn_unused_result));
......
/*****************************************************************************
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
......@@ -5046,9 +5046,6 @@ row_scan_index_for_mysql(
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct
in MySQL handle */
const dict_index_t* index, /*!< in: index */
bool check_keys, /*!< in: true=check for mis-
ordered or duplicate records,
false=count the rows only */
ulint* n_rows) /*!< out: number of entries
seen in the consistent read */
{
......@@ -5115,7 +5112,7 @@ row_scan_index_for_mysql(
goto func_exit;
default:
{
const char* doing = check_keys? "CHECK TABLE" : "COUNT(*)";
const char* doing = "CHECK TABLE";
ib::warn() << doing << " on index " << index->name << " of"
" table " << index->table->name << " returned " << ret;
/* fall through (this error is ignored by CHECK TABLE) */
......@@ -5131,9 +5128,6 @@ row_scan_index_for_mysql(
*n_rows = *n_rows + 1;
if (!check_keys) {
goto next_rec;
}
/* else this code is doing handler::check() for CHECK TABLE */
/* row_search... returns the index record in buf, record origin offset
......@@ -5215,7 +5209,6 @@ row_scan_index_for_mysql(
}
}
next_rec:
ret = row_search_for_mysql(
buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment