26 #ifndef UNIV_HOTBACKUP
117 #define TABLE_STATS_NAME "mysql/innodb_table_stats"
118 #define TABLE_STATS_NAME_PRINT "mysql.innodb_table_stats"
119 #define INDEX_STATS_NAME "mysql/innodb_index_stats"
120 #define INDEX_STATS_NAME_PRINT "mysql.innodb_index_stats"
122 #ifdef UNIV_STATS_DEBUG
123 #define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
125 #define DEBUG_PRINTF(fmt, ...)
129 #define N_SAMPLE_PAGES(index) \
130 ((index)->table->stats_sample_pages != 0 ? \
131 (index)->table->stats_sample_pages : \
132 srv_stats_persistent_sample_pages)
137 #define N_DIFF_REQUIRED(index) (N_SAMPLE_PAGES(index) * 10)
144 typedef std::vector<ib_uint64_t> boundaries_t;
158 return((index->
type & DICT_FTS)
170 dict_stats_persistent_storage_check(
172 bool caller_has_dict_sys_mutex)
177 {
"database_name", DATA_VARMYSQL,
180 {
"table_name", DATA_VARMYSQL,
183 {
"last_update", DATA_FIXBINARY,
187 DATA_NOT_NULL | DATA_UNSIGNED, 8},
189 {
"clustered_index_size", DATA_INT,
190 DATA_NOT_NULL | DATA_UNSIGNED, 8},
192 {
"sum_of_other_index_sizes", DATA_INT,
193 DATA_NOT_NULL | DATA_UNSIGNED, 8}
197 UT_ARR_SIZE(table_stats_columns),
205 {
"database_name", DATA_VARMYSQL,
208 {
"table_name", DATA_VARMYSQL,
211 {
"index_name", DATA_VARMYSQL,
214 {
"last_update", DATA_FIXBINARY,
217 {
"stat_name", DATA_VARMYSQL,
218 DATA_NOT_NULL, 64*3},
220 {
"stat_value", DATA_INT,
221 DATA_NOT_NULL | DATA_UNSIGNED, 8},
223 {
"sample_size", DATA_INT,
226 {
"stat_description", DATA_VARMYSQL,
227 DATA_NOT_NULL, 1024*3}
231 UT_ARR_SIZE(index_stats_columns),
240 if (!caller_has_dict_sys_mutex) {
249 if (ret == DB_SUCCESS) {
255 if (!caller_has_dict_sys_mutex) {
259 if (ret != DB_SUCCESS) {
261 fprintf(stderr,
" InnoDB: Error: %s\n", errstr);
285 #ifdef UNIV_SYNC_DEBUG
290 if (!dict_stats_persistent_storage_check(
true)) {
296 trx_start_if_not_started(trx);
300 if (err == DB_SUCCESS) {
303 trx->
op_info =
"rollback of internal trx on stats tables";
347 dict_stats_table_clone_create(
358 heap_size += strlen(table->
name) + 1;
360 for (index = dict_table_get_first_index(table);
362 index = dict_table_get_next_index(index)) {
368 ut_ad(!dict_index_is_univ(index));
373 heap_size += strlen(index->
name) + 1;
374 heap_size += n_uniq *
sizeof(index->
fields[0]);
375 for (ulint
i = 0;
i < n_uniq;
i++) {
380 heap_size += n_uniq *
sizeof(index->stat_n_non_null_key_vals[0]);
393 UNIV_MEM_ASSERT_RW_ABORT(&table->
id,
sizeof(table->
id));
398 UNIV_MEM_ASSERT_RW_ABORT(table->
name, strlen(table->
name) + 1);
405 for (index = dict_table_get_first_index(table);
407 index = dict_table_get_next_index(index)) {
413 ut_ad(!dict_index_is_univ(index));
419 UNIV_MEM_ASSERT_RW_ABORT(&index->
id,
sizeof(index->
id));
422 UNIV_MEM_ASSERT_RW_ABORT(index->
name, strlen(index->
name) + 1);
440 for (ulint
i = 0;
i < idx->
n_uniq;
i++) {
459 idx->
n_uniq *
sizeof(idx->stat_n_non_null_key_vals[0]));
460 ut_d(idx->magic_n = DICT_INDEX_MAGIC_N);
463 ut_d(t->magic_n = DICT_TABLE_MAGIC_N);
473 dict_stats_table_clone_free(
487 dict_stats_empty_index(
492 ut_ad(!dict_index_is_univ(index));
494 ulint n_uniq = index->
n_uniq;
496 for (ulint
i = 0;
i < n_uniq;
i++) {
499 index->stat_n_non_null_key_vals[
i] = 0;
511 dict_stats_empty_table(
528 for (index = dict_table_get_first_index(table);
530 index = dict_table_get_next_index(index)) {
532 if (index->
type & DICT_FTS) {
536 ut_ad(!dict_index_is_univ(index));
538 dict_stats_empty_index(index);
550 dict_stats_assert_initialized_index(
554 UNIV_MEM_ASSERT_RW_ABORT(
558 UNIV_MEM_ASSERT_RW_ABORT(
562 UNIV_MEM_ASSERT_RW_ABORT(
563 index->stat_n_non_null_key_vals,
564 index->
n_uniq *
sizeof(index->stat_n_non_null_key_vals[0]));
566 UNIV_MEM_ASSERT_RW_ABORT(
570 UNIV_MEM_ASSERT_RW_ABORT(
579 dict_stats_assert_initialized(
612 for (
dict_index_t* index = dict_table_get_first_index(table);
614 index = dict_table_get_next_index(index)) {
617 dict_stats_assert_initialized_index(index);
622 #define INDEX_EQ(i1, i2) \
625 && (i1)->id == (i2)->id \
626 && strcmp((i1)->name, (i2)->name) == 0)
648 for (dst_idx = dict_table_get_first_index(dst),
649 src_idx = dict_table_get_first_index(src);
651 dst_idx = dict_table_get_next_index(dst_idx),
653 && (src_idx = dict_table_get_next_index(src_idx)))) {
659 ut_ad(!dict_index_is_univ(dst_idx));
661 if (!INDEX_EQ(src_idx, dst_idx)) {
662 for (src_idx = dict_table_get_first_index(src);
664 src_idx = dict_table_get_next_index(src_idx)) {
666 if (INDEX_EQ(src_idx, dst_idx)) {
672 if (!INDEX_EQ(src_idx, dst_idx)) {
673 dict_stats_empty_index(dst_idx);
679 if (dst_idx->
n_uniq > src_idx->n_uniq) {
680 n_copy_el = src_idx->n_uniq;
684 dict_stats_empty_index(dst_idx);
686 n_copy_el = dst_idx->
n_uniq;
690 src_idx->stat_n_diff_key_vals,
694 src_idx->stat_n_sample_sizes,
697 memmove(dst_idx->stat_n_non_null_key_vals,
698 src_idx->stat_n_non_null_key_vals,
699 n_copy_el *
sizeof(dst_idx->stat_n_non_null_key_vals[0]));
732 dict_stats_snapshot_create(
740 dict_stats_assert_initialized(table);
744 t = dict_stats_table_clone_create(table);
746 dict_stats_copy(t, table);
765 dict_stats_snapshot_free(
769 dict_stats_table_clone_free(t);
779 dict_stats_update_transient_for_index(
794 if (size != ULINT_UNDEFINED) {
798 index, BTR_N_LEAF_PAGES, &mtr);
804 case ULINT_UNDEFINED:
805 dict_stats_empty_index(index);
822 dict_stats_empty_index(index);
839 ulint sum_of_index_sizes = 0;
844 index = dict_table_get_first_index(table);
848 dict_stats_empty_table(table);
850 }
else if (index == NULL) {
853 char buf[MAX_FULL_NAME_LEN];
855 fprintf(stderr,
" InnoDB: table %s has no indexes. "
856 "Cannot calculate statistics.\n",
858 dict_stats_empty_table(table);
862 for (; index != NULL; index = dict_table_get_next_index(index)) {
864 ut_ad(!dict_index_is_univ(index));
866 if (index->
type & DICT_FTS) {
870 dict_stats_empty_index(index);
876 dict_stats_update_transient_for_index(index);
881 index = dict_table_get_first_index(table);
926 dict_stats_analyze_index_level(
932 ib_uint64_t* total_recs,
933 ib_uint64_t* total_pages,
934 boundaries_t* n_diff_boundaries,
943 const rec_t* prev_rec;
944 bool prev_rec_is_copied;
945 byte* prev_rec_buf = NULL;
946 ulint prev_rec_buf_size = 0;
948 ulint* prev_rec_offsets;
951 DEBUG_PRINTF(
" %s(table=%s, index=%s, level=%lu)\n", __func__,
960 memset(n_diff, 0x0, n_uniq *
sizeof(n_diff[0]));
966 i = (REC_OFFS_HEADER_SIZE + 1 + 1) + index->
n_fields;
969 rec_offsets =
static_cast<ulint*
>(
971 prev_rec_offsets =
static_cast<ulint*
>(
977 if (n_diff_boundaries != NULL) {
978 for (i = 0; i < n_uniq; i++) {
979 n_diff_boundaries[
i].erase(
980 n_diff_boundaries[i].begin(),
981 n_diff_boundaries[i].end());
990 &pcur,
true, level, mtr);
993 page = btr_pcur_get_page(&pcur);
998 ut_ad(btr_pcur_get_rec(&pcur)
1002 ut_a(btr_page_get_level(page, mtr) == level);
1014 prev_rec_is_copied =
false;
1028 ulint matched_fields = 0;
1029 ulint matched_bytes = 0;
1030 bool rec_is_last_on_page;
1032 rec = btr_pcur_get_rec(&pcur);
1037 if (prev_rec != NULL
1040 ut_a(prev_rec_is_copied);
1043 rec_is_last_on_page =
1047 if (rec_is_last_on_page) {
1063 if (rec_is_last_on_page
1064 && !prev_rec_is_copied
1065 && prev_rec != NULL) {
1068 prev_rec_offsets = rec_get_offsets(
1069 prev_rec, index, prev_rec_offsets,
1075 &prev_rec_buf, &prev_rec_buf_size);
1077 prev_rec_is_copied =
true;
1083 rec_offsets = rec_get_offsets(
1084 rec, index, rec_offsets, n_uniq, &heap);
1088 if (prev_rec != NULL) {
1089 prev_rec_offsets = rec_get_offsets(
1090 prev_rec, index, prev_rec_offsets,
1102 for (i = matched_fields; i < n_uniq; i++) {
1104 if (n_diff_boundaries != NULL) {
1119 idx = *total_recs - 2;
1121 n_diff_boundaries[
i].push_back(idx);
1131 for (i = 0; i < n_uniq; i++) {
1136 if (rec_is_last_on_page) {
1148 &prev_rec_buf, &prev_rec_buf_size);
1149 prev_rec_is_copied =
true;
1158 prev_rec_is_copied =
false;
1166 if (*total_pages == 0) {
1169 ut_ad(*total_recs == 0);
1176 if (*total_recs > 0 && n_diff_boundaries != NULL) {
1181 for (i = 0; i < n_uniq; i++) {
1184 idx = *total_recs - 1;
1186 n_diff_boundaries[
i].push_back(idx);
1193 #ifdef UNIV_STATS_DEBUG
1194 for (i = 0; i < n_uniq; i++) {
1196 DEBUG_PRINTF(
" %s(): total recs: " UINT64PF
1197 ", total pages: " UINT64PF
1198 ", n_diff[%lu]: " UINT64PF
"\n",
1199 __func__, *total_recs,
1204 if (n_diff_boundaries != NULL) {
1207 DEBUG_PRINTF(
" %s(): boundaries[%lu]: ",
1210 for (j = 0; j < n_diff[
i]; j++) {
1213 idx = n_diff_boundaries[
i][j];
1215 DEBUG_PRINTF(UINT64PF
"=" UINT64PF
", ",
1230 if (prev_rec_buf != NULL) {
1239 enum page_scan_method_t {
1240 COUNT_ALL_NON_BORING_AND_SKIP_DEL_MARKED,
1244 QUIT_ON_FIRST_NON_BORING
1259 UNIV_INLINE __attribute__((nonnull))
1261 dict_stats_scan_page(
1263 const rec_t** out_rec,
1276 ib_uint64_t* n_diff)
1280 ulint* offsets_next_rec =
offsets2;
1282 const rec_t* next_rec;
1287 const rec_t* (*get_next)(
const rec_t*);
1289 if (scan_method == COUNT_ALL_NON_BORING_AND_SKIP_DEL_MARKED) {
1295 rec = get_next(page_get_infimum_rec(page));
1304 offsets_rec = rec_get_offsets(rec, index, offsets_rec,
1305 ULINT_UNDEFINED, &heap);
1307 next_rec = get_next(rec);
1313 ulint matched_fields = 0;
1314 ulint matched_bytes = 0;
1316 offsets_next_rec = rec_get_offsets(next_rec, index,
1324 offsets_rec, offsets_next_rec,
1325 index, FALSE, &matched_fields,
1328 if (matched_fields < n_prefix) {
1333 if (scan_method == QUIT_ON_FIRST_NON_BORING) {
1352 offsets_tmp = offsets_rec;
1353 offsets_rec = offsets_next_rec;
1354 offsets_next_rec = offsets_tmp;
1357 next_rec = get_next(next_rec);
1364 return(offsets_rec);
1374 dict_stats_analyze_index_below_cur(
1410 heap, size *
sizeof *offsets1));
1413 heap, size *
sizeof *offsets2));
1421 rec = btr_cur_get_rec(cur);
1423 offsets_rec = rec_get_offsets(rec, index, offsets1,
1424 ULINT_UNDEFINED, &heap);
1433 BUF_GET, __FILE__, __LINE__, mtr);
1435 page = buf_block_get_frame(block);
1437 if (btr_page_get_level(page, mtr) == 0) {
1444 offsets_rec = dict_stats_scan_page(
1445 &rec, offsets1, offsets2, index, page, n_prefix,
1446 QUIT_ON_FIRST_NON_BORING, &n_diff);
1449 ut_a(offsets_rec != NULL);
1475 ut_ad(btr_page_get_level(page, mtr) == 0);
1480 offsets_rec = dict_stats_scan_page(
1481 &rec, offsets1, offsets2, index, page, n_prefix,
1482 COUNT_ALL_NON_BORING_AND_SKIP_DEL_MARKED, &n_diff);
1485 DEBUG_PRINTF(
" %s(): n_diff below page_no=%lu: " UINT64PF
"\n",
1486 __func__, page_no, n_diff);
1502 dict_stats_analyze_index_for_n_prefix(
1506 ib_uint64_t total_recs_on_level,
1512 ib_uint64_t n_diff_for_this_prefix,
1517 boundaries_t* boundaries,
1530 ib_uint64_t rec_idx;
1531 ib_uint64_t last_idx_on_level;
1532 ib_uint64_t n_recs_to_dive_below;
1533 ib_uint64_t n_diff_sum_of_all_analyzed_pages;
1537 DEBUG_PRINTF(
" %s(table=%s, index=%s, level=%lu, n_prefix=%lu, "
1538 "n_diff_for_this_prefix=" UINT64PF
")\n",
1540 n_prefix, n_diff_for_this_prefix);
1549 ut_ad(total_recs_on_level > 0);
1550 ut_ad(n_diff_for_this_prefix > 0);
1553 ut_ad(N_SAMPLE_PAGES(index) > 0);
1560 &pcur,
true, level, mtr);
1563 page = btr_pcur_get_page(&pcur);
1568 ut_ad(btr_pcur_get_rec(&pcur)
1572 ut_a(btr_page_get_level(page, mtr) == level);
1583 last_idx_on_level = boundaries->at(n_diff_for_this_prefix - 1);
1587 n_diff_sum_of_all_analyzed_pages = 0;
1589 n_recs_to_dive_below =
ut_min(N_SAMPLE_PAGES(index),
1590 n_diff_for_this_prefix);
1592 for (i = 0; i < n_recs_to_dive_below; i++) {
1596 ib_uint64_t dive_below_idx;
1626 left = n_diff_for_this_prefix * i / n_recs_to_dive_below;
1627 right = n_diff_for_this_prefix * (i + 1)
1628 / n_recs_to_dive_below - 1;
1630 ut_a(left <= right);
1631 ut_a(right <= last_idx_on_level);
1638 dive_below_idx = boundaries->at(left + rnd);
1641 DEBUG_PRINTF(
" %s(): dive below record with index="
1642 UINT64PF
"\n", __func__, dive_below_idx);
1646 while (rec_idx < dive_below_idx
1657 if (rec_idx < dive_below_idx) {
1671 ut_a(rec_idx == dive_below_idx);
1673 ib_uint64_t n_diff_on_leaf_page;
1675 n_diff_on_leaf_page = dict_stats_analyze_index_below_cur(
1676 btr_pcur_get_btr_cur(&pcur), n_prefix, mtr);
1692 if (n_diff_on_leaf_page > 0) {
1693 n_diff_on_leaf_page--;
1696 n_diff_sum_of_all_analyzed_pages += n_diff_on_leaf_page;
1708 * n_diff_for_this_prefix
1709 / total_recs_on_level
1711 * n_diff_sum_of_all_analyzed_pages
1712 / n_recs_to_dive_below;
1716 DEBUG_PRINTF(
" %s(): n_diff=" UINT64PF
" for n_prefix=%lu "
1718 " * " UINT64PF
" / " UINT64PF
1719 " * " UINT64PF
" / " UINT64PF
")\n",
1723 n_diff_for_this_prefix, total_recs_on_level,
1724 n_diff_sum_of_all_analyzed_pages, n_recs_to_dive_below);
1735 dict_stats_analyze_index(
1741 bool level_is_analyzed;
1744 ib_uint64_t* n_diff_on_level;
1745 ib_uint64_t total_recs;
1746 ib_uint64_t total_pages;
1747 boundaries_t* n_diff_boundaries;
1750 DBUG_ENTER(
"dict_stats_analyze_index");
1752 DBUG_PRINT(
"info", (
"index: %s, online status: %d", index->
name,
1755 DEBUG_PRINTF(
" %s(index=%s)\n", __func__, index->
name);
1757 dict_stats_empty_index(index);
1765 if (size != ULINT_UNDEFINED) {
1774 case ULINT_UNDEFINED:
1775 dict_stats_assert_initialized_index(index);
1804 if (root_level == 0) {
1805 DEBUG_PRINTF(
" %s(): just one page, "
1806 "doing full scan\n", __func__);
1808 DEBUG_PRINTF(
" %s(): too many pages requested for "
1809 "sampling, doing full scan\n", __func__);
1815 dict_stats_analyze_index_level(index,
1823 for (ulint i = 0; i < n_uniq; i++) {
1829 dict_stats_assert_initialized_index(index);
1834 n_diff_on_level =
reinterpret_cast<ib_uint64_t*
>
1837 n_diff_boundaries =
new boundaries_t[n_uniq];
1854 level_is_analyzed =
false;
1856 for (n_prefix = n_uniq; n_prefix >= 1; n_prefix--) {
1858 DEBUG_PRINTF(
" %s(): searching level with >=%llu "
1859 "distinct records, n_prefix=%lu\n",
1860 __func__, N_DIFF_REQUIRED(index), n_prefix);
1883 if (level_is_analyzed
1884 && (n_diff_on_level[n_prefix - 1] >= N_DIFF_REQUIRED(index)
1892 if (level_is_analyzed && level > 1) {
1896 ut_ad(n_diff_on_level[n_prefix - 1]
1897 < N_DIFF_REQUIRED(index));
1900 level_is_analyzed =
false;
1912 ut_ad(!level_is_analyzed);
1922 if (total_recs > N_SAMPLE_PAGES(index)) {
1929 ut_a(level != root_level);
1934 level_is_analyzed =
true;
1939 dict_stats_analyze_index_level(index,
1947 level_is_analyzed =
true;
1949 if (n_diff_on_level[n_prefix - 1]
1950 >= N_DIFF_REQUIRED(index)
1959 level_is_analyzed =
false;
1963 DEBUG_PRINTF(
" %s(): found level %lu that has " UINT64PF
1964 " distinct records for n_prefix=%lu\n",
1965 __func__, level, n_diff_on_level[n_prefix - 1],
1974 ut_ad(level_is_analyzed);
1979 dict_stats_analyze_index_for_n_prefix(
1980 index, level, total_recs, n_prefix,
1981 n_diff_on_level[n_prefix - 1],
1982 &n_diff_boundaries[n_prefix - 1], &mtr);
1987 delete[] n_diff_boundaries;
1991 dict_stats_assert_initialized_index(index);
2002 dict_stats_update_persistent(
2008 DEBUG_PRINTF(
"%s(table=%s)\n", __func__, table->
name);
2014 index = dict_table_get_first_index(table);
2022 dict_stats_empty_table(table);
2027 ut_ad(!dict_index_is_univ(index));
2029 dict_stats_analyze_index(index);
2041 for (index = dict_table_get_next_index(index);
2043 index = dict_table_get_next_index(index)) {
2045 ut_ad(!dict_index_is_univ(index));
2047 if (index->
type & DICT_FTS) {
2051 dict_stats_empty_index(index);
2058 dict_stats_analyze_index(index);
2071 dict_stats_assert_initialized(table);
2078 #include "mysql_com.h"
2085 dict_stats_save_index_stat(
2089 const char* stat_name,
2090 ib_uint64_t stat_value,
2091 ib_uint64_t* sample_size,
2092 const char* stat_description)
2096 char db_utf8[MAX_DB_UTF8_LEN];
2097 char table_utf8[MAX_TABLE_UTF8_LEN];
2099 #ifdef UNIV_SYNC_DEBUG
2105 table_utf8,
sizeof(table_utf8));
2110 UNIV_MEM_ASSERT_RW_ABORT(index->
name, strlen(index->
name));
2112 UNIV_MEM_ASSERT_RW_ABORT(&last_update, 4);
2114 UNIV_MEM_ASSERT_RW_ABORT(stat_name, strlen(stat_name));
2116 UNIV_MEM_ASSERT_RW_ABORT(&stat_value, 8);
2118 if (sample_size != NULL) {
2119 UNIV_MEM_ASSERT_RW_ABORT(sample_size, 8);
2123 UNIV_SQL_NULL, DATA_FIXBINARY, 0);
2125 UNIV_MEM_ASSERT_RW_ABORT(stat_description, strlen(stat_description));
2129 ret = dict_stats_exec_sql(
2131 "PROCEDURE INDEX_STATS_SAVE_INSERT () IS\n"
2133 "INSERT INTO \"" INDEX_STATS_NAME
"\"\n"
2143 ":stat_description\n"
2147 if (ret == DB_DUPLICATE_KEY) {
2152 UNIV_MEM_ASSERT_RW_ABORT(index->
name, strlen(index->
name));
2154 UNIV_MEM_ASSERT_RW_ABORT(&last_update, 4);
2156 UNIV_MEM_ASSERT_RW_ABORT(stat_name, strlen(stat_name));
2158 UNIV_MEM_ASSERT_RW_ABORT(&stat_value, 8);
2160 if (sample_size != NULL) {
2161 UNIV_MEM_ASSERT_RW_ABORT(sample_size, 8);
2165 UNIV_SQL_NULL, DATA_FIXBINARY, 0);
2167 UNIV_MEM_ASSERT_RW_ABORT(stat_description, strlen(stat_description));
2171 ret = dict_stats_exec_sql(
2173 "PROCEDURE INDEX_STATS_SAVE_UPDATE () IS\n"
2175 "UPDATE \"" INDEX_STATS_NAME
"\" SET\n"
2176 "last_update = :last_update,\n"
2177 "stat_value = :stat_value,\n"
2178 "sample_size = :sample_size,\n"
2179 "stat_description = :stat_description\n"
2181 "database_name = :database_name AND\n"
2182 "table_name = :table_name AND\n"
2183 "index_name = :index_name AND\n"
2184 "stat_name = :stat_name;\n"
2188 if (ret != DB_SUCCESS) {
2189 char buf_table[MAX_FULL_NAME_LEN];
2190 char buf_index[MAX_FULL_NAME_LEN];
2193 " InnoDB: Cannot save index statistics for table "
2194 "%s, index %s, stat name \"%s\": %s\n",
2196 buf_table,
sizeof(buf_table)),
2198 buf_index,
sizeof(buf_index)),
2218 char db_utf8[MAX_DB_UTF8_LEN];
2219 char table_utf8[MAX_TABLE_UTF8_LEN];
2221 table = dict_stats_snapshot_create(table_orig);
2224 table_utf8,
sizeof(table_utf8));
2234 #define PREPARE_PINFO_FOR_TABLE_SAVE(p, t, n) \
2236 pars_info_add_str_literal((p), "database_name", db_utf8); \
2237 pars_info_add_str_literal((p), "table_name", table_utf8); \
2238 pars_info_add_int4_literal((p), "last_update", (n)); \
2239 pars_info_add_ull_literal((p), "n_rows", (t)->stat_n_rows); \
2240 pars_info_add_ull_literal((p), "clustered_index_size", \
2241 (t)->stat_clustered_index_size); \
2242 pars_info_add_ull_literal((p), "sum_of_other_index_sizes", \
2243 (t)->stat_sum_of_other_index_sizes); \
2248 PREPARE_PINFO_FOR_TABLE_SAVE(pinfo, table, now);
2250 ret = dict_stats_exec_sql(
2252 "PROCEDURE TABLE_STATS_SAVE_INSERT () IS\n"
2254 "INSERT INTO \"" TABLE_STATS_NAME
"\"\n"
2261 ":clustered_index_size,\n"
2262 ":sum_of_other_index_sizes\n"
2266 if (ret == DB_DUPLICATE_KEY) {
2269 PREPARE_PINFO_FOR_TABLE_SAVE(pinfo, table, now);
2271 ret = dict_stats_exec_sql(
2273 "PROCEDURE TABLE_STATS_SAVE_UPDATE () IS\n"
2275 "UPDATE \"" TABLE_STATS_NAME
"\" SET\n"
2276 "last_update = :last_update,\n"
2277 "n_rows = :n_rows,\n"
2278 "clustered_index_size = :clustered_index_size,\n"
2279 "sum_of_other_index_sizes = "
2280 " :sum_of_other_index_sizes\n"
2282 "database_name = :database_name AND\n"
2283 "table_name = :table_name;\n"
2287 if (ret != DB_SUCCESS) {
2288 char buf[MAX_FULL_NAME_LEN];
2291 " InnoDB: Cannot save table statistics for table "
2300 for (index = dict_table_get_first_index(table);
2302 index = dict_table_get_next_index(index)) {
2308 ut_ad(!dict_index_is_univ(index));
2310 ret = dict_stats_save_index_stat(index, now,
"size",
2315 if (ret != DB_SUCCESS) {
2319 ret = dict_stats_save_index_stat(index, now,
"n_leaf_pages",
2322 "Number of leaf pages "
2324 if (ret != DB_SUCCESS) {
2328 for (ulint i = 0; i < index->
n_uniq; i++) {
2331 char stat_description[1024];
2335 "n_diff_pfx%02lu", i + 1);
2339 sizeof(stat_description),
2341 for (j = 1; j <=
i; j++) {
2344 len = strlen(stat_description);
2347 sizeof(stat_description) - len,
2351 ret = dict_stats_save_index_stat(
2352 index, now, stat_name,
2357 if (ret != DB_SUCCESS) {
2367 dict_stats_snapshot_free(table);
2380 dict_stats_fetch_table_stats_step(
2392 for (cnode = static_cast<que_common_t*>(node->
select_list), i = 0;
2402 data =
static_cast<const byte*
>(dfield_get_data(dfield));
2456 struct index_fetch_t {
2458 bool stats_were_modified;
2481 dict_stats_fetch_index_stats_step(
2488 index_fetch_t* arg = (index_fetch_t*) arg_void;
2492 const char* stat_name = NULL;
2493 ulint stat_name_len = ULINT_UNDEFINED;
2494 ib_uint64_t stat_value = UINT64_UNDEFINED;
2495 ib_uint64_t sample_size = UINT64_UNDEFINED;
2500 for (cnode = static_cast<que_common_t*>(node->
select_list), i = 0;
2507 dtype_t* type = dfield_get_type(dfield);
2510 data =
static_cast<const byte*
>(dfield_get_data(dfield));
2520 for (index = dict_table_get_first_index(table);
2522 index = dict_table_get_next_index(index)) {
2524 if (strlen(index->
name) == len
2525 && memcmp(index->
name, data, len) == 0) {
2538 if (index == NULL) {
2549 ut_a(index != NULL);
2551 stat_name = (
const char*) data;
2552 stat_name_len = len;
2561 ut_a(index != NULL);
2562 ut_a(stat_name != NULL);
2563 ut_a(stat_name_len != ULINT_UNDEFINED);
2572 ut_a(len == 8 || len == UNIV_SQL_NULL);
2574 ut_a(index != NULL);
2575 ut_a(stat_name != NULL);
2576 ut_a(stat_name_len != ULINT_UNDEFINED);
2577 ut_a(stat_value != UINT64_UNDEFINED);
2579 if (len == UNIV_SQL_NULL) {
2604 ut_a(index != NULL);
2605 ut_a(stat_name != NULL);
2606 ut_a(stat_name_len != ULINT_UNDEFINED);
2607 ut_a(stat_value != UINT64_UNDEFINED);
2610 #define PFX "n_diff_pfx"
2613 if (stat_name_len == 4
2614 && strncasecmp(
"size", stat_name, stat_name_len) == 0) {
2616 arg->stats_were_modified =
true;
2617 }
else if (stat_name_len == 12
2618 && strncasecmp(
"n_leaf_pages", stat_name, stat_name_len)
2621 arg->stats_were_modified =
true;
2622 }
else if (stat_name_len > PFX_LEN
2623 && strncasecmp(PFX, stat_name, PFX_LEN) == 0) {
2625 const char* num_ptr;
2626 unsigned long n_pfx;
2629 num_ptr = stat_name + PFX_LEN;
2633 if (stat_name_len != PFX_LEN + 2
2634 || num_ptr[0] <
'0' || num_ptr[0] >
'9'
2635 || num_ptr[1] <
'0' || num_ptr[1] >
'9') {
2637 char db_utf8[MAX_DB_UTF8_LEN];
2638 char table_utf8[MAX_TABLE_UTF8_LEN];
2641 table_utf8,
sizeof(table_utf8));
2645 " InnoDB: Ignoring strange row from "
2647 "database_name = '%s' AND "
2648 "table_name = '%s' AND "
2649 "index_name = '%s' AND "
2650 "stat_name = '%.*s'; because stat_name "
2652 INDEX_STATS_NAME_PRINT,
2656 (
int) stat_name_len,
2664 n_pfx = (num_ptr[0] -
'0') * 10 + (num_ptr[1] -
'0');
2666 ulint n_uniq = index->
n_uniq;
2668 if (n_pfx == 0 || n_pfx > n_uniq) {
2670 char db_utf8[MAX_DB_UTF8_LEN];
2671 char table_utf8[MAX_TABLE_UTF8_LEN];
2674 table_utf8,
sizeof(table_utf8));
2678 " InnoDB: Ignoring strange row from "
2680 "database_name = '%s' AND "
2681 "table_name = '%s' AND "
2682 "index_name = '%s' AND "
2683 "stat_name = '%.*s'; because stat_name is "
2684 "out of range, the index has %lu unique "
2686 INDEX_STATS_NAME_PRINT,
2690 (
int) stat_name_len,
2699 if (sample_size != UINT64_UNDEFINED) {
2707 index->stat_n_non_null_key_vals[n_pfx - 1] = 0;
2709 arg->stats_were_modified =
true;
2724 dict_stats_fetch_from_ps(
2728 index_fetch_t index_fetch_arg;
2732 char db_utf8[MAX_DB_UTF8_LEN];
2733 char table_utf8[MAX_TABLE_UTF8_LEN];
2741 dict_stats_empty_table(table);
2751 trx_start_if_not_started(trx);
2754 table_utf8,
sizeof(table_utf8));
2763 "fetch_table_stats_step",
2764 dict_stats_fetch_table_stats_step,
2767 index_fetch_arg.table =
table;
2768 index_fetch_arg.stats_were_modified =
false;
2770 "fetch_index_stats_step",
2771 dict_stats_fetch_index_stats_step,
2775 "PROCEDURE FETCH_STATS () IS\n"
2777 "DECLARE FUNCTION fetch_table_stats_step;\n"
2778 "DECLARE FUNCTION fetch_index_stats_step;\n"
2779 "DECLARE CURSOR table_stats_cur IS\n"
2785 " clustered_index_size,\n"
2786 " sum_of_other_index_sizes\n"
2787 " FROM \"" TABLE_STATS_NAME
"\"\n"
2789 " database_name = :database_name AND\n"
2790 " table_name = :table_name;\n"
2791 "DECLARE CURSOR index_stats_cur IS\n"
2800 " FROM \"" INDEX_STATS_NAME
"\"\n"
2802 " database_name = :database_name AND\n"
2803 " table_name = :table_name;\n"
2807 "OPEN table_stats_cur;\n"
2808 "FETCH table_stats_cur INTO\n"
2809 " fetch_table_stats_step();\n"
2810 "IF (SQL % NOTFOUND) THEN\n"
2811 " CLOSE table_stats_cur;\n"
2814 "CLOSE table_stats_cur;\n"
2816 "OPEN index_stats_cur;\n"
2818 "WHILE found = 1 LOOP\n"
2819 " FETCH index_stats_cur INTO\n"
2820 " fetch_index_stats_step();\n"
2821 " IF (SQL % NOTFOUND) THEN\n"
2825 "CLOSE index_stats_cur;\n"
2835 if (!index_fetch_arg.stats_were_modified) {
2850 DBUG_ENTER(
"dict_stats_update_for_index");
2856 if (dict_stats_persistent_storage_check(
false)) {
2858 dict_stats_analyze_index(index);
2860 dict_stats_save(index->
table);
2867 char buf_table[MAX_FULL_NAME_LEN];
2868 char buf_index[MAX_FULL_NAME_LEN];
2871 " InnoDB: Recalculation of persistent statistics "
2872 "requested for table %s index %s but the required "
2873 "persistent statistics storage is not present or is "
2874 "corrupted. Using transient stats instead.\n",
2876 buf_table,
sizeof(buf_table)),
2878 buf_index,
sizeof(buf_index)));
2882 dict_stats_update_transient_for_index(index);
2897 dict_stats_upd_option_t stats_upd_option)
2903 char buf[MAX_FULL_NAME_LEN];
2910 " InnoDB: cannot calculate statistics for table %s "
2911 "because the .ibd file is missing. For help, please "
2912 "refer to " REFMAN
"innodb-troubleshooting.html\n",
2914 dict_stats_empty_table(table);
2920 dict_stats_empty_table(table);
2924 switch (stats_upd_option) {
2925 case DICT_STATS_RECALC_PERSISTENT:
2939 ut_a(strchr(table->
name,
'/') != NULL);
2945 if (dict_stats_persistent_storage_check(
false)) {
2949 err = dict_stats_update_persistent(table);
2951 if (err != DB_SUCCESS) {
2955 err = dict_stats_save(table);
2965 " InnoDB: Recalculation of persistent statistics "
2966 "requested for table %s but the required persistent "
2967 "statistics storage is not present or is corrupted. "
2968 "Using transient stats instead.\n",
2973 case DICT_STATS_RECALC_TRANSIENT:
2977 case DICT_STATS_EMPTY_TABLE:
2979 dict_stats_empty_table(table);
2986 if (dict_stats_persistent_storage_check(
false)) {
2988 return(dict_stats_save(table));
2996 case DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY:
3007 ut_a(strchr(table->
name,
'/') != NULL);
3009 if (!dict_stats_persistent_storage_check(
false)) {
3015 " InnoDB: Error: Fetch of persistent "
3016 "statistics requested for table %s but the "
3017 "required system tables %s and %s are not "
3018 "present or have unexpected structure. "
3019 "Using transient stats instead.\n",
3022 TABLE_STATS_NAME_PRINT,
3023 INDEX_STATS_NAME_PRINT);
3032 t = dict_stats_table_clone_create(table);
3034 dberr_t err = dict_stats_fetch_from_ps(t);
3048 dict_stats_empty_table(table);
3050 dict_stats_copy(table, t);
3052 dict_stats_assert_initialized(table);
3056 dict_stats_table_clone_free(t);
3061 dict_stats_table_clone_free(t);
3070 DICT_STATS_RECALC_PERSISTENT));
3076 " InnoDB: Trying to use table %s which has "
3077 "persistent statistics enabled, but auto "
3078 "recalculation turned off and the statistics "
3079 "do not exist in %s and %s. Please either run "
3080 "\"ANALYZE TABLE %s;\" manually or enable the "
3081 "auto recalculation with "
3082 "\"ALTER TABLE %s STATS_AUTO_RECALC=1;\". "
3083 "InnoDB will now use transient statistics for "
3085 buf, TABLE_STATS_NAME, INDEX_STATS_NAME, buf,
3091 dict_stats_table_clone_free(t);
3095 " InnoDB: Error fetching persistent statistics "
3096 "for table %s from %s and %s: %s. "
3097 "Using transient stats method instead.\n",
3136 const char* db_and_table,
3142 char db_utf8[MAX_DB_UTF8_LEN];
3143 char table_utf8[MAX_TABLE_UTF8_LEN];
3151 if (strchr(db_and_table,
'/') == NULL) {
3157 table_utf8,
sizeof(table_utf8));
3170 ret = dict_stats_exec_sql(
3172 "PROCEDURE DROP_INDEX_STATS () IS\n"
3174 "DELETE FROM \"" INDEX_STATS_NAME
"\" WHERE\n"
3175 "database_name = :database_name AND\n"
3176 "table_name = :table_name AND\n"
3177 "index_name = :index_name;\n"
3187 if (ret != DB_SUCCESS) {
3189 "Unable to delete statistics for index %s "
3190 "from %s%s: %s. They can be deleted later using "
3191 "DELETE FROM %s WHERE "
3192 "database_name = '%s' AND "
3193 "table_name = '%s' AND "
3194 "index_name = '%s';",
3196 INDEX_STATS_NAME_PRINT,
3198 ?
" because the rows are locked"
3201 INDEX_STATS_NAME_PRINT,
3207 fprintf(stderr,
" InnoDB: %s\n", errstr);
3223 const char* database_name,
3229 #ifdef UNIV_SYNC_DEBUG
3239 ret = dict_stats_exec_sql(
3241 "PROCEDURE DELETE_FROM_TABLE_STATS () IS\n"
3243 "DELETE FROM \"" TABLE_STATS_NAME
"\" WHERE\n"
3244 "database_name = :database_name AND\n"
3245 "table_name = :table_name;\n"
3261 const char* database_name,
3267 #ifdef UNIV_SYNC_DEBUG
3277 ret = dict_stats_exec_sql(
3279 "PROCEDURE DELETE_FROM_INDEX_STATS () IS\n"
3281 "DELETE FROM \"" INDEX_STATS_NAME
"\" WHERE\n"
3282 "database_name = :database_name AND\n"
3283 "table_name = :table_name;\n"
3298 const char* db_and_table,
3303 char db_utf8[MAX_DB_UTF8_LEN];
3304 char table_utf8[MAX_TABLE_UTF8_LEN];
3307 #ifdef UNIV_SYNC_DEBUG
3314 if (strchr(db_and_table,
'/') == NULL) {
3320 if (strcmp(db_and_table, TABLE_STATS_NAME) == 0
3321 || strcmp(db_and_table, INDEX_STATS_NAME) == 0) {
3327 table_utf8,
sizeof(table_utf8));
3331 if (ret == DB_SUCCESS) {
3339 if (ret != DB_SUCCESS) {
3342 "Unable to delete statistics for table %s.%s: %s. "
3343 "They can be deleted later using "
3345 "DELETE FROM %s WHERE "
3346 "database_name = '%s' AND "
3347 "table_name = '%s'; "
3349 "DELETE FROM %s WHERE "
3350 "database_name = '%s' AND "
3351 "table_name = '%s';",
3353 db_utf8, table_utf8,
3356 INDEX_STATS_NAME_PRINT,
3357 db_utf8, table_utf8,
3359 TABLE_STATS_NAME_PRINT,
3360 db_utf8, table_utf8);
3377 const char* old_dbname_utf8,
3378 const char* old_tablename_utf8,
3379 const char* new_dbname_utf8,
3380 const char* new_tablename_utf8)
3385 #ifdef UNIV_SYNC_DEBUG
3397 ret = dict_stats_exec_sql(
3399 "PROCEDURE RENAME_IN_TABLE_STATS () IS\n"
3401 "UPDATE \"" TABLE_STATS_NAME
"\" SET\n"
3402 "database_name = :new_dbname_utf8,\n"
3403 "table_name = :new_tablename_utf8\n"
3405 "database_name = :old_dbname_utf8 AND\n"
3406 "table_name = :old_tablename_utf8;\n"
3423 const char* old_dbname_utf8,
3424 const char* old_tablename_utf8,
3425 const char* new_dbname_utf8,
3426 const char* new_tablename_utf8)
3431 #ifdef UNIV_SYNC_DEBUG
3443 ret = dict_stats_exec_sql(
3445 "PROCEDURE RENAME_IN_INDEX_STATS () IS\n"
3447 "UPDATE \"" INDEX_STATS_NAME
"\" SET\n"
3448 "database_name = :new_dbname_utf8,\n"
3449 "table_name = :new_tablename_utf8\n"
3451 "database_name = :old_dbname_utf8 AND\n"
3452 "table_name = :old_tablename_utf8;\n"
3466 const char* old_name,
3467 const char* new_name,
3472 char old_db_utf8[MAX_DB_UTF8_LEN];
3473 char new_db_utf8[MAX_DB_UTF8_LEN];
3474 char old_table_utf8[MAX_TABLE_UTF8_LEN];
3475 char new_table_utf8[MAX_TABLE_UTF8_LEN];
3478 #ifdef UNIV_SYNC_DEBUG
3484 if (strcmp(old_name, TABLE_STATS_NAME) == 0
3485 || strcmp(old_name, INDEX_STATS_NAME) == 0
3486 || strcmp(new_name, TABLE_STATS_NAME) == 0
3487 || strcmp(new_name, INDEX_STATS_NAME) == 0) {
3492 dict_fs2utf8(old_name, old_db_utf8,
sizeof(old_db_utf8),
3493 old_table_utf8,
sizeof(old_table_utf8));
3495 dict_fs2utf8(new_name, new_db_utf8,
sizeof(new_db_utf8),
3496 new_table_utf8,
sizeof(new_table_utf8));
3501 ulint n_attempts = 0;
3506 old_db_utf8, old_table_utf8,
3507 new_db_utf8, new_table_utf8);
3509 if (ret == DB_DUPLICATE_KEY) {
3511 new_db_utf8, new_table_utf8);
3518 if (ret != DB_SUCCESS) {
3525 }
while ((ret == DB_DEADLOCK
3526 || ret == DB_DUPLICATE_KEY
3530 if (ret != DB_SUCCESS) {
3532 "Unable to rename statistics from "
3533 "%s.%s to %s.%s in %s: %s. "
3534 "They can be renamed later using "
3537 "database_name = '%s', "
3538 "table_name = '%s' "
3540 "database_name = '%s' AND "
3541 "table_name = '%s';",
3543 old_db_utf8, old_table_utf8,
3544 new_db_utf8, new_table_utf8,
3545 TABLE_STATS_NAME_PRINT,
3548 TABLE_STATS_NAME_PRINT,
3549 new_db_utf8, new_table_utf8,
3550 old_db_utf8, old_table_utf8);
3562 old_db_utf8, old_table_utf8,
3563 new_db_utf8, new_table_utf8);
3565 if (ret == DB_DUPLICATE_KEY) {
3567 new_db_utf8, new_table_utf8);
3574 if (ret != DB_SUCCESS) {
3581 }
while ((ret == DB_DEADLOCK
3582 || ret == DB_DUPLICATE_KEY
3589 if (ret != DB_SUCCESS) {
3591 "Unable to rename statistics from "
3592 "%s.%s to %s.%s in %s: %s. "
3593 "They can be renamed later using "
3596 "database_name = '%s', "
3597 "table_name = '%s' "
3599 "database_name = '%s' AND "
3600 "table_name = '%s';",
3602 old_db_utf8, old_table_utf8,
3603 new_db_utf8, new_table_utf8,
3604 INDEX_STATS_NAME_PRINT,
3607 INDEX_STATS_NAME_PRINT,
3608 new_db_utf8, new_table_utf8,
3609 old_db_utf8, old_table_utf8);
3616 #ifdef UNIV_COMPILE_TEST_FUNCS
3624 test_dict_table_schema_check()
3639 {
"c01", DATA_VARCHAR, 0, 123},
3640 {
"c02", DATA_INT, 0, 4},
3641 {
"c03", DATA_INT, DATA_NOT_NULL, 4},
3642 {
"c04", DATA_INT, DATA_UNSIGNED, 4},
3643 {
"c05", DATA_INT, 0, 8},
3644 {
"c06", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
3645 {
"c07", DATA_INT, 0, 4},
3646 {
"c_extra", DATA_INT, 0, 4}
3655 ut_snprintf(errstr,
sizeof(errstr),
"Table not found");
3666 printf(
"OK: test.tcheck ok\n");
3668 printf(
"ERROR: %s\n", errstr);
3669 printf(
"ERROR: test.tcheck not present or corrupted\n");
3670 goto test_dict_table_schema_check_end;
3674 schema.columns[1].len = 8;
3677 printf(
"OK: test.tcheck.c02 has different length and is "
3678 "reported as corrupted\n");
3680 printf(
"OK: test.tcheck.c02 has different length but is "
3681 "reported as ok\n");
3682 goto test_dict_table_schema_check_end;
3684 schema.columns[1].len = 4;
3688 schema.columns[1].prtype_mask |= DATA_NOT_NULL;
3691 printf(
"OK: test.tcheck.c02 does not have NOT NULL while "
3692 "it should and is reported as corrupted\n");
3694 printf(
"ERROR: test.tcheck.c02 does not have NOT NULL while "
3695 "it should and is not reported as corrupted\n");
3696 goto test_dict_table_schema_check_end;
3698 schema.columns[1].prtype_mask &= ~DATA_NOT_NULL;
3704 printf(
"ERROR: test.tcheck has more columns but is not "
3705 "reported as corrupted\n");
3706 goto test_dict_table_schema_check_end;
3708 printf(
"OK: test.tcheck has more columns and is "
3709 "reported as corrupted\n");
3716 printf(
"OK: test.tcheck has missing columns and is "
3717 "reported as corrupted\n");
3719 printf(
"ERROR: test.tcheck has missing columns but is "
3720 "reported as ok\n");
3721 goto test_dict_table_schema_check_end;
3725 schema.table_name =
"test/tcheck_nonexistent";
3728 printf(
"OK: test.tcheck_nonexistent is not present\n");
3730 printf(
"ERROR: test.tcheck_nonexistent is present!?\n");
3731 goto test_dict_table_schema_check_end;
3734 test_dict_table_schema_check_end:
3741 #define TEST_DATABASE_NAME "foobardb"
3742 #define TEST_TABLE_NAME "test_dict_stats"
3744 #define TEST_N_ROWS 111
3745 #define TEST_CLUSTERED_INDEX_SIZE 222
3746 #define TEST_SUM_OF_OTHER_INDEX_SIZES 333
3748 #define TEST_IDX1_NAME "tidx1"
3749 #define TEST_IDX1_COL1_NAME "tidx1_col1"
3750 #define TEST_IDX1_INDEX_SIZE 123
3751 #define TEST_IDX1_N_LEAF_PAGES 234
3752 #define TEST_IDX1_N_DIFF1 50
3753 #define TEST_IDX1_N_DIFF1_SAMPLE_SIZE 500
3755 #define TEST_IDX2_NAME "tidx2"
3756 #define TEST_IDX2_COL1_NAME "tidx2_col1"
3757 #define TEST_IDX2_COL2_NAME "tidx2_col2"
3758 #define TEST_IDX2_COL3_NAME "tidx2_col3"
3759 #define TEST_IDX2_COL4_NAME "tidx2_col4"
3760 #define TEST_IDX2_INDEX_SIZE 321
3761 #define TEST_IDX2_N_LEAF_PAGES 432
3762 #define TEST_IDX2_N_DIFF1 60
3763 #define TEST_IDX2_N_DIFF1_SAMPLE_SIZE 600
3764 #define TEST_IDX2_N_DIFF2 61
3765 #define TEST_IDX2_N_DIFF2_SAMPLE_SIZE 610
3766 #define TEST_IDX2_N_DIFF3 62
3767 #define TEST_IDX2_N_DIFF3_SAMPLE_SIZE 620
3768 #define TEST_IDX2_N_DIFF4 63
3769 #define TEST_IDX2_N_DIFF4_SAMPLE_SIZE 630
3774 test_dict_stats_save()
3779 ib_uint64_t index1_stat_n_diff_key_vals[1];
3780 ib_uint64_t index1_stat_n_sample_sizes[1];
3783 ib_uint64_t index2_stat_n_diff_key_vals[4];
3784 ib_uint64_t index2_stat_n_sample_sizes[4];
3788 table.
name = (
char*) (TEST_DATABASE_NAME
"/" TEST_TABLE_NAME);
3795 ut_d(table.magic_n = DICT_TABLE_MAGIC_N);
3796 ut_d(index1.magic_n = DICT_INDEX_MAGIC_N);
3798 index1.
name = TEST_IDX1_NAME;
3802 index1.
fields = index1_fields;
3807 index1_fields[0].
name = TEST_IDX1_COL1_NAME;
3808 index1_stat_n_diff_key_vals[0] = TEST_IDX1_N_DIFF1;
3809 index1_stat_n_sample_sizes[0] = TEST_IDX1_N_DIFF1_SAMPLE_SIZE;
3811 ut_d(index2.magic_n = DICT_INDEX_MAGIC_N);
3812 index2.
name = TEST_IDX2_NAME;
3816 index2.
fields = index2_fields;
3821 index2_fields[0].
name = TEST_IDX2_COL1_NAME;
3822 index2_fields[1].
name = TEST_IDX2_COL2_NAME;
3823 index2_fields[2].
name = TEST_IDX2_COL3_NAME;
3824 index2_fields[3].
name = TEST_IDX2_COL4_NAME;
3825 index2_stat_n_diff_key_vals[0] = TEST_IDX2_N_DIFF1;
3826 index2_stat_n_diff_key_vals[1] = TEST_IDX2_N_DIFF2;
3827 index2_stat_n_diff_key_vals[2] = TEST_IDX2_N_DIFF3;
3828 index2_stat_n_diff_key_vals[3] = TEST_IDX2_N_DIFF4;
3829 index2_stat_n_sample_sizes[0] = TEST_IDX2_N_DIFF1_SAMPLE_SIZE;
3830 index2_stat_n_sample_sizes[1] = TEST_IDX2_N_DIFF2_SAMPLE_SIZE;
3831 index2_stat_n_sample_sizes[2] = TEST_IDX2_N_DIFF3_SAMPLE_SIZE;
3832 index2_stat_n_sample_sizes[3] = TEST_IDX2_N_DIFF4_SAMPLE_SIZE;
3834 ret = dict_stats_save(&table);
3836 ut_a(ret == DB_SUCCESS);
3838 printf(
"\nOK: stats saved successfully, now go ahead and read "
3839 "what's inside %s and %s:\n\n",
3840 TABLE_STATS_NAME_PRINT,
3841 INDEX_STATS_NAME_PRINT);
3843 printf(
"SELECT COUNT(*) = 1 AS table_stats_saved_successfully\n"
3846 "database_name = '%s' AND\n"
3847 "table_name = '%s' AND\n"
3849 "clustered_index_size = %d AND\n"
3850 "sum_of_other_index_sizes = %d;\n"
3852 TABLE_STATS_NAME_PRINT,
3856 TEST_CLUSTERED_INDEX_SIZE,
3857 TEST_SUM_OF_OTHER_INDEX_SIZES);
3859 printf(
"SELECT COUNT(*) = 3 AS tidx1_stats_saved_successfully\n"
3862 "database_name = '%s' AND\n"
3863 "table_name = '%s' AND\n"
3864 "index_name = '%s' AND\n"
3866 " (stat_name = 'size' AND stat_value = %d AND"
3867 " sample_size IS NULL) OR\n"
3868 " (stat_name = 'n_leaf_pages' AND stat_value = %d AND"
3869 " sample_size IS NULL) OR\n"
3870 " (stat_name = 'n_diff_pfx01' AND stat_value = %d AND"
3871 " sample_size = '%d' AND stat_description = '%s')\n"
3874 INDEX_STATS_NAME_PRINT,
3878 TEST_IDX1_INDEX_SIZE,
3879 TEST_IDX1_N_LEAF_PAGES,
3881 TEST_IDX1_N_DIFF1_SAMPLE_SIZE,
3882 TEST_IDX1_COL1_NAME);
3884 printf(
"SELECT COUNT(*) = 6 AS tidx2_stats_saved_successfully\n"
3887 "database_name = '%s' AND\n"
3888 "table_name = '%s' AND\n"
3889 "index_name = '%s' AND\n"
3891 " (stat_name = 'size' AND stat_value = %d AND"
3892 " sample_size IS NULL) OR\n"
3893 " (stat_name = 'n_leaf_pages' AND stat_value = %d AND"
3894 " sample_size IS NULL) OR\n"
3895 " (stat_name = 'n_diff_pfx01' AND stat_value = %d AND"
3896 " sample_size = '%d' AND stat_description = '%s') OR\n"
3897 " (stat_name = 'n_diff_pfx02' AND stat_value = %d AND"
3898 " sample_size = '%d' AND stat_description = '%s,%s') OR\n"
3899 " (stat_name = 'n_diff_pfx03' AND stat_value = %d AND"
3900 " sample_size = '%d' AND stat_description = '%s,%s,%s') OR\n"
3901 " (stat_name = 'n_diff_pfx04' AND stat_value = %d AND"
3902 " sample_size = '%d' AND stat_description = '%s,%s,%s,%s')\n"
3905 INDEX_STATS_NAME_PRINT,
3909 TEST_IDX2_INDEX_SIZE,
3910 TEST_IDX2_N_LEAF_PAGES,
3912 TEST_IDX2_N_DIFF1_SAMPLE_SIZE, TEST_IDX2_COL1_NAME,
3914 TEST_IDX2_N_DIFF2_SAMPLE_SIZE,
3915 TEST_IDX2_COL1_NAME, TEST_IDX2_COL2_NAME,
3917 TEST_IDX2_N_DIFF3_SAMPLE_SIZE,
3918 TEST_IDX2_COL1_NAME, TEST_IDX2_COL2_NAME, TEST_IDX2_COL3_NAME,
3920 TEST_IDX2_N_DIFF4_SAMPLE_SIZE,
3921 TEST_IDX2_COL1_NAME, TEST_IDX2_COL2_NAME, TEST_IDX2_COL3_NAME,
3922 TEST_IDX2_COL4_NAME);
3928 test_dict_stats_fetch_from_ps()
3932 ib_uint64_t index1_stat_n_diff_key_vals[1];
3933 ib_uint64_t index1_stat_n_sample_sizes[1];
3935 ib_uint64_t index2_stat_n_diff_key_vals[4];
3936 ib_uint64_t index2_stat_n_sample_sizes[4];
3940 table.
name = (
char*) (TEST_DATABASE_NAME
"/" TEST_TABLE_NAME);
3944 ut_d(table.magic_n = DICT_TABLE_MAGIC_N);
3946 index1.
name = TEST_IDX1_NAME;
3947 ut_d(index1.magic_n = DICT_INDEX_MAGIC_N);
3953 index2.
name = TEST_IDX2_NAME;
3954 ut_d(index2.magic_n = DICT_INDEX_MAGIC_N);
3960 ret = dict_stats_fetch_from_ps(&table);
3962 ut_a(ret == DB_SUCCESS);
3967 == TEST_SUM_OF_OTHER_INDEX_SIZES);
3971 ut_a(index1_stat_n_diff_key_vals[0] == TEST_IDX1_N_DIFF1);
3972 ut_a(index1_stat_n_sample_sizes[0] == TEST_IDX1_N_DIFF1_SAMPLE_SIZE);
3976 ut_a(index2_stat_n_diff_key_vals[0] == TEST_IDX2_N_DIFF1);
3977 ut_a(index2_stat_n_sample_sizes[0] == TEST_IDX2_N_DIFF1_SAMPLE_SIZE);
3978 ut_a(index2_stat_n_diff_key_vals[1] == TEST_IDX2_N_DIFF2);
3979 ut_a(index2_stat_n_sample_sizes[1] == TEST_IDX2_N_DIFF2_SAMPLE_SIZE);
3980 ut_a(index2_stat_n_diff_key_vals[2] == TEST_IDX2_N_DIFF3);
3981 ut_a(index2_stat_n_sample_sizes[2] == TEST_IDX2_N_DIFF3_SAMPLE_SIZE);
3982 ut_a(index2_stat_n_diff_key_vals[3] == TEST_IDX2_N_DIFF4);
3983 ut_a(index2_stat_n_sample_sizes[3] == TEST_IDX2_N_DIFF4_SAMPLE_SIZE);
3985 printf(
"OK: fetch successful\n");
3991 test_dict_stats_all()
3993 test_dict_table_schema_check();
3995 test_dict_stats_save();
3997 test_dict_stats_fetch_from_ps();