Commit f4fd6885 authored by Mattias Jonsson's avatar Mattias Jonsson

Bug#17565888: UP TO 75% INCREASE IN DBT3 QUERY (Q7) EXECUTION TIME

Regression from bug#14621190 due to disabled optimistic restoration
of cursor, which required full key lookup instead of verifying
if previously positioned btree cursor could be reused.

Fixed by enable optimistic restore and adjust cursor afterward.

rb#3324 approved by Marko.
parent 37502cfa
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -110,7 +110,7 @@ btr_pcur_store_position( ...@@ -110,7 +110,7 @@ btr_pcur_store_position(
page_t* page; page_t* page;
ulint offs; ulint offs;
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES); ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
block = btr_pcur_get_block(cursor); block = btr_pcur_get_block(cursor);
...@@ -235,21 +235,12 @@ btr_pcur_restore_position_func( ...@@ -235,21 +235,12 @@ btr_pcur_restore_position_func(
ut_ad(mtr); ut_ad(mtr);
ut_ad(mtr->state == MTR_ACTIVE); ut_ad(mtr->state == MTR_ACTIVE);
ut_ad(cursor->old_stored == BTR_PCUR_OLD_STORED);
ut_ad(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
|| cursor->pos_state == BTR_PCUR_IS_POSITIONED);
index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor)); index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
|| UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
&& cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
putc('\n', stderr);
if (cursor->trx_if_known) {
trx_print(stderr, cursor->trx_if_known, 0);
}
ut_error;
}
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
(cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
|| cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) { || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
...@@ -273,29 +264,26 @@ btr_pcur_restore_position_func( ...@@ -273,29 +264,26 @@ btr_pcur_restore_position_func(
if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF) if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
|| UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) { || UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
/* Try optimistic restoration if cursor is expected to be /* Try optimistic restoration. */
positioned on the same btr record as before (BTR_PCUR_ON). */
if (cursor->rel_pos == BTR_PCUR_ON if (buf_page_optimistic_get(latch_mode,
&& buf_page_optimistic_get(
latch_mode,
cursor->block_when_stored, cursor->block_when_stored,
cursor->modify_clock, cursor->modify_clock,
file, line, mtr)) { file, line, mtr)) {
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
buf_block_dbg_add_level( buf_block_dbg_add_level(
btr_pcur_get_block(cursor), btr_pcur_get_block(cursor),
dict_index_is_ibuf(index) dict_index_is_ibuf(index)
? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE); ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
{ if (cursor->rel_pos == BTR_PCUR_ON) {
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
const rec_t* rec; const rec_t* rec;
const ulint* offsets1; const ulint* offsets1;
const ulint* offsets2; const ulint* offsets2;
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
cursor->latch_mode = latch_mode; cursor->latch_mode = latch_mode;
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
rec = btr_pcur_get_rec(cursor); rec = btr_pcur_get_rec(cursor);
...@@ -314,6 +302,11 @@ btr_pcur_restore_position_func( ...@@ -314,6 +302,11 @@ btr_pcur_restore_position_func(
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
return(TRUE); return(TRUE);
} }
/* This is the same record as stored,
may need to be adjusted for BTR_PCUR_BEFORE/AFTER,
depending on search mode and direction. */
cursor->pos_state = BTR_PCUR_IS_POSITIONED_OPTIMISTIC;
return(FALSE);
} }
} }
...@@ -414,7 +407,7 @@ btr_pcur_move_to_next_page( ...@@ -414,7 +407,7 @@ btr_pcur_move_to_next_page(
buf_block_t* next_block; buf_block_t* next_block;
page_t* next_page; page_t* next_page;
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES); ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
ut_ad(btr_pcur_is_after_last_on_page(cursor)); ut_ad(btr_pcur_is_after_last_on_page(cursor));
...@@ -469,7 +462,6 @@ btr_pcur_move_backward_from_page( ...@@ -469,7 +462,6 @@ btr_pcur_move_backward_from_page(
ulint latch_mode; ulint latch_mode;
ulint latch_mode2; ulint latch_mode2;
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES); ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
ut_ad(btr_pcur_is_before_first_on_page(cursor)); ut_ad(btr_pcur_is_before_first_on_page(cursor));
ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr)); ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr));
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -447,6 +447,27 @@ btr_pcur_move_to_prev_on_page( ...@@ -447,6 +447,27 @@ btr_pcur_move_to_prev_on_page(
/*==========================*/ /*==========================*/
btr_pcur_t* cursor);/*!< in/out: persistent cursor */ btr_pcur_t* cursor);/*!< in/out: persistent cursor */
/** Position state of persistent B-tree cursor. */
enum pcur_pos_t {
/** The persistent cursor is not positioned. */
BTR_PCUR_NOT_POSITIONED = 0,
/** The persistent cursor was previously positioned.
TODO: currently, the state can be BTR_PCUR_IS_POSITIONED,
though it really should be BTR_PCUR_WAS_POSITIONED,
because we have no obligation to commit the cursor with
mtr; similarly latch_mode may be out of date. This can
lead to problems if btr_pcur is not used the right way;
all current code should be ok. */
BTR_PCUR_WAS_POSITIONED,
/** The persistent cursor is positioned by optimistic get to the same
record as it was positioned at. Not used for rel_pos == BTR_PCUR_ON.
It may need adjustment depending on previous/current search direction
and rel_pos. */
BTR_PCUR_IS_POSITIONED_OPTIMISTIC,
/** The persistent cursor is positioned by index search.
Or optimistic get for rel_pos == BTR_PCUR_ON. */
BTR_PCUR_IS_POSITIONED
};
/* The persistent B-tree cursor structure. This is used mainly for SQL /* The persistent B-tree cursor structure. This is used mainly for SQL
selects, updates, and deletes. */ selects, updates, and deletes. */
...@@ -480,10 +501,8 @@ struct btr_pcur_struct{ ...@@ -480,10 +501,8 @@ struct btr_pcur_struct{
ib_uint64_t modify_clock; /*!< the modify clock value of the ib_uint64_t modify_clock; /*!< the modify clock value of the
buffer block when the cursor position buffer block when the cursor position
was stored */ was stored */
ulint pos_state; /*!< see TODO note below! enum pcur_pos_t pos_state; /*!< btr_pcur_store_position() and
BTR_PCUR_IS_POSITIONED, btr_pcur_restore_position() state. */
BTR_PCUR_WAS_POSITIONED,
BTR_PCUR_NOT_POSITIONED */
ulint search_mode; /*!< PAGE_CUR_G, ... */ ulint search_mode; /*!< PAGE_CUR_G, ... */
trx_t* trx_if_known; /*!< the transaction, if we know it; trx_t* trx_if_known; /*!< the transaction, if we know it;
otherwise this field is not defined; otherwise this field is not defined;
...@@ -499,21 +518,6 @@ struct btr_pcur_struct{ ...@@ -499,21 +518,6 @@ struct btr_pcur_struct{
is not NULL */ is not NULL */
}; };
#define BTR_PCUR_IS_POSITIONED 1997660512 /* TODO: currently, the state
can be BTR_PCUR_IS_POSITIONED,
though it really should be
BTR_PCUR_WAS_POSITIONED,
because we have no obligation
to commit the cursor with
mtr; similarly latch_mode may
be out of date. This can
lead to problems if btr_pcur
is not used the right way;
all current code should be
ok. */
#define BTR_PCUR_WAS_POSITIONED 1187549791
#define BTR_PCUR_NOT_POSITIONED 1328997689
#define BTR_PCUR_OLD_STORED 908467085 #define BTR_PCUR_OLD_STORED 908467085
#define BTR_PCUR_OLD_NOT_STORED 122766467 #define BTR_PCUR_OLD_NOT_STORED 122766467
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -309,7 +309,8 @@ btr_pcur_move_to_next_user_rec( ...@@ -309,7 +309,8 @@ btr_pcur_move_to_next_user_rec(
function may release the page latch */ function may release the page latch */
mtr_t* mtr) /*!< in: mtr */ mtr_t* mtr) /*!< in: mtr */
{ {
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED_OPTIMISTIC
|| cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES); ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
loop: loop:
...@@ -379,7 +380,7 @@ btr_pcur_commit_specify_mtr( ...@@ -379,7 +380,7 @@ btr_pcur_commit_specify_mtr(
btr_pcur_t* pcur, /*!< in: persistent cursor */ btr_pcur_t* pcur, /*!< in: persistent cursor */
mtr_t* mtr) /*!< in: mtr to commit */ mtr_t* mtr) /*!< in: mtr to commit */
{ {
ut_a(pcur->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
pcur->latch_mode = BTR_NO_LATCHES; pcur->latch_mode = BTR_NO_LATCHES;
......
...@@ -3096,54 +3096,75 @@ sel_restore_position_for_mysql( ...@@ -3096,54 +3096,75 @@ sel_restore_position_for_mysql(
mtr temporarily! */ mtr temporarily! */
{ {
ibool success; ibool success;
ulint relative_position;
relative_position = pcur->rel_pos;
success = btr_pcur_restore_position(latch_mode, pcur, mtr); success = btr_pcur_restore_position(latch_mode, pcur, mtr);
*same_user_rec = success; *same_user_rec = success;
if (relative_position == BTR_PCUR_ON) { ut_ad(!success || pcur->rel_pos == BTR_PCUR_ON);
if (success) { #ifdef UNIV_DEBUG
return(FALSE); if (pcur->pos_state == BTR_PCUR_IS_POSITIONED_OPTIMISTIC) {
ut_ad(pcur->rel_pos == BTR_PCUR_BEFORE
|| pcur->rel_pos == BTR_PCUR_AFTER);
} else {
ut_ad(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
} }
#endif
if (moves_up) { /* The position may need be adjusted for rel_pos and moves_up. */
btr_pcur_move_to_next(pcur, mtr);
}
switch (pcur->rel_pos) {
case BTR_PCUR_ON:
if (!success && moves_up) {
next:
btr_pcur_move_to_next(pcur, mtr);
return(TRUE); return(TRUE);
} }
return(!success);
/* success can only be TRUE for BTR_PCUR_ON! */ case BTR_PCUR_AFTER_LAST_IN_TREE:
ut_ad(!success); case BTR_PCUR_BEFORE_FIRST_IN_TREE:
/* BTR_PCUR_BEFORE -> the position is now set to the record before
pcur->old_rec.
BTR_PCUR_AFTER-> positioned to record after pcur->old_rec. */
if (relative_position == BTR_PCUR_AFTER
|| relative_position == BTR_PCUR_AFTER_LAST_IN_TREE) {
if (moves_up) {
return(TRUE); return(TRUE);
} case BTR_PCUR_AFTER:
/* positioned to record after pcur->old_rec. */
if (btr_pcur_is_on_user_rec(pcur)) { pcur->pos_state = BTR_PCUR_IS_POSITIONED;
prev:
if (btr_pcur_is_on_user_rec(pcur) && !moves_up) {
btr_pcur_move_to_prev(pcur, mtr); btr_pcur_move_to_prev(pcur, mtr);
} }
return(TRUE); return(TRUE);
case BTR_PCUR_BEFORE:
/* For non optimistic restoration:
The position is now set to the record before pcur->old_rec.
For optimistic restoration:
The position also needs to take the previous search_mode into
consideration. */
switch (pcur->pos_state) {
case BTR_PCUR_IS_POSITIONED_OPTIMISTIC:
pcur->pos_state = BTR_PCUR_IS_POSITIONED;
if (pcur->search_mode == PAGE_CUR_GE) {
/* Positioned during Greater or Equal search
with BTR_PCUR_BEFORE. Optimistic restore to
the same record. If scanning for lower then
we must move to previous record.
This can happen with:
HANDLER READ idx a = (const);
HANDLER READ idx PREV; */
goto prev;
} }
return(TRUE);
ut_ad(relative_position == BTR_PCUR_BEFORE case BTR_PCUR_IS_POSITIONED:
|| relative_position == BTR_PCUR_BEFORE_FIRST_IN_TREE);
if (moves_up && btr_pcur_is_on_user_rec(pcur)) { if (moves_up && btr_pcur_is_on_user_rec(pcur)) {
btr_pcur_move_to_next(pcur, mtr); goto next;
} }
return(TRUE);
case BTR_PCUR_WAS_POSITIONED:
case BTR_PCUR_NOT_POSITIONED:
break;
}
}
ut_ad(0);
return(TRUE); return(TRUE);
} }
......
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