summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2020-02-27 19:12:27 +0200
committerMonty <monty@mariadb.org>2020-03-27 03:54:45 +0200
commitf36ca142f7fa59598e34e842b60372b963067766 (patch)
tree4b797dcf88e98fd9fe83e3a29bfaabc10b7219c2 /storage/innobase
parent9b061990801b5c8309149794145f9c361bb8cfc6 (diff)
downloadmariadb-git-f36ca142f7fa59598e34e842b60372b963067766.tar.gz
Added page_range to records_in_range() to improve range statistics
Prototype change: - virtual ha_rows records_in_range(uint inx, key_range *min_key, - key_range *max_key) + virtual ha_rows records_in_range(uint inx, const key_range *min_key, + const key_range *max_key, + page_range *res) The handler can ignore the page_range parameter. In the case the handler updates the parameter, the optimizer can deduce the following: - If previous range's last key is on the same block as next range's first key - If the current key range is in one block - We can also assume that the first and last block read are cached! This can be used for a better calculation of IO seeks when we estimate the cost of a range index scan. The parameter is fully implemented for MyISAM, Aria and InnoDB. A separate patch will update handler::multi_range_read_info_const() to take the benefits of this change and also remove the double records_in_range() calls that are not anymore needed.
Diffstat (limited to 'storage/innobase')
-rw-r--r--storage/innobase/btr/btr0cur.cc41
-rw-r--r--storage/innobase/handler/ha_innodb.cc11
-rw-r--r--storage/innobase/handler/ha_innodb.h7
-rw-r--r--storage/innobase/include/btr0cur.h37
-rw-r--r--storage/innobase/include/buf0types.h2
5 files changed, 64 insertions, 34 deletions
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index ba5979ff1c6..8a547669894 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -6135,10 +6135,8 @@ static const ha_rows rows_in_range_arbitrary_ret_val = 10;
/** Estimates the number of rows in a given index range.
@param[in] index index
-@param[in] tuple1 range start, may also be empty tuple
-@param[in] mode1 search mode for range start
-@param[in] tuple2 range end, may also be empty tuple
-@param[in] mode2 search mode for range end
+@param[in] tuple1 range start
+@param[in] tuple2 range end
@param[in] nth_attempt if the tree gets modified too much while
we are trying to analyze it, then we will retry (this function will call
itself, incrementing this parameter)
@@ -6151,10 +6149,8 @@ static
ha_rows
btr_estimate_n_rows_in_range_low(
dict_index_t* index,
- const dtuple_t* tuple1,
- page_cur_mode_t mode1,
- const dtuple_t* tuple2,
- page_cur_mode_t mode2,
+ btr_pos_t* tuple1,
+ btr_pos_t* tuple2,
unsigned nth_attempt)
{
btr_path_t path1[BTR_PATH_ARRAY_N_SLOTS];
@@ -6170,6 +6166,7 @@ btr_estimate_n_rows_in_range_low(
ulint i;
mtr_t mtr;
ha_rows table_n_rows;
+ page_cur_mode_t mode2= tuple2->mode;
table_n_rows = dict_table_get_n_rows(index->table);
@@ -6188,9 +6185,10 @@ btr_estimate_n_rows_in_range_low(
bool should_count_the_left_border;
- if (dtuple_get_n_fields(tuple1) > 0) {
+ if (dtuple_get_n_fields(tuple1->tuple) > 0) {
- btr_cur_search_to_nth_level(index, 0, tuple1, mode1,
+ btr_cur_search_to_nth_level(index, 0, tuple1->tuple,
+ tuple1->mode,
BTR_SEARCH_LEAF | BTR_ESTIMATE,
&cursor, 0,
__FILE__, __LINE__, &mtr);
@@ -6230,6 +6228,8 @@ btr_estimate_n_rows_in_range_low(
should_count_the_left_border = false;
}
+ tuple1->page_id= cursor.page_cur.block->page.id;
+
mtr_commit(&mtr);
if (!index->is_readable()) {
@@ -6242,9 +6242,10 @@ btr_estimate_n_rows_in_range_low(
bool should_count_the_right_border;
- if (dtuple_get_n_fields(tuple2) > 0) {
+ if (dtuple_get_n_fields(tuple2->tuple) > 0) {
- btr_cur_search_to_nth_level(index, 0, tuple2, mode2,
+ btr_cur_search_to_nth_level(index, 0, tuple2->tuple,
+ mode2,
BTR_SEARCH_LEAF | BTR_ESTIMATE,
&cursor, 0,
__FILE__, __LINE__, &mtr);
@@ -6256,7 +6257,7 @@ btr_estimate_n_rows_in_range_low(
should_count_the_right_border
= (mode2 == PAGE_CUR_LE /* if the range is '<=' */
/* and the record was found */
- && cursor.low_match >= dtuple_get_n_fields(tuple2))
+ && cursor.low_match >= dtuple_get_n_fields(tuple2->tuple))
|| (mode2 == PAGE_CUR_L /* or if the range is '<' */
/* and there are any records to match the criteria,
i.e. if the minimum record on the tree is 5 and
@@ -6300,6 +6301,8 @@ btr_estimate_n_rows_in_range_low(
should_count_the_right_border = false;
}
+ tuple2->page_id= cursor.page_cur.block->page.id;
+
mtr_commit(&mtr);
/* We have the path information for the range in path1 and path2 */
@@ -6438,8 +6441,8 @@ btr_estimate_n_rows_in_range_low(
}
return btr_estimate_n_rows_in_range_low(
- index, tuple1, mode1,
- tuple2, mode2, nth_attempt + 1);
+ index, tuple1, tuple2,
+ nth_attempt + 1);
}
diverged = true;
@@ -6510,13 +6513,11 @@ btr_estimate_n_rows_in_range_low(
ha_rows
btr_estimate_n_rows_in_range(
dict_index_t* index,
- const dtuple_t* tuple1,
- page_cur_mode_t mode1,
- const dtuple_t* tuple2,
- page_cur_mode_t mode2)
+ btr_pos_t *tuple1,
+ btr_pos_t *tuple2)
{
return btr_estimate_n_rows_in_range_low(
- index, tuple1, mode1, tuple2, mode2, 1);
+ index, tuple1, tuple2, 1);
}
/*******************************************************************//**
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 2d3471fd65c..9c5db57c661 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -13936,10 +13936,11 @@ ha_rows
ha_innobase::records_in_range(
/*==========================*/
uint keynr, /*!< in: index number */
- key_range *min_key, /*!< in: start key value of the
+ const key_range *min_key, /*!< in: start key value of the
range, may also be 0 */
- key_range *max_key) /*!< in: range end key val, may
+ const key_range *max_key, /*!< in: range end key val, may
also be 0 */
+ page_range *pages)
{
KEY* key;
dict_index_t* index;
@@ -14028,8 +14029,12 @@ ha_innobase::records_in_range(
n_rows = rtr_estimate_n_rows_in_range(
index, range_start, mode1);
} else {
+ btr_pos_t tuple1(range_start, mode1, pages->first_page);
+ btr_pos_t tuple2(range_end, mode2, pages->last_page);
n_rows = btr_estimate_n_rows_in_range(
- index, range_start, mode1, range_end, mode2);
+ index, &tuple1, &tuple2);
+ pages->first_page= tuple1.page_id.raw();
+ pages->last_page= tuple2.page_id.raw();
}
} else {
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index 980c5b06ea5..d48c14da970 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -184,9 +184,10 @@ public:
int start_stmt(THD *thd, thr_lock_type lock_type) override;
ha_rows records_in_range(
- uint inx,
- key_range* min_key,
- key_range* max_key) override;
+ uint inx,
+ const key_range* min_key,
+ const key_range* max_key,
+ page_range* pages) override;
ha_rows estimate_rows_upper_bound() override;
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
index 0a45c3bb45f..9d5c9283e3b 100644
--- a/storage/innobase/include/btr0cur.h
+++ b/storage/innobase/include/btr0cur.h
@@ -555,20 +555,41 @@ btr_cur_pessimistic_delete(
@param[in,out] mtr mini-transaction */
void btr_cur_node_ptr_delete(btr_cur_t* parent, mtr_t* mtr)
MY_ATTRIBUTE((nonnull));
+/***********************************************************//**
+Parses a redo log record of updating a record in-place.
+@return end of log record or NULL */
+byte*
+btr_cur_parse_update_in_place(
+/*==========================*/
+ byte* ptr, /*!< in: buffer */
+ byte* end_ptr,/*!< in: buffer end */
+ page_t* page, /*!< in/out: page or NULL */
+ page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
+ dict_index_t* index); /*!< in: index corresponding to page */
+/** Arguments to btr_estimate_n_rows_in_range */
+struct btr_pos_t
+{
+ btr_pos_t(dtuple_t *arg_tuple,
+ page_cur_mode_t arg_mode,
+ page_id_t arg_page_id)
+ :tuple(arg_tuple), mode(arg_mode), page_id(arg_page_id)
+ {}
+
+ dtuple_t* tuple; /* Range start or end. May be NULL */
+ page_cur_mode_t mode; /* search mode for range */
+ page_id_t page_id; /* Out: Page where we found the tuple */
+};
+
/** Estimates the number of rows in a given index range.
@param[in] index index
-@param[in] tuple1 range start, may also be empty tuple
-@param[in] mode1 search mode for range start
-@param[in] tuple2 range end, may also be empty tuple
-@param[in] mode2 search mode for range end
+@param[in/out] range_start
+@param[in/out] range_ end
@return estimated number of rows */
ha_rows
btr_estimate_n_rows_in_range(
dict_index_t* index,
- const dtuple_t* tuple1,
- page_cur_mode_t mode1,
- const dtuple_t* tuple2,
- page_cur_mode_t mode2);
+ btr_pos_t* range_start,
+ btr_pos_t* range_end);
/*******************************************************************//**
Estimates the number of different key values in a given index, for
diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h
index 124a7f1854f..34146ccdfa5 100644
--- a/storage/innobase/include/buf0types.h
+++ b/storage/innobase/include/buf0types.h
@@ -141,6 +141,7 @@ public:
ut_ad(page_no <= 0xFFFFFFFFU);
}
+ page_id_t(ulonglong id) : m_id(id) {}
bool operator==(const page_id_t& rhs) const { return m_id == rhs.m_id; }
bool operator!=(const page_id_t& rhs) const { return m_id != rhs.m_id; }
@@ -169,6 +170,7 @@ public:
/** Set the FIL_NULL for the space and page_no */
void set_corrupt_id() { m_id= ~uint64_t{0}; }
+ ulonglong raw() { return m_id; }
private:
/** The page identifier */
uint64_t m_id;