Skip to content

Commit 0b87e9c

Browse files
Bug#33472935: dict_stats_analyze_index() may always discard optimal
index-based access paths Post-push fix: Making sure that during calculation of transient statistics no intentionally deinitilized stats are used. They are deinitilized in dict_stats_deinit. Change-Id: I902442553a2b9dbb6471fc868ba0fde34c92c31d
1 parent a9d58ef commit 0b87e9c

File tree

6 files changed

+79
-49
lines changed

6 files changed

+79
-49
lines changed

mysql-test/suite/innodb/r/innodb_autoextend_table_ddl.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,14 +416,14 @@ WHERE NAME LIKE '%tcopy_part%';
416416
NAME FILE_SIZE AUTOEXTEND_SIZE
417417
test/tcopy_part 8388608 8388608
418418
# Exchange a partition
419-
SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'tpart';
419+
SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'tpart' ORDER BY PARTITION_NAME;
420420
PARTITION_NAME TABLE_ROWS
421421
p0 1
422422
p1 0
423423
p2 0
424424
p3 3
425425
ALTER TABLE tpart EXCHANGE PARTITION p3 WITH TABLE tcopy_part;
426-
SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'tpart';
426+
SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'tpart' ORDER BY PARTITION_NAME;
427427
PARTITION_NAME TABLE_ROWS
428428
p0 0
429429
p1 0

mysql-test/suite/innodb/t/innodb_autoextend_table_ddl.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,9 @@ SELECT NAME, FILE_SIZE, AUTOEXTEND_SIZE FROM information_schema.innodb_tablespac
291291
WHERE NAME LIKE '%tcopy_part%';
292292

293293
--echo # Exchange a partition
294-
SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'tpart';
294+
SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'tpart' ORDER BY PARTITION_NAME;
295295
ALTER TABLE tpart EXCHANGE PARTITION p3 WITH TABLE tcopy_part;
296-
SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'tpart';
296+
SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'tpart' ORDER BY PARTITION_NAME;
297297

298298
SELECT COUNT(*) FROM tpart;
299299
SELECT COUNT(*) FROM tcopy_part;

storage/innobase/btr/btr0cur.cc

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -146,22 +146,22 @@ uint btr_cur_limit_optimistic_insert_debug = 0;
146146
can be released by page reorganize, then it is reorganized */
147147
#define BTR_CUR_PAGE_REORGANIZE_LIMIT (UNIV_PAGE_SIZE / 32)
148148

