1 # name : innodb_stats.patch
2 # introduced : 11 or before
3 # maintainer : Yasufumi
6 # Any small change to this file in the main branch
7 # should be done or reviewed by the maintainer!
8 diff -ruN a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.c
9 --- a/storage/innobase/dict/dict0boot.c 2010-12-03 15:48:03.034036843 +0900
10 +++ b/storage/innobase/dict/dict0boot.c 2010-12-03 17:19:24.835112632 +0900
12 /* Get the dictionary header */
13 dict_hdr = dict_hdr_get(&mtr);
15 + if (mach_read_from_8(dict_hdr + DICT_HDR_XTRADB_MARK)
16 + != DICT_HDR_XTRADB_FLAG) {
17 + /* not extended yet by XtraDB, need to be extended */
20 + root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
21 + DICT_HDR_SPACE, 0, DICT_STATS_ID,
22 + dict_ind_redundant, &mtr);
23 + if (root_page_no == FIL_NULL) {
24 + fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n");
25 + srv_use_sys_stats_table = FALSE;
27 + mlog_write_ulint(dict_hdr + DICT_HDR_STATS, root_page_no,
29 + mlog_write_ull(dict_hdr + DICT_HDR_XTRADB_MARK,
30 + DICT_HDR_XTRADB_FLAG, &mtr);
35 + dict_hdr = dict_hdr_get(&mtr);
38 /* Because we only write new row ids to disk-based data structure
39 (dictionary header) when it is divisible by
40 DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover
42 table->id = DICT_FIELDS_ID;
43 dict_table_add_to_cache(table, heap);
44 dict_sys->sys_fields = table;
45 - mem_heap_free(heap);
46 + mem_heap_empty(heap);
48 index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
52 ut_a(error == DB_SUCCESS);
54 + /*-------------------------*/
55 + table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 3, 0);
56 + table->n_mysql_handles_opened = 1; /* for pin */
58 + dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
59 + dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
60 + dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
62 + /* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
63 +#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
64 +#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
67 + table->id = DICT_STATS_ID;
68 + dict_table_add_to_cache(table, heap);
69 + dict_sys->sys_stats = table;
70 + mem_heap_empty(heap);
72 + index = dict_mem_index_create("SYS_STATS", "CLUST_IND",
74 + DICT_UNIQUE | DICT_CLUSTERED, 2);
76 + dict_mem_index_add_field(index, "INDEX_ID", 0);
77 + dict_mem_index_add_field(index, "KEY_COLS", 0);
79 + index->id = DICT_STATS_ID;
80 + error = dict_index_add_to_cache(table, index,
81 + mtr_read_ulint(dict_hdr
85 + ut_a(error == DB_SUCCESS);
87 + mem_heap_free(heap);
90 /*-------------------------*/
93 dict_load_sys_table(dict_sys->sys_columns);
94 dict_load_sys_table(dict_sys->sys_indexes);
95 dict_load_sys_table(dict_sys->sys_fields);
96 + dict_load_sys_table(dict_sys->sys_stats);
98 mutex_exit(&(dict_sys->mutex));
100 diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c
101 --- a/storage/innobase/dict/dict0crea.c 2010-12-03 15:48:03.036081059 +0900
102 +++ b/storage/innobase/dict/dict0crea.c 2010-12-03 17:19:24.836964976 +0900
106 /*****************************************************************//**
107 +Based on an index object, this function builds the entry to be inserted
108 +in the SYS_STATS system table.
109 +@return the tuple which should be inserted */
112 +dict_create_sys_stats_tuple(
113 +/*========================*/
114 + const dict_index_t* index,
118 + dict_table_t* sys_stats;
126 + sys_stats = dict_sys->sys_stats;
128 + entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);
130 + dict_table_copy_types(entry, sys_stats);
132 + /* 0: INDEX_ID -----------------------*/
133 + dfield = dtuple_get_nth_field(entry, 0/*INDEX_ID*/);
134 + ptr = mem_heap_alloc(heap, 8);
135 + mach_write_to_8(ptr, index->id);
136 + dfield_set_data(dfield, ptr, 8);
137 + /* 1: KEY_COLS -----------------------*/
138 + dfield = dtuple_get_nth_field(entry, 1/*KEY_COLS*/);
139 + ptr = mem_heap_alloc(heap, 4);
140 + mach_write_to_4(ptr, i);
141 + dfield_set_data(dfield, ptr, 4);
142 + /* 4: DIFF_VALS ----------------------*/
143 + dfield = dtuple_get_nth_field(entry, 2/*DIFF_VALS*/);
144 + ptr = mem_heap_alloc(heap, 8);
145 + mach_write_to_8(ptr, 0); /* initial value is 0 */
146 + dfield_set_data(dfield, ptr, 8);
151 +/*****************************************************************//**
152 Creates the tuple with which the index entry is searched for writing the index
153 tree root page number, if such a tree is created.
154 @return the tuple for search */
158 /***************************************************************//**
159 +Builds a row for storing stats to insert.
160 +@return DB_SUCCESS */
163 +dict_build_stats_def_step(
164 +/*======================*/
167 + dict_index_t* index;
170 + index = node->index;
172 + row = dict_create_sys_stats_tuple(index, node->stats_no, node->heap);
174 + ins_node_set_new_row(node->stats_def, row);
176 + return(DB_SUCCESS);
179 +/***************************************************************//**
180 Creates an index tree for the index if it is not a member of a cluster.
181 @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
183 @@ -937,6 +1003,49 @@
184 dict_sys->sys_fields, heap);
185 node->field_def->common.parent = node;
187 + if (srv_use_sys_stats_table) {
188 + node->stats_def = ins_node_create(INS_DIRECT,
189 + dict_sys->sys_stats, heap);
190 + node->stats_def->common.parent = node;
192 + node->stats_def = NULL;
195 + node->commit_node = commit_node_create(heap);
196 + node->commit_node->common.parent = node;
201 +/*********************************************************************//**
205 +ind_insert_stats_graph_create(
206 +/*==========================*/
207 + dict_index_t* index,
212 + node = mem_heap_alloc(heap, sizeof(ind_node_t));
214 + node->common.type = QUE_NODE_INSERT_STATS;
216 + node->index = index;
218 + node->state = INDEX_BUILD_STATS_COLS;
219 + node->page_no = FIL_NULL;
220 + node->heap = mem_heap_create(256);
222 + node->ind_def = NULL;
223 + node->field_def = NULL;
225 + node->stats_def = ins_node_create(INS_DIRECT,
226 + dict_sys->sys_stats, heap);
227 + node->stats_def->common.parent = node;
228 + node->stats_no = 0;
230 node->commit_node = commit_node_create(heap);
231 node->commit_node->common.parent = node;
233 @@ -1087,6 +1196,7 @@
235 node->state = INDEX_BUILD_FIELD_DEF;
237 + node->stats_no = 0;
239 thr->run_node = node->ind_def;
241 @@ -1132,7 +1242,31 @@
245 - node->state = INDEX_CREATE_INDEX_TREE;
246 + if (srv_use_sys_stats_table
247 + && !((node->table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)) {
248 + node->state = INDEX_BUILD_STATS_COLS;
250 + node->state = INDEX_CREATE_INDEX_TREE;
253 + if (node->state == INDEX_BUILD_STATS_COLS) {
254 + if (node->stats_no <= dict_index_get_n_unique(node->index)) {
256 + err = dict_build_stats_def_step(node);
258 + if (err != DB_SUCCESS) {
260 + goto function_exit;
265 + thr->run_node = node->stats_def;
269 + node->state = INDEX_CREATE_INDEX_TREE;
273 if (node->state == INDEX_CREATE_INDEX_TREE) {
274 @@ -1178,6 +1312,66 @@
278 + thr->run_node = que_node_get_parent(node);
283 +/****************************************************************//**
287 +dict_insert_stats_step(
288 +/*===================*/
289 + que_thr_t* thr) /*!< in: query thread */
292 + ulint err = DB_ERROR;
297 + trx = thr_get_trx(thr);
299 + node = thr->run_node;
301 + if (thr->prev_node == que_node_get_parent(node)) {
302 + node->state = INDEX_BUILD_STATS_COLS;
305 + if (node->state == INDEX_BUILD_STATS_COLS) {
306 + if (node->stats_no <= dict_index_get_n_unique(node->index)) {
308 + err = dict_build_stats_def_step(node);
310 + if (err != DB_SUCCESS) {
312 + goto function_exit;
317 + thr->run_node = node->stats_def;
321 + node->state = INDEX_COMMIT_WORK;
325 + if (node->state == INDEX_COMMIT_WORK) {
327 + /* do not commit transaction here for now */
331 + trx->error_state = err;
333 + if (err == DB_SUCCESS) {
338 thr->run_node = que_node_get_parent(node);
341 diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
342 --- a/storage/innobase/dict/dict0dict.c 2010-12-03 15:48:03.040222428 +0900
343 +++ b/storage/innobase/dict/dict0dict.c 2010-12-03 17:19:24.841947690 +0900
345 print an error message and return without doing
347 dict_update_statistics(table, TRUE /* only update stats
348 - if they have not been initialized */);
349 + if they have not been initialized */, FALSE);
353 @@ -4310,6 +4310,240 @@
356 /*********************************************************************//**
357 +functions to use SYS_STATS system table. */
360 +dict_reload_statistics(
361 +/*===================*/
362 + dict_table_t* table,
363 + ulint* sum_of_index_sizes)
365 + dict_index_t* index;
369 + index = dict_table_get_first_index(table);
371 + if (index == NULL) {
372 + /* Table definition is corrupt */
377 + heap = mem_heap_create(1000);
380 + size = btr_get_size(index, BTR_TOTAL_SIZE);
382 + index->stat_index_size = size;
384 + *sum_of_index_sizes += size;
386 + size = btr_get_size(index, BTR_N_LEAF_PAGES);
389 + /* The root node of the tree is a leaf */
393 + index->stat_n_leaf_pages = size;
395 +/*===========================================*/
397 + dict_table_t* sys_stats;
398 + dict_index_t* sys_index;
407 + ib_int64_t* stat_n_diff_key_vals_tmp;
412 + n_cols = dict_index_get_n_unique(index);
413 + stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
415 + sys_stats = dict_sys->sys_stats;
416 + sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
417 + ut_a(!dict_table_is_comp(sys_stats));
419 + tuple = dtuple_create(heap, 1);
420 + dfield = dtuple_get_nth_field(tuple, 0);
422 + buf = mem_heap_alloc(heap, 8);
423 + mach_write_to_8(buf, index->id);
425 + dfield_set_data(dfield, buf, 8);
426 + dict_index_copy_types(tuple, sys_index, 1);
430 + btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
431 + BTR_SEARCH_LEAF, &pcur, &mtr);
432 + for (i = 0; i <= n_cols; i++) {
433 + rec = btr_pcur_get_rec(&pcur);
435 + if (!btr_pcur_is_on_user_rec(&pcur)
436 + || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
438 + /* not found: even 1 if not found should not be alowed */
439 + fprintf(stderr, "InnoDB: Warning: stats for %s/%s (%lu/%lu)"
440 + " not found in SYS_STATS\n",
441 + index->table_name, index->name, i, n_cols);
442 + btr_pcur_close(&pcur);
444 + mem_heap_free(heap);
448 + if (rec_get_deleted_flag(rec, 0)) {
452 + field = rec_get_nth_field_old(rec, 1, &len);
455 + key_cols = mach_read_from_4(field);
457 + ut_a(i == key_cols);
459 + field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
462 + stat_n_diff_key_vals_tmp[i] = mach_read_from_8(field);
464 + btr_pcur_move_to_next_user_rec(&pcur, &mtr);
467 + btr_pcur_close(&pcur);
470 + for (i = 0; i <= n_cols; i++) {
471 + index->stat_n_diff_key_vals[i] = stat_n_diff_key_vals_tmp[i];
474 +/*===========================================*/
476 + index = dict_table_get_next_index(index);
479 + mem_heap_free(heap);
485 +dict_store_statistics(
486 +/*==================*/
487 + dict_table_t* table)
489 + dict_index_t* index;
492 + index = dict_table_get_first_index(table);
496 + heap = mem_heap_create(1000);
499 +/*===========================================*/
501 + dict_table_t* sys_stats;
502 + dict_index_t* sys_index;
512 + ib_int64_t* stat_n_diff_key_vals_tmp;
517 + n_cols = dict_index_get_n_unique(index);
518 + stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
520 + for (i = 0; i <= n_cols; i++) {
521 + stat_n_diff_key_vals_tmp[i] = index->stat_n_diff_key_vals[i];
524 + sys_stats = dict_sys->sys_stats;
525 + sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
526 + ut_a(!dict_table_is_comp(sys_stats));
528 + tuple = dtuple_create(heap, 1);
529 + dfield = dtuple_get_nth_field(tuple, 0);
531 + buf = mem_heap_alloc(heap, 8);
532 + mach_write_to_8(buf, index->id);
534 + dfield_set_data(dfield, buf, 8);
535 + dict_index_copy_types(tuple, sys_index, 1);
539 + btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
540 + BTR_MODIFY_LEAF, &pcur, &mtr);
541 + rests = n_cols + 1;
542 + for (i = 0; i <= n_cols; i++) {
543 + rec = btr_pcur_get_rec(&pcur);
545 + if (!btr_pcur_is_on_user_rec(&pcur)
546 + || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
554 + if (rec_get_deleted_flag(rec, 0)) {
558 + field = rec_get_nth_field_old(rec, 1, &len);
561 + key_cols = mach_read_from_4(field);
563 + field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
566 + mlog_write_ull((byte*)field, stat_n_diff_key_vals_tmp[key_cols], &mtr);
571 + btr_pcur_move_to_next_user_rec(&pcur, &mtr);
573 + btr_pcur_close(&pcur);
577 + fprintf(stderr, "InnoDB: Warning: failed to store %lu stats entries"
578 + " of %s/%s to SYS_STATS system table.\n",
579 + rests, index->table_name, index->name);
582 +/*===========================================*/
584 + index = dict_table_get_next_index(index);
587 + mem_heap_free(heap);
590 +/*********************************************************************//**
591 Calculates new estimates for table and index statistics. The statistics
592 are used in query optimization. */
594 @@ -4317,10 +4551,11 @@
595 dict_update_statistics(
596 /*===================*/
597 dict_table_t* table, /*!< in/out: table */
598 - ibool only_calc_if_missing_stats)/*!< in: only
599 + ibool only_calc_if_missing_stats,/*!< in: only
600 update/recalc the stats if they have
601 not been initialized yet, otherwise
603 + ibool sync) /*!< in: TRUE if must update SYS_STATS */
606 ulint sum_of_index_sizes = 0;
607 @@ -4337,6 +4572,27 @@
611 + if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) && !sync) {
612 + dict_table_stats_lock(table, RW_X_LATCH);
614 + /* reload statistics from SYS_STATS table */
615 + if (dict_reload_statistics(table, &sum_of_index_sizes)) {
618 + fprintf(stderr, "InnoDB: DEBUG: reload_statistics succeeded for %s.\n",
624 + dict_table_stats_unlock(table, RW_X_LATCH);
627 + fprintf(stderr, "InnoDB: DEBUG: update_statistics for %s.\n",
630 + sum_of_index_sizes = 0;
632 /* Find out the sizes of the indexes and how many different values
633 for the key they approximately have */
635 @@ -4401,6 +4657,11 @@
636 index = dict_table_get_next_index(index);
639 + if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)) {
640 + /* store statistics to SYS_STATS table */
641 + dict_store_statistics(table);
644 index = dict_table_get_first_index(table);
646 table->stat_n_rows = index->stat_n_diff_key_vals[
647 @@ -4495,7 +4756,8 @@
649 ut_ad(mutex_own(&(dict_sys->mutex)));
651 - dict_update_statistics(table, FALSE /* update even if initialized */);
652 + if (srv_stats_auto_update)
653 + dict_update_statistics(table, FALSE /* update even if initialized */, FALSE);
655 dict_table_stats_lock(table, RW_S_LATCH);
657 diff -ruN a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c
658 --- a/storage/innobase/dict/dict0load.c 2010-11-03 07:01:13.000000000 +0900
659 +++ b/storage/innobase/dict/dict0load.c 2010-12-03 17:19:24.845947460 +0900
665 + "SYS_FOREIGN_COLS",
668 /****************************************************************//**
669 Compare the name of an index column.
670 @@ -343,12 +344,13 @@
673 if ((status & DICT_TABLE_UPDATE_STATS)
674 + && srv_stats_auto_update
675 && dict_table_get_first_index(*table)) {
677 /* Update statistics if DICT_TABLE_UPDATE_STATS
679 dict_update_statistics(*table, FALSE /* update even if
681 + initialized */, FALSE);
686 //#endif /* FOREIGN_NOT_USED */
688 /********************************************************************//**
689 +This function parses a SYS_STATS record and extract necessary
690 +information from the record and return to caller.
691 +@return error message, or NULL on success */
694 +dict_process_sys_stats_rec(
695 +/*=============================*/
696 + mem_heap_t* heap __attribute__((unused)), /*!< in/out: heap memory */
697 + const rec_t* rec, /*!< in: current SYS_STATS rec */
698 + index_id_t* index_id, /*!< out: INDEX_ID */
699 + ulint* key_cols, /*!< out: KEY_COLS */
700 + ib_uint64_t* diff_vals) /*!< out: DIFF_VALS */
705 + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
706 + return("delete-marked record in SYS_STATS");
709 + if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
710 + return("wrong number of columns in SYS_STATS record");
713 + field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
714 + if (UNIV_UNLIKELY(len != 8)) {
716 + return("incorrect column length in SYS_STATS");
718 + *index_id = mach_read_from_8(field);
720 + field = rec_get_nth_field_old(rec, 1/*KEY_COLS*/, &len);
721 + if (UNIV_UNLIKELY(len != 4)) {
724 + *key_cols = mach_read_from_4(field);
726 + rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
727 + if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
730 + rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
731 + if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
735 + field = rec_get_nth_field_old(rec, 4/*DIFF_VALS*/, &len);
736 + if (UNIV_UNLIKELY(len != 8)) {
739 + *diff_vals = mach_read_from_8(field);
743 +/********************************************************************//**
744 Determine the flags of a table described in SYS_TABLES.
745 @return compressed page size in kilobytes; or 0 if the tablespace is
746 uncompressed, ULINT_UNDEFINED on error */
747 diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
748 --- a/storage/innobase/handler/ha_innodb.cc 2010-12-03 17:17:03.665960357 +0900
749 +++ b/storage/innobase/handler/ha_innodb.cc 2010-12-03 17:22:21.586939783 +0900
751 static my_bool innobase_rollback_on_timeout = FALSE;
752 static my_bool innobase_create_status_file = FALSE;
753 static my_bool innobase_stats_on_metadata = TRUE;
754 +static my_bool innobase_use_sys_stats_table = FALSE;
757 static char* internal_innobase_data_file_path = NULL;
758 @@ -2407,6 +2408,8 @@
762 + srv_use_sys_stats_table = (ibool) innobase_use_sys_stats_table;
764 /* -------------- Log files ---------------------------*/
766 /* The default dir for log files is the datadir of MySQL */
767 @@ -5211,6 +5214,10 @@
769 error = row_insert_for_mysql((byte*) record, prebuilt);
771 +#ifdef EXTENDED_FOR_USERSTAT
772 + if (error == DB_SUCCESS) rows_changed++;
775 /* Handle duplicate key errors */
778 @@ -5547,6 +5554,10 @@
782 +#ifdef EXTENDED_FOR_USERSTAT
783 + if (error == DB_SUCCESS) rows_changed++;
786 innodb_srv_conc_exit_innodb(trx);
788 error = convert_error_code_to_mysql(error,
789 @@ -5600,6 +5611,10 @@
791 error = row_update_for_mysql((byte*) record, prebuilt);
793 +#ifdef EXTENDED_FOR_USERSTAT
794 + if (error == DB_SUCCESS) rows_changed++;
797 innodb_srv_conc_exit_innodb(trx);
799 error = convert_error_code_to_mysql(
800 @@ -5918,6 +5933,11 @@
804 +#ifdef EXTENDED_FOR_USERSTAT
806 + if (active_index >= 0 && active_index < MAX_KEY)
807 + index_rows_read[active_index]++;
810 case DB_RECORD_NOT_FOUND:
811 error = HA_ERR_KEY_NOT_FOUND;
812 @@ -6127,6 +6147,11 @@
816 +#ifdef EXTENDED_FOR_USERSTAT
818 + if (active_index >= 0 && active_index < MAX_KEY)
819 + index_rows_read[active_index]++;
822 case DB_RECORD_NOT_FOUND:
823 error = HA_ERR_END_OF_FILE;
824 @@ -8077,11 +8102,31 @@
825 /* In sql_show we call with this flag: update
826 then statistics so that they are up-to-date */
828 + if (srv_use_sys_stats_table && !((ib_table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)
829 + && called_from_analyze) {
830 + /* If the indexes on the table don't have enough rows in SYS_STATS system table, */
831 + /* they need to be created. */
832 + dict_index_t* index;
834 + prebuilt->trx->op_info = "confirming rows of SYS_STATS to store statistics";
836 + ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
838 + for (index = dict_table_get_first_index(ib_table);
840 + index = dict_table_get_next_index(index)) {
841 + row_insert_stats_for_mysql(index, prebuilt->trx);
842 + innobase_commit_low(prebuilt->trx);
845 + ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
848 prebuilt->trx->op_info = "updating table statistics";
850 dict_update_statistics(ib_table,
851 FALSE /* update even if stats
852 - are initialized */);
853 + are initialized */, called_from_analyze);
855 prebuilt->trx->op_info = "returning various info to MySQL";
857 @@ -8159,7 +8204,7 @@
858 are asked by MySQL to avoid locking. Another reason to
859 avoid the call is that it uses quite a lot of CPU.
861 - if (flag & HA_STATUS_NO_LOCK
862 + if (flag & HA_STATUS_NO_LOCK || !srv_stats_update_need_lock
863 || !(flag & HA_STATUS_VARIABLE_EXTRA)) {
864 /* We do not update delete_length if no
865 locking is requested so the "old" value can
866 @@ -11354,6 +11399,26 @@
867 "The number of index pages to sample when calculating statistics (default 8)",
868 NULL, NULL, 8, 1, ~0ULL, 0);
870 +static MYSQL_SYSVAR_ULONG(stats_auto_update, srv_stats_auto_update,
871 + PLUGIN_VAR_RQCMDARG,
872 + "Enable/Disable InnoDB's auto update statistics of indexes. "
873 + "(except for ANALYZE TABLE command) 0:disable 1:enable",
874 + NULL, NULL, 1, 0, 1, 0);
876 +static MYSQL_SYSVAR_ULONG(stats_update_need_lock, srv_stats_update_need_lock,
877 + PLUGIN_VAR_RQCMDARG,
878 + "Enable/Disable InnoDB's update statistics which needs to lock dictionary. "
880 + NULL, NULL, 1, 0, 1, 0);
882 +static MYSQL_SYSVAR_BOOL(use_sys_stats_table, innobase_use_sys_stats_table,
883 + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
884 + "Enable to use SYS_STATS system table to store statistics statically, "
885 + "And avoids to calculate statistics at every first open of the tables. "
886 + "This option may make the opportunities of update statistics less. "
887 + "So you should use ANALYZE TABLE command intentionally.",
888 + NULL, NULL, FALSE);
890 static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
892 "Enable InnoDB adaptive hash index (enabled by default). "
893 @@ -11684,6 +11749,9 @@
894 MYSQL_SYSVAR(recovery_update_relay_log),
895 MYSQL_SYSVAR(rollback_on_timeout),
896 MYSQL_SYSVAR(stats_on_metadata),
897 + MYSQL_SYSVAR(stats_auto_update),
898 + MYSQL_SYSVAR(stats_update_need_lock),
899 + MYSQL_SYSVAR(use_sys_stats_table),
900 MYSQL_SYSVAR(stats_sample_pages),
901 MYSQL_SYSVAR(adaptive_hash_index),
902 MYSQL_SYSVAR(stats_method),
903 @@ -11753,7 +11821,10 @@
904 i_s_innodb_sys_columns,
905 i_s_innodb_sys_fields,
906 i_s_innodb_sys_foreign,
907 -i_s_innodb_sys_foreign_cols
908 +i_s_innodb_sys_foreign_cols,
909 +i_s_innodb_sys_stats,
910 +i_s_innodb_table_stats,
911 +i_s_innodb_index_stats
912 mysql_declare_plugin_end;
914 /** @brief Initialize the default value of innodb_commit_concurrency.
915 diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
916 --- a/storage/innobase/handler/i_s.cc 2010-12-03 17:17:03.666956117 +0900
917 +++ b/storage/innobase/handler/i_s.cc 2010-12-03 17:19:24.880964526 +0900
919 #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
920 #include "trx0rseg.h" /* for trx_rseg_struct */
921 #include "trx0sys.h" /* for trx_sys */
922 +#include "dict0dict.h" /* for dict_sys */
925 static const char plugin_author[] = "Innobase Oy";
926 @@ -3457,6 +3458,203 @@
927 STRUCT_FLD(__reserved1, NULL)
930 +/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_stats */
931 +static ST_FIELD_INFO innodb_sys_stats_fields_info[] =
933 +#define SYS_STATS_INDEX_ID 0
934 + {STRUCT_FLD(field_name, "INDEX_ID"),
935 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
936 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
937 + STRUCT_FLD(value, 0),
938 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
939 + STRUCT_FLD(old_name, ""),
940 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
942 +#define SYS_STATS_KEY_COLS 1
943 + {STRUCT_FLD(field_name, "KEY_COLS"),
944 + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
945 + STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
946 + STRUCT_FLD(value, 0),
947 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
948 + STRUCT_FLD(old_name, ""),
949 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
951 +#define SYS_STATS_DIFF_VALS 2
952 + {STRUCT_FLD(field_name, "DIFF_VALS"),
953 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
954 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
955 + STRUCT_FLD(value, 0),
956 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
957 + STRUCT_FLD(old_name, ""),
958 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
960 + END_OF_ST_FIELD_INFO
962 +/**********************************************************************//**
963 +Function to fill information_schema.innodb_sys_stats
964 +@return 0 on success */
967 +i_s_dict_fill_sys_stats(
968 +/*====================*/
969 + THD* thd, /*!< in: thread */
970 + index_id_t index_id, /*!< in: INDEX_ID */
971 + ulint key_cols, /*!< in: KEY_COLS */
972 + ib_uint64_t diff_vals, /*!< in: DIFF_VALS */
973 + TABLE* table_to_fill) /*!< in/out: fill this table */
977 + DBUG_ENTER("i_s_dict_fill_sys_stats");
979 + fields = table_to_fill->field;
981 + OK(fields[SYS_STATS_INDEX_ID]->store(longlong(index_id), TRUE));
983 + OK(fields[SYS_STATS_KEY_COLS]->store(key_cols));
985 + OK(fields[SYS_STATS_DIFF_VALS]->store(longlong(diff_vals), TRUE));
987 + OK(schema_table_store_record(thd, table_to_fill));
991 +/*******************************************************************//**
992 +Function to populate INFORMATION_SCHEMA.innodb_sys_stats table.
993 +@return 0 on success */
996 +i_s_sys_stats_fill_table(
997 +/*=====================*/
998 + THD* thd, /*!< in: thread */
999 + TABLE_LIST* tables, /*!< in/out: tables to fill */
1000 + COND* cond) /*!< in: condition (not used) */
1007 + DBUG_ENTER("i_s_sys_stats_fill_table");
1009 + /* deny access to non-superusers */
1010 + if (check_global_access(thd, PROCESS_ACL)) {
1014 + heap = mem_heap_create(1000);
1015 + mutex_enter(&dict_sys->mutex);
1018 + rec = dict_startscan_system(&pcur, &mtr, SYS_STATS);
1021 + const char* err_msg;
1022 + index_id_t index_id;
1024 + ib_uint64_t diff_vals;
1026 + /* Extract necessary information from a SYS_FOREIGN_COLS row */
1027 + err_msg = dict_process_sys_stats_rec(
1028 + heap, rec, &index_id, &key_cols, &diff_vals);
1031 + mutex_exit(&dict_sys->mutex);
1034 + i_s_dict_fill_sys_stats(
1035 + thd, index_id, key_cols, diff_vals,
1038 + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
1039 + ER_CANT_FIND_SYSTEM_REC,
1043 + mem_heap_empty(heap);
1045 + /* Get the next record */
1046 + mutex_enter(&dict_sys->mutex);
1048 + rec = dict_getnext_system(&pcur, &mtr);
1052 + mutex_exit(&dict_sys->mutex);
1053 + mem_heap_free(heap);
1057 +/*******************************************************************//**
1058 +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_stats
1059 +@return 0 on success */
1062 +innodb_sys_stats_init(
1063 +/*========================*/
1064 + void* p) /*!< in/out: table schema object */
1066 + ST_SCHEMA_TABLE* schema;
1068 + DBUG_ENTER("innodb_sys_stats_init");
1070 + schema = (ST_SCHEMA_TABLE*) p;
1072 + schema->fields_info = innodb_sys_stats_fields_info;
1073 + schema->fill_table = i_s_sys_stats_fill_table;
1078 +UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_stats =
1080 + /* the plugin type (a MYSQL_XXX_PLUGIN value) */
1082 + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1084 + /* pointer to type-specific plugin descriptor */
1086 + STRUCT_FLD(info, &i_s_info),
1090 + STRUCT_FLD(name, "INNODB_SYS_STATS"),
1092 + /* plugin author (for SHOW PLUGINS) */
1094 + STRUCT_FLD(author, plugin_author),
1096 + /* general descriptive text (for SHOW PLUGINS) */
1098 + STRUCT_FLD(descr, "XtraDB SYS_STATS table"),
1100 + /* the plugin license (PLUGIN_LICENSE_XXX) */
1102 + STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1104 + /* the function to invoke when plugin is loaded */
1105 + /* int (*)(void*); */
1106 + STRUCT_FLD(init, innodb_sys_stats_init),
1108 + /* the function to invoke when plugin is unloaded */
1109 + /* int (*)(void*); */
1110 + STRUCT_FLD(deinit, i_s_common_deinit),
1112 + /* plugin version (for SHOW PLUGINS) */
1113 + /* unsigned int */
1114 + STRUCT_FLD(version, INNODB_VERSION_SHORT),
1116 + /* struct st_mysql_show_var* */
1117 + STRUCT_FLD(status_vars, NULL),
1119 + /* struct st_mysql_sys_var** */
1120 + STRUCT_FLD(system_vars, NULL),
1122 + /* reserved for dependency checking */
1124 + STRUCT_FLD(__reserved1, NULL)
1127 /***********************************************************************
1129 static ST_FIELD_INFO i_s_innodb_rseg_fields_info[] =
1130 @@ -3619,3 +3817,347 @@
1132 STRUCT_FLD(__reserved1, NULL)
1135 +/***********************************************************************
1137 +static ST_FIELD_INFO i_s_innodb_table_stats_info[] =
1139 + {STRUCT_FLD(field_name, "table_schema"),
1140 + STRUCT_FLD(field_length, NAME_LEN),
1141 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1142 + STRUCT_FLD(value, 0),
1143 + STRUCT_FLD(field_flags, 0),
1144 + STRUCT_FLD(old_name, ""),
1145 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1147 + {STRUCT_FLD(field_name, "table_name"),
1148 + STRUCT_FLD(field_length, NAME_LEN),
1149 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1150 + STRUCT_FLD(value, 0),
1151 + STRUCT_FLD(field_flags, 0),
1152 + STRUCT_FLD(old_name, ""),
1153 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1155 + {STRUCT_FLD(field_name, "rows"),
1156 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1157 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1158 + STRUCT_FLD(value, 0),
1159 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1160 + STRUCT_FLD(old_name, ""),
1161 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1163 + {STRUCT_FLD(field_name, "clust_size"),
1164 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1165 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1166 + STRUCT_FLD(value, 0),
1167 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1168 + STRUCT_FLD(old_name, ""),
1169 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1171 + {STRUCT_FLD(field_name, "other_size"),
1172 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1173 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1174 + STRUCT_FLD(value, 0),
1175 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1176 + STRUCT_FLD(old_name, ""),
1177 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1179 + {STRUCT_FLD(field_name, "modified"),
1180 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1181 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1182 + STRUCT_FLD(value, 0),
1183 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1184 + STRUCT_FLD(old_name, ""),
1185 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1187 + END_OF_ST_FIELD_INFO
1190 +static ST_FIELD_INFO i_s_innodb_index_stats_info[] =
1192 + {STRUCT_FLD(field_name, "table_schema"),
1193 + STRUCT_FLD(field_length, NAME_LEN),
1194 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1195 + STRUCT_FLD(value, 0),
1196 + STRUCT_FLD(field_flags, 0),
1197 + STRUCT_FLD(old_name, ""),
1198 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1200 + {STRUCT_FLD(field_name, "table_name"),
1201 + STRUCT_FLD(field_length, NAME_LEN),
1202 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1203 + STRUCT_FLD(value, 0),
1204 + STRUCT_FLD(field_flags, 0),
1205 + STRUCT_FLD(old_name, ""),
1206 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1208 + {STRUCT_FLD(field_name, "index_name"),
1209 + STRUCT_FLD(field_length, NAME_LEN),
1210 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1211 + STRUCT_FLD(value, 0),
1212 + STRUCT_FLD(field_flags, 0),
1213 + STRUCT_FLD(old_name, ""),
1214 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1216 + {STRUCT_FLD(field_name, "fields"),
1217 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1218 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1219 + STRUCT_FLD(value, 0),
1220 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1221 + STRUCT_FLD(old_name, ""),
1222 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1224 + {STRUCT_FLD(field_name, "rows_per_key"),
1225 + STRUCT_FLD(field_length, 256),
1226 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1227 + STRUCT_FLD(value, 0),
1228 + STRUCT_FLD(field_flags, 0),
1229 + STRUCT_FLD(old_name, ""),
1230 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1232 + {STRUCT_FLD(field_name, "index_total_pages"),
1233 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1234 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1235 + STRUCT_FLD(value, 0),
1236 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1237 + STRUCT_FLD(old_name, ""),
1238 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1240 + {STRUCT_FLD(field_name, "index_leaf_pages"),
1241 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1242 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1243 + STRUCT_FLD(value, 0),
1244 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1245 + STRUCT_FLD(old_name, ""),
1246 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1248 + END_OF_ST_FIELD_INFO
1253 +i_s_innodb_table_stats_fill(
1254 +/*========================*/
1256 + TABLE_LIST* tables,
1259 + TABLE* i_s_table = (TABLE *) tables->table;
1261 + dict_table_t* table;
1263 + DBUG_ENTER("i_s_innodb_table_stats_fill");
1265 + /* deny access to non-superusers */
1266 + if (check_global_access(thd, PROCESS_ACL)) {
1270 + mutex_enter(&(dict_sys->mutex));
1272 + table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1275 + char buf[NAME_LEN * 2 + 2];
1278 + if (table->stat_clustered_index_size == 0) {
1279 + table = UT_LIST_GET_NEXT(table_LRU, table);
1283 + buf[NAME_LEN * 2 + 1] = 0;
1284 + strncpy(buf, table->name, NAME_LEN * 2 + 1);
1285 + ptr = strchr(buf, '/');
1293 + field_store_string(i_s_table->field[0], buf);
1294 + field_store_string(i_s_table->field[1], ptr);
1295 + i_s_table->field[2]->store(table->stat_n_rows);
1296 + i_s_table->field[3]->store(table->stat_clustered_index_size);
1297 + i_s_table->field[4]->store(table->stat_sum_of_other_index_sizes);
1298 + i_s_table->field[5]->store(table->stat_modified_counter);
1300 + if (schema_table_store_record(thd, i_s_table)) {
1305 + table = UT_LIST_GET_NEXT(table_LRU, table);
1308 + mutex_exit(&(dict_sys->mutex));
1310 + DBUG_RETURN(status);
1315 +i_s_innodb_index_stats_fill(
1316 +/*========================*/
1318 + TABLE_LIST* tables,
1321 + TABLE* i_s_table = (TABLE *) tables->table;
1323 + dict_table_t* table;
1324 + dict_index_t* index;
1326 + DBUG_ENTER("i_s_innodb_index_stats_fill");
1328 + /* deny access to non-superusers */
1329 + if (check_global_access(thd, PROCESS_ACL)) {
1333 + mutex_enter(&(dict_sys->mutex));
1335 + table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1338 + if (table->stat_clustered_index_size == 0) {
1339 + table = UT_LIST_GET_NEXT(table_LRU, table);
1343 + ib_int64_t n_rows = table->stat_n_rows;
1349 + index = dict_table_get_first_index(table);
1353 + char row_per_keys[256+1];
1354 + char buf[NAME_LEN * 2 + 2];
1358 + buf[NAME_LEN * 2 + 1] = 0;
1359 + strncpy(buf, table->name, NAME_LEN * 2 + 1);
1360 + ptr = strchr(buf, '/');
1368 + field_store_string(i_s_table->field[0], buf);
1369 + field_store_string(i_s_table->field[1], ptr);
1370 + field_store_string(i_s_table->field[2], index->name);
1371 + i_s_table->field[3]->store(index->n_uniq);
1373 + row_per_keys[0] = '\0';
1375 + /* It is remained optimistic operation still for now */
1376 + //dict_index_stat_mutex_enter(index);
1377 + if (index->stat_n_diff_key_vals) {
1378 + for (i = 1; i <= index->n_uniq; i++) {
1379 + ib_int64_t rec_per_key;
1380 + if (index->stat_n_diff_key_vals[i]) {
1381 + rec_per_key = n_rows / index->stat_n_diff_key_vals[i];
1383 + rec_per_key = n_rows;
1385 + ut_snprintf(buff, 256, (i == index->n_uniq)?"%llu":"%llu, ",
1387 + strncat(row_per_keys, buff, 256 - strlen(row_per_keys));
1390 + //dict_index_stat_mutex_exit(index);
1392 + field_store_string(i_s_table->field[4], row_per_keys);
1394 + i_s_table->field[5]->store(index->stat_index_size);
1395 + i_s_table->field[6]->store(index->stat_n_leaf_pages);
1397 + if (schema_table_store_record(thd, i_s_table)) {
1402 + index = dict_table_get_next_index(index);
1405 + if (status == 1) {
1409 + table = UT_LIST_GET_NEXT(table_LRU, table);
1412 + mutex_exit(&(dict_sys->mutex));
1414 + DBUG_RETURN(status);
1419 +i_s_innodb_table_stats_init(
1420 +/*========================*/
1423 + DBUG_ENTER("i_s_innodb_table_stats_init");
1424 + ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1426 + schema->fields_info = i_s_innodb_table_stats_info;
1427 + schema->fill_table = i_s_innodb_table_stats_fill;
1434 +i_s_innodb_index_stats_init(
1435 +/*========================*/
1438 + DBUG_ENTER("i_s_innodb_index_stats_init");
1439 + ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1441 + schema->fields_info = i_s_innodb_index_stats_info;
1442 + schema->fill_table = i_s_innodb_index_stats_fill;
1447 +UNIV_INTERN struct st_mysql_plugin i_s_innodb_table_stats =
1449 + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1450 + STRUCT_FLD(info, &i_s_info),
1451 + STRUCT_FLD(name, "INNODB_TABLE_STATS"),
1452 + STRUCT_FLD(author, plugin_author),
1453 + STRUCT_FLD(descr, "InnoDB table statistics in memory"),
1454 + STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1455 + STRUCT_FLD(init, i_s_innodb_table_stats_init),
1456 + STRUCT_FLD(deinit, i_s_common_deinit),
1457 + STRUCT_FLD(version, 0x0100 /* 1.0 */),
1458 + STRUCT_FLD(status_vars, NULL),
1459 + STRUCT_FLD(system_vars, NULL),
1460 + STRUCT_FLD(__reserved1, NULL)
1463 +UNIV_INTERN struct st_mysql_plugin i_s_innodb_index_stats =
1465 + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1466 + STRUCT_FLD(info, &i_s_info),
1467 + STRUCT_FLD(name, "INNODB_INDEX_STATS"),
1468 + STRUCT_FLD(author, plugin_author),
1469 + STRUCT_FLD(descr, "InnoDB index statistics in memory"),
1470 + STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1471 + STRUCT_FLD(init, i_s_innodb_index_stats_init),
1472 + STRUCT_FLD(deinit, i_s_common_deinit),
1473 + STRUCT_FLD(version, 0x0100 /* 1.0 */),
1474 + STRUCT_FLD(status_vars, NULL),
1475 + STRUCT_FLD(system_vars, NULL),
1476 + STRUCT_FLD(__reserved1, NULL)
1478 diff -ruN a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h
1479 --- a/storage/innobase/handler/i_s.h 2010-12-03 17:17:03.668953884 +0900
1480 +++ b/storage/innobase/handler/i_s.h 2010-12-03 17:19:24.882947826 +0900
1482 extern struct st_mysql_plugin i_s_innodb_sys_foreign;
1483 extern struct st_mysql_plugin i_s_innodb_sys_foreign_cols;
1484 extern struct st_mysql_plugin i_s_innodb_rseg;
1485 +extern struct st_mysql_plugin i_s_innodb_sys_stats;
1486 +extern struct st_mysql_plugin i_s_innodb_table_stats;
1487 +extern struct st_mysql_plugin i_s_innodb_index_stats;
1490 diff -ruN a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h
1491 --- a/storage/innobase/include/dict0boot.h 2010-11-03 07:01:13.000000000 +0900
1492 +++ b/storage/innobase/include/dict0boot.h 2010-12-03 17:19:24.885947372 +0900
1494 #define DICT_COLUMNS_ID 2
1495 #define DICT_INDEXES_ID 3
1496 #define DICT_FIELDS_ID 4
1497 +#define DICT_STATS_ID 6
1498 /* The following is a secondary index on SYS_TABLES */
1499 #define DICT_TABLE_IDS_ID 5
1501 @@ -131,10 +132,13 @@
1502 #define DICT_HDR_INDEXES 44 /* Root of the index index tree */
1503 #define DICT_HDR_FIELDS 48 /* Root of the index field
1505 +#define DICT_HDR_STATS 52 /* Root of the stats tree */
1507 #define DICT_HDR_FSEG_HEADER 56 /* Segment header for the tablespace
1508 segment into which the dictionary
1509 header is created */
1511 +#define DICT_HDR_XTRADB_MARK 256 /* Flag to distinguish expansion of XtraDB */
1512 /*-------------------------------------------------------------*/
1514 /* The field number of the page number field in the sys_indexes table
1515 @@ -144,11 +148,15 @@
1516 #define DICT_SYS_INDEXES_TYPE_FIELD 6
1517 #define DICT_SYS_INDEXES_NAME_FIELD 4
1519 +#define DICT_SYS_STATS_DIFF_VALS_FIELD 4
1521 /* When a row id which is zero modulo this number (which must be a power of
1522 two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is
1524 #define DICT_HDR_ROW_ID_WRITE_MARGIN 256
1526 +#define DICT_HDR_XTRADB_FLAG 0x5854524144425F31ULL /* "XTRADB_1" */
1529 #include "dict0boot.ic"
1531 diff -ruN a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h
1532 --- a/storage/innobase/include/dict0crea.h 2010-11-03 07:01:13.000000000 +0900
1533 +++ b/storage/innobase/include/dict0crea.h 2010-12-03 17:19:24.886949643 +0900
1535 dict_index_t* index, /*!< in: index to create, built as a memory data
1537 mem_heap_t* heap); /*!< in: heap where created */
1538 +/*********************************************************************//**
1542 +ind_insert_stats_graph_create(
1543 +/*==========================*/
1544 + dict_index_t* index,
1545 + mem_heap_t* heap);
1546 /***********************************************************//**
1547 Creates a table. This is a high-level function used in SQL execution graphs.
1548 @return query thread to run next or NULL */
1550 /*===================*/
1551 que_thr_t* thr); /*!< in: query thread */
1552 /***********************************************************//**
1556 +dict_insert_stats_step(
1557 +/*===================*/
1559 +/***********************************************************//**
1560 Creates an index. This is a high-level function used in SQL execution
1562 @return query thread to run next or NULL */
1564 ins_node_t* field_def; /* child node which does the inserts of
1565 the field definitions; the row to be inserted
1566 is built by the parent node */
1567 + ins_node_t* stats_def;
1568 commit_node_t* commit_node;
1569 /* child node which performs a commit after
1570 a successful index creation */
1572 dict_table_t* table; /*!< table which owns the index */
1573 dtuple_t* ind_row;/* index definition row built */
1574 ulint field_no;/* next field definition to insert */
1576 mem_heap_t* heap; /*!< memory heap used as auxiliary storage */
1580 #define INDEX_CREATE_INDEX_TREE 3
1581 #define INDEX_COMMIT_WORK 4
1582 #define INDEX_ADD_TO_CACHE 5
1583 +#define INDEX_BUILD_STATS_COLS 6
1586 #include "dict0crea.ic"
1587 diff -ruN a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
1588 --- a/storage/innobase/include/dict0dict.h 2010-12-03 15:48:03.073024387 +0900
1589 +++ b/storage/innobase/include/dict0dict.h 2010-12-03 17:19:24.888965622 +0900
1590 @@ -1084,10 +1084,11 @@
1591 dict_update_statistics(
1592 /*===================*/
1593 dict_table_t* table, /*!< in/out: table */
1594 - ibool only_calc_if_missing_stats);/*!< in: only
1595 + ibool only_calc_if_missing_stats, /*!< in: only
1596 update/recalc the stats if they have
1597 not been initialized yet, otherwise
1600 /********************************************************************//**
1601 Reserves the dictionary system mutex for MySQL. */
1603 @@ -1202,6 +1203,7 @@
1604 dict_table_t* sys_columns; /*!< SYS_COLUMNS table */
1605 dict_table_t* sys_indexes; /*!< SYS_INDEXES table */
1606 dict_table_t* sys_fields; /*!< SYS_FIELDS table */
1607 + dict_table_t* sys_stats; /*!< SYS_STATS table */
1609 #endif /* !UNIV_HOTBACKUP */
1611 diff -ruN a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h
1612 --- a/storage/innobase/include/dict0load.h 2010-11-03 07:01:13.000000000 +0900
1613 +++ b/storage/innobase/include/dict0load.h 2010-12-03 17:19:24.889947481 +0900
1620 /* This must be last item. Defines the number of system tables. */
1621 SYS_NUM_SYSTEM_TABLES
1622 @@ -319,6 +320,19 @@
1623 const char** ref_col_name, /*!< out: referenced column name
1624 in referenced table */
1625 ulint* pos); /*!< out: column position */
1626 +/********************************************************************//**
1627 +This function parses a SYS_STATS record and extract necessary
1628 +information from the record and return to caller.
1629 +@return error message, or NULL on success */
1632 +dict_process_sys_stats_rec(
1633 +/*=============================*/
1634 + mem_heap_t* heap, /*!< in/out: heap memory */
1635 + const rec_t* rec, /*!< in: current SYS_STATS rec */
1636 + index_id_t* index_id, /*!< out: INDEX_ID */
1637 + ulint* key_cols, /*!< out: KEY_COLS */
1638 + ib_uint64_t* diff_vals); /*!< out: DIFF_VALS */
1640 #include "dict0load.ic"
1642 diff -ruN a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h
1643 --- a/storage/innobase/include/que0que.h 2010-11-03 07:01:13.000000000 +0900
1644 +++ b/storage/innobase/include/que0que.h 2010-12-03 17:19:24.892947946 +0900
1646 #define QUE_NODE_CALL 31
1647 #define QUE_NODE_EXIT 32
1649 +#define QUE_NODE_INSERT_STATS 34
1651 /* Query thread states */
1652 #define QUE_THR_RUNNING 1
1653 #define QUE_THR_PROCEDURE_WAIT 2
1654 diff -ruN a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
1655 --- a/storage/innobase/include/row0mysql.h 2010-11-03 07:01:13.000000000 +0900
1656 +++ b/storage/innobase/include/row0mysql.h 2010-12-03 17:19:24.904973020 +0900
1657 @@ -387,6 +387,14 @@
1658 then checked for not being too
1660 /*********************************************************************//**
1664 +row_insert_stats_for_mysql(
1665 +/*=======================*/
1666 + dict_index_t* index,
1668 +/*********************************************************************//**
1669 Scans a table create SQL string and adds to the data dictionary
1670 the foreign key constraints declared in the string. This function
1671 should be called after the indexes for a table have been created.
1672 diff -ruN a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
1673 --- a/storage/innobase/include/srv0srv.h 2010-12-03 15:53:54.622036720 +0900
1674 +++ b/storage/innobase/include/srv0srv.h 2010-12-03 17:19:24.906953188 +0900
1676 extern ibool srv_innodb_status;
1678 extern unsigned long long srv_stats_sample_pages;
1679 +extern ulint srv_stats_auto_update;
1680 +extern ulint srv_stats_update_need_lock;
1681 +extern ibool srv_use_sys_stats_table;
1683 extern ibool srv_use_doublewrite_buf;
1684 extern ibool srv_use_checksums;
1685 diff -ruN a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c
1686 --- a/storage/innobase/que/que0que.c 2010-11-03 07:01:13.000000000 +0900
1687 +++ b/storage/innobase/que/que0que.c 2010-12-03 17:19:24.910953422 +0900
1688 @@ -621,11 +621,21 @@
1690 que_graph_free_recursive(cre_ind->ind_def);
1691 que_graph_free_recursive(cre_ind->field_def);
1692 + if (srv_use_sys_stats_table)
1693 + que_graph_free_recursive(cre_ind->stats_def);
1694 que_graph_free_recursive(cre_ind->commit_node);
1696 mem_heap_free(cre_ind->heap);
1699 + case QUE_NODE_INSERT_STATS:
1702 + que_graph_free_recursive(cre_ind->stats_def);
1703 + que_graph_free_recursive(cre_ind->commit_node);
1705 + mem_heap_free(cre_ind->heap);
1708 que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
1710 @@ -1138,6 +1148,8 @@
1711 str = "CREATE TABLE";
1712 } else if (type == QUE_NODE_CREATE_INDEX) {
1713 str = "CREATE INDEX";
1714 + } else if (type == QUE_NODE_INSERT_STATS) {
1715 + str = "INSERT TO SYS_STATS";
1716 } else if (type == QUE_NODE_FOR) {
1718 } else if (type == QUE_NODE_RETURN) {
1719 @@ -1255,6 +1267,8 @@
1720 thr = dict_create_table_step(thr);
1721 } else if (type == QUE_NODE_CREATE_INDEX) {
1722 thr = dict_create_index_step(thr);
1723 + } else if (type == QUE_NODE_INSERT_STATS) {
1724 + thr = dict_insert_stats_step(thr);
1725 } else if (type == QUE_NODE_ROW_PRINTF) {
1726 thr = row_printf_step(thr);
1728 diff -ruN a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c
1729 --- a/storage/innobase/row/row0merge.c 2010-11-03 07:01:13.000000000 +0900
1730 +++ b/storage/innobase/row/row0merge.c 2010-12-03 17:19:24.914955391 +0900
1731 @@ -2020,6 +2020,8 @@
1732 "UPDATE SYS_INDEXES SET NAME=CONCAT('"
1733 TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n"
1735 + /* Drop the statistics of the index. */
1736 + "DELETE FROM SYS_STATS WHERE INDEX_ID = :indexid;\n"
1737 /* Drop the field definitions of the index. */
1738 "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
1739 /* Drop the index definition and the B-tree. */
1740 diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
1741 --- a/storage/innobase/row/row0mysql.c 2010-11-03 07:01:13.000000000 +0900
1742 +++ b/storage/innobase/row/row0mysql.c 2010-12-03 17:19:24.918953476 +0900
1745 table->stat_modified_counter = counter + 1;
1747 + if (!srv_stats_auto_update)
1750 /* Calculate new statistics if 1 / 16 of table has been modified
1751 since the last time a statistics batch was run, or if
1752 stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
1754 || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
1756 dict_update_statistics(table, FALSE /* update even if stats
1757 - are initialized */);
1758 + are initialized */, TRUE);
1762 @@ -2105,6 +2108,45 @@
1765 /*********************************************************************//**
1769 +row_insert_stats_for_mysql(
1770 +/*=======================*/
1771 + dict_index_t* index,
1779 + ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1781 + trx->op_info = "try to insert rows to SYS_STATS";
1783 + trx_start_if_not_started(trx);
1784 + trx->error_state = DB_SUCCESS;
1786 + heap = mem_heap_create(512);
1788 + node = ind_insert_stats_graph_create(index, heap);
1790 + thr = pars_complete_graph_for_exec(node, trx, heap);
1792 + ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
1793 + que_run_threads(thr);
1795 + err = trx->error_state;
1797 + que_graph_free((que_t*) que_node_get_parent(thr));
1799 + trx->op_info = "";
1801 + return((int) err);
1804 +/*********************************************************************//**
1805 Scans a table create SQL string and adds to the data dictionary
1806 the foreign key constraints declared in the string. This function
1807 should be called after the indexes for a table have been created.
1808 @@ -3024,7 +3066,7 @@
1809 dict_table_autoinc_initialize(table, 1);
1810 dict_table_autoinc_unlock(table);
1811 dict_update_statistics(table, FALSE /* update even if stats are
1813 + initialized */, TRUE);
1815 trx_commit_for_mysql(trx);
1817 @@ -3326,6 +3368,8 @@
1818 " IF (SQL % NOTFOUND) THEN\n"
1821 + " DELETE FROM SYS_STATS\n"
1822 + " WHERE INDEX_ID = index_id;\n"
1823 " DELETE FROM SYS_FIELDS\n"
1824 " WHERE INDEX_ID = index_id;\n"
1825 " DELETE FROM SYS_INDEXES\n"
1826 diff -ruN a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
1827 --- a/storage/innobase/srv/srv0srv.c 2010-12-03 15:53:54.625288512 +0900
1828 +++ b/storage/innobase/srv/srv0srv.c 2010-12-03 17:19:24.922953561 +0900
1830 /* When estimating number of different key values in an index, sample
1831 this many index pages */
1832 UNIV_INTERN unsigned long long srv_stats_sample_pages = 8;
1833 +UNIV_INTERN ulint srv_stats_auto_update = 1;
1834 +UNIV_INTERN ulint srv_stats_update_need_lock = 1;
1835 +UNIV_INTERN ibool srv_use_sys_stats_table = FALSE;
1837 UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE;
1838 UNIV_INTERN ibool srv_use_checksums = TRUE;