149+
#ifndef UNIV_HOTBACKUP
149150
/** Estimated table level stats from sampled value.
150151
@param value sampled stats
151-
@param index index being sampled
152+
@param n_leaf_pages number of leaf pages of the index
152153
@param sample number of sampled rows
153154
@param ext_size external stored data size
154155
@param not_empty table not empty
155156
@return estimated table wide stats from sampled value */
156-
constexpr uint64_t BTR_TABLE_STATS_FROM_SAMPLE(uint64_t value,
157-
dict_index_t *index,
158-
uint64_t sample, ulint ext_size,
159-
ulint not_empty) {
160-
return (value * index->stat_n_leaf_pages + sample - 1 + ext_size +
161-
not_empty) /
157+
static uint64_t BTR_TABLE_STATS_FROM_SAMPLE(uint64_t value,
158+
uint64_t n_leaf_pages,
159+
uint64_t sample, ulint ext_size,
160+
ulint not_empty) {
161+
return (value * n_leaf_pages + sample - 1 + ext_size + not_empty) /
162162
(sample + ext_size);
163163
}
164-
#ifndef UNIV_HOTBACKUP
164+
165165
/** Adds path information to the cursor for the current page, for which
166166
the binary search has been performed.
167167
@param[in, out] cursor Cursor positioned on a page.
@@ -5450,9 +5450,9 @@ bool btr_estimate_number_of_different_key_vals(
54505450

54515451
/* It makes no sense to test more pages than are contained
54525452
in the index, thus we lower the number if it is too high */
5453-
if (srv_stats_transient_sample_pages > index->stat_index_size) {
5454-
if (index->stat_index_size > 0) {
5455-
n_sample_pages = index->stat_index_size;
5453+
if (srv_stats_transient_sample_pages > index_stats->index_size) {
5454+
if (index_stats->index_size > 0) {
5455+
n_sample_pages = index_stats->index_size;
54565456
} else {
54575457
n_sample_pages = 1;
54585458
}
@@ -5562,15 +5562,18 @@ bool btr_estimate_number_of_different_key_vals(
55625562

55635563
/* If we saw k borders between different key values on
55645564
n_sample_pages leaf pages, we can estimate how many
5565-
there will be in index->stat_n_leaf_pages */
5565+
there will be in index_stats->n_leaf_pages (to be later stored in
5566+
index->stat_n_leaf_pages) */
55665567

55675568
/* We must take into account that our sample actually represents
55685569
also the pages used for external storage of fields (those pages are
5569-
included in index->stat_n_leaf_pages) */
5570+
included in index_stats->n_leaf_pages (to be later stored in
5571+
index->stat_n_leaf_pages) */
55705572

55715573
for (j = 0; j < n_cols; j++) {
55725574
index_stats->n_diff_key_vals[j] = BTR_TABLE_STATS_FROM_SAMPLE(
5573-
n_diff[j], index, n_sample_pages, total_external_size, not_empty_flag);
5575+
n_diff[j], index_stats->n_leaf_pages, n_sample_pages,
5576+
total_external_size, not_empty_flag);
55745577

55755578
/* If the tree is small, smaller than
55765579
10 * n_sample_pages + total_external_size, then
@@ -5596,9 +5599,9 @@ bool btr_estimate_number_of_different_key_vals(
55965599
and initialized to zero in dict_index_add_to_cache(),
55975600
along with n_diff_key_vals[] array */
55985601
if (n_not_null != nullptr) {
5599-
index_stats->n_non_null_key_vals[j] =
5600-
BTR_TABLE_STATS_FROM_SAMPLE(n_not_null[j], index, n_sample_pages,
5601-
total_external_size, not_empty_flag);
5602+
index_stats->n_non_null_key_vals[j] = BTR_TABLE_STATS_FROM_SAMPLE(
5603+
n_not_null[j], index_stats->n_leaf_pages, n_sample_pages,
5604+
total_external_size, not_empty_flag);
56025605
}
56035606
}
56045607

storage/innobase/dict/dict0mem.cc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,9 +918,44 @@ page_size_t dict_index_t::get_page_size() const {
918918
return (dict_table_page_size(table));
919919
}
920920

921+
#ifndef UNIV_HOTBACKUP
922+
923+
void dict_index_t::assert_stats_initialized() const {
924+
UNIV_MEM_ASSERT_RW_ABORT(stat_n_diff_key_vals,
925+
n_uniq * sizeof(stat_n_diff_key_vals[0]));
926+
927+
UNIV_MEM_ASSERT_RW_ABORT(stat_n_sample_sizes,
928+
n_uniq * sizeof(stat_n_sample_sizes[0]));
929+
930+
UNIV_MEM_ASSERT_RW_ABORT(stat_n_non_null_key_vals,
931+
n_uniq * sizeof(stat_n_non_null_key_vals[0]));
932+
933+
UNIV_MEM_ASSERT_RW_ABORT(&stat_index_size, sizeof(stat_index_size));
934+
935+
UNIV_MEM_ASSERT_RW_ABORT(&stat_n_leaf_pages, sizeof(stat_n_leaf_pages));
936+
}
937+
938+
#endif /* !UNIV_HOTBACKUP */
939+
921940
bool dict_table_t::has_pk() const {
922941
const dict_index_t *first = first_index();
923942
const size_t len = strlen(innobase_index_reserve_name);
924943
const int cmp = strncmp(innobase_index_reserve_name, first->name(), len);
925944
return cmp != 0;
926945
}
946+
947+
#ifndef UNIV_HOTBACKUP
948+
void dict_index_stats_t::assert_initialized() const {
949+
UNIV_MEM_ASSERT_RW_ABORT(n_diff_key_vals,
950+
n_uniq * sizeof(n_diff_key_vals[0]));
951+
952+
UNIV_MEM_ASSERT_RW_ABORT(n_sample_sizes, n_uniq * sizeof(n_sample_sizes[0]));
953+
954+
UNIV_MEM_ASSERT_RW_ABORT(n_non_null_key_vals,
955+
n_uniq * sizeof(n_non_null_key_vals[0]));
956+
957+
UNIV_MEM_ASSERT_RW_ABORT(&index_size, sizeof(index_size));
958+
959+
UNIV_MEM_ASSERT_RW_ABORT(&n_leaf_pages, sizeof(n_leaf_pages));
960+
}
961+
#endif /* !UNIV_HOTBACKUP */

storage/innobase/dict/dict0stats.cc

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -442,30 +442,6 @@ static void dict_stats_empty_table(dict_table_t *table) /*!< in/out: table */
442442
dict_table_stats_unlock(table, RW_X_LATCH);
443443
}
444444

445-
/** Check whether index's stats are initialized (assert if they are not). */
446-
template <typename T>
447-
static void dict_stats_assert_initialized_index(
448-
const T *index [[maybe_unused]]) /*!< in: index */
449-
{
450-
UNIV_MEM_ASSERT_RW_ABORT(
451-
index->stat_n_diff_key_vals,
452-
index->n_uniq * sizeof(index->stat_n_diff_key_vals[0]));
453-
454-
UNIV_MEM_ASSERT_RW_ABORT(
455-
index->stat_n_sample_sizes,
456-
index->n_uniq * sizeof(index->stat_n_sample_sizes[0]));
457-
458-
UNIV_MEM_ASSERT_RW_ABORT(
459-
index->stat_n_non_null_key_vals,
460-
index->n_uniq * sizeof(index->stat_n_non_null_key_vals[0]));
461-
462-
UNIV_MEM_ASSERT_RW_ABORT(&index->stat_index_size,
463-
sizeof(index->stat_index_size));
464-
465-
UNIV_MEM_ASSERT_RW_ABORT(&index->stat_n_leaf_pages,
466-
sizeof(index->stat_n_leaf_pages));
467-
}
468-
469445
/** Check whether table's stats are initialized (assert if they are not). */
470446
static void dict_stats_assert_initialized(
471447
const dict_table_t *table) /*!< in: table */
@@ -500,7 +476,7 @@ static void dict_stats_assert_initialized(
500476
for (const dict_index_t *index = table->first_index(); index != nullptr;
501477
index = index->next()) {
502478
if (!dict_stats_should_ignore_index(index)) {
503-
dict_stats_assert_initialized_index(index);
479+
index->assert_stats_initialized();
504480
}
505481
}
506482
}
@@ -726,8 +702,6 @@ static void dict_stats_copy_index(dict_index_t *dst_idx,
726702
const size_t n_copy_el = dst_idx->n_uniq;
727703
ut_a_eq(dst_idx->n_uniq, src_idx_stats->n_uniq);
728704

729-
dict_stats_assert_initialized_index(dst_idx);
730-
731705
memmove(dst_idx->stat_n_diff_key_vals, src_idx_stats->n_diff_key_vals,
732706
n_copy_el * sizeof(dst_idx->stat_n_diff_key_vals[0]));
733707

@@ -746,6 +720,8 @@ static void dict_stats_copy_index(dict_index_t *dst_idx,
746720
dst_idx->stat_index_size = src_idx_stats->index_size;
747721

748722
dst_idx->stat_n_leaf_pages = src_idx_stats->n_leaf_pages;
723+
724+
dst_idx->assert_stats_initialized();
749725
}
750726

751727
/** Calculates new estimates for index statistics. This function is
@@ -1878,7 +1854,6 @@ static bool dict_stats_analyze_index_low(uint64_t &n_sample_pages,
18781854
ulint size;
18791855

18801856
ut_ad(index_stats);
1881-
dict_stats_assert_initialized_index(index_stats);
18821857

18831858
DBUG_TRACE;
18841859

@@ -1987,6 +1962,8 @@ static bool dict_stats_analyze_index_low(uint64_t &n_sample_pages,
19871962

19881963
mtr_commit(&mtr);
19891964

1965+
index_stats->assert_initialized();
1966+
19901967
return true;
19911968
}
19921969

@@ -2208,6 +2185,10 @@ static bool dict_stats_analyze_index_low(uint64_t &n_sample_pages,
22082185

22092186
ut::delete_arr(n_diff_data);
22102187

2188+
if (succeeded) {
2189+
index_stats->assert_initialized();
2190+
}
2191+
22112192
return succeeded;
22122193
}
22132194

storage/innobase/include/dict0mem.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,11 @@ struct dict_index_t {
16311631
/** Check if it is a full-text search (FTS) index
16321632
@return true if this is a FTS index, false otherwise. */
16331633
bool is_fts_index() const { return type & DICT_FTS; }
1634+
1635+
#ifndef UNIV_HOTBACKUP
1636+
/** Check whether index's stats are initialized (assert if they are not).*/
1637+
void assert_stats_initialized() const;
1638+
#endif /* !UNIV_HOTBACKUP */
16341639
};
16351640

16361641
/** The status of online index creation */
@@ -3110,6 +3115,7 @@ inline bool dict_table_autoinc_own(const dict_table_t *table) {
31103115
}
31113116
#endif /* UNIV_DEBUG */
31123117

3118+
#ifndef UNIV_HOTBACKUP
31133119
/* Data structure storing index statistics. Used as temporary state during
31143120
statistics calculation. The final version of statistics for reading by
31153121
optimizer are stored in dict_index_t.*/
@@ -3127,8 +3133,13 @@ struct dict_index_stats_t {
31273133
unsigned type : DICT_IT_BITS;
31283134

31293135
unsigned n_uniq : 10;
3136+
3137+
/** Check whether index's stats are initialized (assert if they are not). */
3138+
void assert_initialized() const;
31303139
};
31313140

3141+
#endif /* !UNIV_HOTBACKUP */
3142+
31323143
#include "dict0mem.ic"
31333144

31343145
#endif /* dict0mem_h */

0 commit comments

Comments
 (0)