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/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c
9 --- a/storage/innobase/btr/btr0cur.c 2010-12-03 15:49:59.165212710 +0900
10 +++ b/storage/innobase/btr/btr0cur.c 2010-12-03 17:19:24.834126874 +0900
11 @@ -1010,6 +1010,107 @@
15 +/**********************************************************************//**
16 +Positions a cursor at a randomly chosen position within a B-tree
18 +@return TRUE if the position is at the first page, and cursor must point
19 + the first record for used by the caller.*/
22 +btr_cur_open_at_rnd_pos_after_path(
23 +/*====================*/
24 + dict_index_t* index, /*!< in: index */
25 + ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
26 + btr_path_t* first_rec_path,
27 + btr_cur_t* cursor, /*!< in/out: B-tree cursor */
28 + mtr_t* mtr) /*!< in: mtr */
30 + page_cur_t* page_cursor;
32 + ibool is_first_rec = TRUE;
38 + mem_heap_t* heap = NULL;
39 + ulint offsets_[REC_OFFS_NORMAL_SIZE];
40 + ulint* offsets = offsets_;
41 + rec_offs_init(offsets_);
43 + if (latch_mode == BTR_MODIFY_TREE) {
44 + mtr_x_lock(dict_index_get_lock(index), mtr);
46 + mtr_s_lock(dict_index_get_lock(index), mtr);
49 + page_cursor = btr_cur_get_page_cur(cursor);
50 + cursor->index = index;
52 + space = dict_index_get_space(index);
53 + zip_size = dict_table_zip_size(index->table);
54 + page_no = dict_index_get_page(index);
56 + height = ULINT_UNDEFINED;
57 + slot = first_rec_path;
63 + block = buf_page_get_gen(space, zip_size, page_no,
64 + RW_NO_LATCH, NULL, BUF_GET,
65 + __FILE__, __LINE__, mtr);
66 + page = buf_block_get_frame(block);
67 + ut_ad(index->id == btr_page_get_index_id(page));
69 + if (height == ULINT_UNDEFINED) {
70 + /* We are in the root node */
72 + height = btr_page_get_level(page, mtr);
76 + btr_cur_latch_leaves(page, space, zip_size, page_no,
77 + latch_mode, cursor, mtr);
80 + if (is_first_rec && slot->nth_rec != ULINT_UNDEFINED) {
82 + /* must open the first rec */
83 + page_cur_open_on_nth_user_rec(block, page_cursor, slot->nth_rec);
85 + is_first_rec = page_cur_open_on_rnd_user_rec_after_nth(block,
86 + page_cursor, slot->nth_rec);
89 + is_first_rec = FALSE;
90 + page_cur_open_on_rnd_user_rec(block, page_cursor);
102 + node_ptr = page_cur_get_rec(page_cursor);
103 + offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
104 + ULINT_UNDEFINED, &heap);
105 + /* Go to the child node */
106 + page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
109 + if (UNIV_LIKELY_NULL(heap)) {
110 + mem_heap_free(heap);
113 + return (is_first_rec);
116 /*==================== B-TREE INSERT =========================*/
118 /*************************************************************//**
119 @@ -3479,6 +3580,154 @@
122 /*******************************************************************//**
123 +Estimates the number of pages which have not null value of the key of n_cols.
124 +@return estimated number of pages */
127 +btr_estimate_n_pages_not_null(
128 +/*=========================*/
129 + dict_index_t* index, /*!< in: index */
130 + ulint n_cols, /*!< in: The cols should be not null */
131 + btr_path_t* path1) /*!< in: path1[BTR_PATH_ARRAY_N_SLOTS] */
134 + btr_path_t path2[BTR_PATH_ARRAY_N_SLOTS];
139 + ibool diverged_lot;
140 + ulint divergence_level;
146 + heap = mem_heap_create(n_cols * sizeof(dfield_t)
147 + + sizeof(dtuple_t));
149 + /* make tuple1 (NULL,NULL,,,) from n_cols */
150 + tuple1 = dtuple_create(heap, n_cols);
151 + dict_index_copy_types(tuple1, index, n_cols);
153 + for (i = 0; i < n_cols; i++) {
154 + dfield_set_null(dtuple_get_nth_field(tuple1, i));
159 + cursor.path_arr = path1;
161 + btr_cur_search_to_nth_level(index, 0, tuple1, PAGE_CUR_G,
162 + BTR_SEARCH_LEAF | BTR_ESTIMATE,
163 + &cursor, 0, __FILE__, __LINE__, &mtr);
171 + cursor.path_arr = path2;
173 + btr_cur_open_at_index_side(FALSE, index,
174 + BTR_SEARCH_LEAF | BTR_ESTIMATE,
179 + mem_heap_free(heap);
181 + /* We have the path information for the range in path1 and path2 */
184 + diverged = FALSE; /* This becomes true when the path is not
185 + the same any more */
186 + diverged_lot = FALSE; /* This becomes true when the paths are
187 + not the same or adjacent any more */
188 + divergence_level = 1000000; /* This is the level where paths diverged
190 + for (i = 0; ; i++) {
191 + ut_ad(i < BTR_PATH_ARRAY_N_SLOTS);
196 + if ((slot1 + 1)->nth_rec == ULINT_UNDEFINED
197 + || (slot2 + 1)->nth_rec == ULINT_UNDEFINED) {
199 + if (i > divergence_level + 1) {
200 + /* In trees whose height is > 1 our algorithm
201 + tends to underestimate: multiply the estimate
204 + n_pages = n_pages * 2;
207 + /* Do not estimate the number of rows in the range
208 + to over 1 / 2 of the estimated rows in the whole
211 + if (n_pages > index->stat_n_leaf_pages / 2) {
212 + n_pages = index->stat_n_leaf_pages / 2;
214 + /* If there are just 0 or 1 rows in the table,
215 + then we estimate all rows are in the range */
217 + if (n_pages == 0) {
218 + n_pages = index->stat_n_leaf_pages;
225 + if (!diverged && slot1->nth_rec != slot2->nth_rec) {
229 + if (slot1->nth_rec < slot2->nth_rec) {
230 + n_pages = slot2->nth_rec - slot1->nth_rec;
233 + diverged_lot = TRUE;
234 + divergence_level = i;
237 + /* Maybe the tree has changed between
243 + } else if (diverged && !diverged_lot) {
245 + if (slot1->nth_rec < slot1->n_recs
246 + || slot2->nth_rec > 1) {
248 + diverged_lot = TRUE;
249 + divergence_level = i;
253 + if (slot1->nth_rec < slot1->n_recs) {
254 + n_pages += slot1->n_recs
258 + if (slot2->nth_rec > 1) {
259 + n_pages += slot2->nth_rec - 1;
262 + } else if (diverged_lot) {
264 + n_pages = (n_pages * (slot1->n_recs + slot2->n_recs))
270 +/*******************************************************************//**
271 Estimates the number of different key values in a given index, for
272 each n-column prefix of the index where n <= dict_index_get_n_unique(index).
273 The estimates are stored in the array index->stat_n_diff_key_vals. */
274 @@ -3507,18 +3756,38 @@
275 ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
276 ulint* offsets_rec = offsets_rec_;
277 ulint* offsets_next_rec= offsets_next_rec_;
278 + ulint stats_method = srv_stats_method;
279 + btr_path_t first_rec_path[BTR_PATH_ARRAY_N_SLOTS];
280 + ulint effective_pages; /* effective leaf pages */
281 rec_offs_init(offsets_rec_);
282 rec_offs_init(offsets_next_rec_);
284 n_cols = dict_index_get_n_unique(index);
286 + if (stats_method == SRV_STATS_METHOD_IGNORE_NULLS) {
287 + /* estimate effective pages and path for the first effective record */
288 + /* TODO: make it work also for n_cols > 1. */
289 + effective_pages = btr_estimate_n_pages_not_null(index, 1 /*k*/, first_rec_path);
291 + if (!effective_pages) {
292 + for (j = 0; j <= n_cols; j++) {
293 + index->stat_n_diff_key_vals[j] = (ib_int64_t)index->stat_n_leaf_pages;
296 + } else if (effective_pages > index->stat_n_leaf_pages) {
297 + effective_pages = index->stat_n_leaf_pages;
300 + effective_pages = index->stat_n_leaf_pages;
303 n_diff = mem_zalloc((n_cols + 1) * sizeof(ib_int64_t));
305 /* It makes no sense to test more pages than are contained
306 in the index, thus we lower the number if it is too high */
307 - if (srv_stats_sample_pages > index->stat_index_size) {
308 - if (index->stat_index_size > 0) {
309 - n_sample_pages = index->stat_index_size;
310 + if (srv_stats_sample_pages > effective_pages) {
311 + if (effective_pages > 0) {
312 + n_sample_pages = effective_pages;
316 @@ -3530,9 +3799,15 @@
318 for (i = 0; i < n_sample_pages; i++) {
320 + ibool is_first_page = TRUE;
323 + if (stats_method == SRV_STATS_METHOD_IGNORE_NULLS) {
324 + is_first_page = btr_cur_open_at_rnd_pos_after_path(index, BTR_SEARCH_LEAF,
325 + first_rec_path, &cursor, &mtr);
327 btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
330 /* Count the number of different key values for each prefix of
331 the key on this index page. If the prefix does not determine
332 @@ -3543,7 +3818,13 @@
333 page = btr_cur_get_page(&cursor);
335 supremum = page_get_supremum_rec(page);
336 + if (stats_method == SRV_STATS_METHOD_IGNORE_NULLS && is_first_page) {
337 + /* the cursor should be the first record of the page. */
338 + /* Counting should be started from here. */
339 + rec = btr_cur_get_rec(&cursor);
341 rec = page_rec_get_next(page_get_infimum_rec(page));
344 if (rec != supremum) {
346 @@ -3552,7 +3833,8 @@
349 while (rec != supremum) {
350 - rec_t* next_rec = page_rec_get_next(rec);
352 + next_rec = page_rec_get_next(rec);
353 if (next_rec == supremum) {
356 @@ -3566,7 +3848,10 @@
357 cmp_rec_rec_with_match(rec, next_rec,
358 offsets_rec, offsets_next_rec,
359 index, &matched_fields,
362 + (stats_method==SRV_STATS_METHOD_NULLS_NOT_EQUAL) ?
363 + SRV_STATS_METHOD_NULLS_NOT_EQUAL :
364 + SRV_STATS_METHOD_NULLS_EQUAL);
366 for (j = matched_fields + 1; j <= n_cols; j++) {
367 /* We add one if this index record has
368 @@ -3627,7 +3912,7 @@
369 for (j = 0; j <= n_cols; j++) {
370 index->stat_n_diff_key_vals[j]
372 - * (ib_int64_t)index->stat_n_leaf_pages
373 + * (ib_int64_t)effective_pages
375 + total_external_size
377 @@ -3642,7 +3927,7 @@
378 different key values, or even more. Let us try to approximate
381 - add_on = index->stat_n_leaf_pages
382 + add_on = effective_pages
383 / (10 * (n_sample_pages
384 + total_external_size));
386 @@ -3651,6 +3936,15 @@
389 index->stat_n_diff_key_vals[j] += add_on;
391 + if (stats_method == SRV_STATS_METHOD_IGNORE_NULLS) {
392 + /* index->stat_n_diff_key_vals[k] is used for calc rec_per_key,
393 + as "stats.records / index->stat_n_diff_key_vals[x]".
394 + So it should be adjusted to the value which is based on whole of the index. */
395 + index->stat_n_diff_key_vals[j] =
396 + index->stat_n_diff_key_vals[j] * (ib_int64_t)index->stat_n_leaf_pages
397 + / (ib_int64_t)effective_pages;
402 diff -ruN a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.c
403 --- a/storage/innobase/dict/dict0boot.c 2010-12-03 15:48:03.034036843 +0900
404 +++ b/storage/innobase/dict/dict0boot.c 2010-12-03 17:19:24.835112632 +0900
406 /* Get the dictionary header */
407 dict_hdr = dict_hdr_get(&mtr);
409 + if (mach_read_from_8(dict_hdr + DICT_HDR_XTRADB_MARK)
410 + != DICT_HDR_XTRADB_FLAG) {
411 + /* not extended yet by XtraDB, need to be extended */
412 + ulint root_page_no;
414 + root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
415 + DICT_HDR_SPACE, 0, DICT_STATS_ID,
416 + dict_ind_redundant, &mtr);
417 + if (root_page_no == FIL_NULL) {
418 + fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n");
419 + srv_use_sys_stats_table = FALSE;
421 + mlog_write_ulint(dict_hdr + DICT_HDR_STATS, root_page_no,
422 + MLOG_4BYTES, &mtr);
423 + mlog_write_ull(dict_hdr + DICT_HDR_XTRADB_MARK,
424 + DICT_HDR_XTRADB_FLAG, &mtr);
429 + dict_hdr = dict_hdr_get(&mtr);
432 /* Because we only write new row ids to disk-based data structure
433 (dictionary header) when it is divisible by
434 DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover
436 table->id = DICT_FIELDS_ID;
437 dict_table_add_to_cache(table, heap);
438 dict_sys->sys_fields = table;
439 - mem_heap_free(heap);
440 + mem_heap_empty(heap);
442 index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
446 ut_a(error == DB_SUCCESS);
448 + /*-------------------------*/
449 + table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 3, 0);
450 + table->n_mysql_handles_opened = 1; /* for pin */
452 + dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
453 + dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
454 + dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
456 + /* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
457 +#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
458 +#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
461 + table->id = DICT_STATS_ID;
462 + dict_table_add_to_cache(table, heap);
463 + dict_sys->sys_stats = table;
464 + mem_heap_empty(heap);
466 + index = dict_mem_index_create("SYS_STATS", "CLUST_IND",
468 + DICT_UNIQUE | DICT_CLUSTERED, 2);
470 + dict_mem_index_add_field(index, "INDEX_ID", 0);
471 + dict_mem_index_add_field(index, "KEY_COLS", 0);
473 + index->id = DICT_STATS_ID;
474 + error = dict_index_add_to_cache(table, index,
475 + mtr_read_ulint(dict_hdr
477 + MLOG_4BYTES, &mtr),
479 + ut_a(error == DB_SUCCESS);
481 + mem_heap_free(heap);
484 /*-------------------------*/
487 dict_load_sys_table(dict_sys->sys_columns);
488 dict_load_sys_table(dict_sys->sys_indexes);
489 dict_load_sys_table(dict_sys->sys_fields);
490 + dict_load_sys_table(dict_sys->sys_stats);
492 mutex_exit(&(dict_sys->mutex));
494 diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c
495 --- a/storage/innobase/dict/dict0crea.c 2010-12-03 15:48:03.036081059 +0900
496 +++ b/storage/innobase/dict/dict0crea.c 2010-12-03 17:19:24.836964976 +0900
500 /*****************************************************************//**
501 +Based on an index object, this function builds the entry to be inserted
502 +in the SYS_STATS system table.
503 +@return the tuple which should be inserted */
506 +dict_create_sys_stats_tuple(
507 +/*========================*/
508 + const dict_index_t* index,
512 + dict_table_t* sys_stats;
520 + sys_stats = dict_sys->sys_stats;
522 + entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);
524 + dict_table_copy_types(entry, sys_stats);
526 + /* 0: INDEX_ID -----------------------*/
527 + dfield = dtuple_get_nth_field(entry, 0/*INDEX_ID*/);
528 + ptr = mem_heap_alloc(heap, 8);
529 + mach_write_to_8(ptr, index->id);
530 + dfield_set_data(dfield, ptr, 8);
531 + /* 1: KEY_COLS -----------------------*/
532 + dfield = dtuple_get_nth_field(entry, 1/*KEY_COLS*/);
533 + ptr = mem_heap_alloc(heap, 4);
534 + mach_write_to_4(ptr, i);
535 + dfield_set_data(dfield, ptr, 4);
536 + /* 4: DIFF_VALS ----------------------*/
537 + dfield = dtuple_get_nth_field(entry, 2/*DIFF_VALS*/);
538 + ptr = mem_heap_alloc(heap, 8);
539 + mach_write_to_8(ptr, 0); /* initial value is 0 */
540 + dfield_set_data(dfield, ptr, 8);
545 +/*****************************************************************//**
546 Creates the tuple with which the index entry is searched for writing the index
547 tree root page number, if such a tree is created.
548 @return the tuple for search */
552 /***************************************************************//**
553 +Builds a row for storing stats to insert.
554 +@return DB_SUCCESS */
557 +dict_build_stats_def_step(
558 +/*======================*/
561 + dict_index_t* index;
564 + index = node->index;
566 + row = dict_create_sys_stats_tuple(index, node->stats_no, node->heap);
568 + ins_node_set_new_row(node->stats_def, row);
570 + return(DB_SUCCESS);
573 +/***************************************************************//**
574 Creates an index tree for the index if it is not a member of a cluster.
575 @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
577 @@ -937,6 +1003,49 @@
578 dict_sys->sys_fields, heap);
579 node->field_def->common.parent = node;
581 + if (srv_use_sys_stats_table) {
582 + node->stats_def = ins_node_create(INS_DIRECT,
583 + dict_sys->sys_stats, heap);
584 + node->stats_def->common.parent = node;
586 + node->stats_def = NULL;
589 + node->commit_node = commit_node_create(heap);
590 + node->commit_node->common.parent = node;
595 +/*********************************************************************//**
599 +ind_insert_stats_graph_create(
600 +/*==========================*/
601 + dict_index_t* index,
606 + node = mem_heap_alloc(heap, sizeof(ind_node_t));
608 + node->common.type = QUE_NODE_INSERT_STATS;
610 + node->index = index;
612 + node->state = INDEX_BUILD_STATS_COLS;
613 + node->page_no = FIL_NULL;
614 + node->heap = mem_heap_create(256);
616 + node->ind_def = NULL;
617 + node->field_def = NULL;
619 + node->stats_def = ins_node_create(INS_DIRECT,
620 + dict_sys->sys_stats, heap);
621 + node->stats_def->common.parent = node;
622 + node->stats_no = 0;
624 node->commit_node = commit_node_create(heap);
625 node->commit_node->common.parent = node;
627 @@ -1087,6 +1196,7 @@
629 node->state = INDEX_BUILD_FIELD_DEF;
631 + node->stats_no = 0;
633 thr->run_node = node->ind_def;
635 @@ -1132,7 +1242,31 @@
639 - node->state = INDEX_CREATE_INDEX_TREE;
640 + if (srv_use_sys_stats_table
641 + && !((node->table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)) {
642 + node->state = INDEX_BUILD_STATS_COLS;
644 + node->state = INDEX_CREATE_INDEX_TREE;
647 + if (node->state == INDEX_BUILD_STATS_COLS) {
648 + if (node->stats_no <= dict_index_get_n_unique(node->index)) {
650 + err = dict_build_stats_def_step(node);
652 + if (err != DB_SUCCESS) {
654 + goto function_exit;
659 + thr->run_node = node->stats_def;
663 + node->state = INDEX_CREATE_INDEX_TREE;
667 if (node->state == INDEX_CREATE_INDEX_TREE) {
668 @@ -1178,6 +1312,66 @@
672 + thr->run_node = que_node_get_parent(node);
677 +/****************************************************************//**
681 +dict_insert_stats_step(
682 +/*===================*/
683 + que_thr_t* thr) /*!< in: query thread */
686 + ulint err = DB_ERROR;
691 + trx = thr_get_trx(thr);
693 + node = thr->run_node;
695 + if (thr->prev_node == que_node_get_parent(node)) {
696 + node->state = INDEX_BUILD_STATS_COLS;
699 + if (node->state == INDEX_BUILD_STATS_COLS) {
700 + if (node->stats_no <= dict_index_get_n_unique(node->index)) {
702 + err = dict_build_stats_def_step(node);
704 + if (err != DB_SUCCESS) {
706 + goto function_exit;
711 + thr->run_node = node->stats_def;
715 + node->state = INDEX_COMMIT_WORK;
719 + if (node->state == INDEX_COMMIT_WORK) {
721 + /* do not commit transaction here for now */
725 + trx->error_state = err;
727 + if (err == DB_SUCCESS) {
732 thr->run_node = que_node_get_parent(node);
735 diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
736 --- a/storage/innobase/dict/dict0dict.c 2010-12-03 15:48:03.040222428 +0900
737 +++ b/storage/innobase/dict/dict0dict.c 2010-12-03 17:19:24.841947690 +0900
739 print an error message and return without doing
741 dict_update_statistics(table, TRUE /* only update stats
742 - if they have not been initialized */);
743 + if they have not been initialized */, FALSE);
747 @@ -4304,6 +4304,240 @@
750 /*********************************************************************//**
751 +functions to use SYS_STATS system table. */
754 +dict_reload_statistics(
755 +/*===================*/
756 + dict_table_t* table,
757 + ulint* sum_of_index_sizes)
759 + dict_index_t* index;
763 + index = dict_table_get_first_index(table);
765 + if (index == NULL) {
766 + /* Table definition is corrupt */
771 + heap = mem_heap_create(1000);
774 + size = btr_get_size(index, BTR_TOTAL_SIZE);
776 + index->stat_index_size = size;
778 + *sum_of_index_sizes += size;
780 + size = btr_get_size(index, BTR_N_LEAF_PAGES);
783 + /* The root node of the tree is a leaf */
787 + index->stat_n_leaf_pages = size;
789 +/*===========================================*/
791 + dict_table_t* sys_stats;
792 + dict_index_t* sys_index;
801 + ib_int64_t* stat_n_diff_key_vals_tmp;
806 + n_cols = dict_index_get_n_unique(index);
807 + stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
809 + sys_stats = dict_sys->sys_stats;
810 + sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
811 + ut_a(!dict_table_is_comp(sys_stats));
813 + tuple = dtuple_create(heap, 1);
814 + dfield = dtuple_get_nth_field(tuple, 0);
816 + buf = mem_heap_alloc(heap, 8);
817 + mach_write_to_8(buf, index->id);
819 + dfield_set_data(dfield, buf, 8);
820 + dict_index_copy_types(tuple, sys_index, 1);
824 + btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
825 + BTR_SEARCH_LEAF, &pcur, &mtr);
826 + for (i = 0; i <= n_cols; i++) {
827 + rec = btr_pcur_get_rec(&pcur);
829 + if (!btr_pcur_is_on_user_rec(&pcur)
830 + || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
832 + /* not found: even 1 if not found should not be alowed */
833 + fprintf(stderr, "InnoDB: Warning: stats for %s/%s (%lu/%lu)"
834 + " not found in SYS_STATS\n",
835 + index->table_name, index->name, i, n_cols);
836 + btr_pcur_close(&pcur);
838 + mem_heap_free(heap);
842 + if (rec_get_deleted_flag(rec, 0)) {
846 + field = rec_get_nth_field_old(rec, 1, &len);
849 + key_cols = mach_read_from_4(field);
851 + ut_a(i == key_cols);
853 + field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
856 + stat_n_diff_key_vals_tmp[i] = mach_read_from_8(field);
858 + btr_pcur_move_to_next_user_rec(&pcur, &mtr);
861 + btr_pcur_close(&pcur);
864 + for (i = 0; i <= n_cols; i++) {
865 + index->stat_n_diff_key_vals[i] = stat_n_diff_key_vals_tmp[i];
868 +/*===========================================*/
870 + index = dict_table_get_next_index(index);
873 + mem_heap_free(heap);
879 +dict_store_statistics(
880 +/*==================*/
881 + dict_table_t* table)
883 + dict_index_t* index;
886 + index = dict_table_get_first_index(table);
890 + heap = mem_heap_create(1000);
893 +/*===========================================*/
895 + dict_table_t* sys_stats;
896 + dict_index_t* sys_index;
906 + ib_int64_t* stat_n_diff_key_vals_tmp;
911 + n_cols = dict_index_get_n_unique(index);
912 + stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
914 + for (i = 0; i <= n_cols; i++) {
915 + stat_n_diff_key_vals_tmp[i] = index->stat_n_diff_key_vals[i];
918 + sys_stats = dict_sys->sys_stats;
919 + sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
920 + ut_a(!dict_table_is_comp(sys_stats));
922 + tuple = dtuple_create(heap, 1);
923 + dfield = dtuple_get_nth_field(tuple, 0);
925 + buf = mem_heap_alloc(heap, 8);
926 + mach_write_to_8(buf, index->id);
928 + dfield_set_data(dfield, buf, 8);
929 + dict_index_copy_types(tuple, sys_index, 1);
933 + btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
934 + BTR_MODIFY_LEAF, &pcur, &mtr);
935 + rests = n_cols + 1;
936 + for (i = 0; i <= n_cols; i++) {
937 + rec = btr_pcur_get_rec(&pcur);
939 + if (!btr_pcur_is_on_user_rec(&pcur)
940 + || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
948 + if (rec_get_deleted_flag(rec, 0)) {
952 + field = rec_get_nth_field_old(rec, 1, &len);
955 + key_cols = mach_read_from_4(field);
957 + field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
960 + mlog_write_ull((byte*)field, stat_n_diff_key_vals_tmp[key_cols], &mtr);
965 + btr_pcur_move_to_next_user_rec(&pcur, &mtr);
967 + btr_pcur_close(&pcur);
971 + fprintf(stderr, "InnoDB: Warning: failed to store %lu stats entries"
972 + " of %s/%s to SYS_STATS system table.\n",
973 + rests, index->table_name, index->name);
976 +/*===========================================*/
978 + index = dict_table_get_next_index(index);
981 + mem_heap_free(heap);
984 +/*********************************************************************//**
985 Calculates new estimates for table and index statistics. The statistics
986 are used in query optimization. */
988 @@ -4311,10 +4545,11 @@
989 dict_update_statistics(
990 /*===================*/
991 dict_table_t* table, /*!< in/out: table */
992 - ibool only_calc_if_missing_stats)/*!< in: only
993 + ibool only_calc_if_missing_stats,/*!< in: only
994 update/recalc the stats if they have
995 not been initialized yet, otherwise
997 + ibool sync) /*!< in: TRUE if must update SYS_STATS */
1000 ulint sum_of_index_sizes = 0;
1001 @@ -4331,6 +4566,27 @@
1005 + if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) && !sync) {
1006 + dict_table_stats_lock(table, RW_X_LATCH);
1008 + /* reload statistics from SYS_STATS table */
1009 + if (dict_reload_statistics(table, &sum_of_index_sizes)) {
1012 + fprintf(stderr, "InnoDB: DEBUG: reload_statistics succeeded for %s.\n",
1018 + dict_table_stats_unlock(table, RW_X_LATCH);
1021 + fprintf(stderr, "InnoDB: DEBUG: update_statistics for %s.\n",
1024 + sum_of_index_sizes = 0;
1026 /* Find out the sizes of the indexes and how many different values
1027 for the key they approximately have */
1029 @@ -4391,6 +4647,11 @@
1030 index = dict_table_get_next_index(index);
1033 + if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)) {
1034 + /* store statistics to SYS_STATS table */
1035 + dict_store_statistics(table);
1038 index = dict_table_get_first_index(table);
1040 table->stat_n_rows = index->stat_n_diff_key_vals[
1041 @@ -4485,7 +4746,8 @@
1043 ut_ad(mutex_own(&(dict_sys->mutex)));
1045 - dict_update_statistics(table, FALSE /* update even if initialized */);
1046 + if (srv_stats_auto_update)
1047 + dict_update_statistics(table, FALSE /* update even if initialized */, FALSE);
1049 dict_table_stats_lock(table, RW_S_LATCH);
1051 diff -ruN a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c
1052 --- a/storage/innobase/dict/dict0load.c 2010-11-03 07:01:13.000000000 +0900
1053 +++ b/storage/innobase/dict/dict0load.c 2010-12-03 17:19:24.845947460 +0900
1058 - "SYS_FOREIGN_COLS"
1059 + "SYS_FOREIGN_COLS",
1062 /****************************************************************//**
1063 Compare the name of an index column.
1064 @@ -343,12 +344,13 @@
1067 if ((status & DICT_TABLE_UPDATE_STATS)
1068 + && srv_stats_auto_update
1069 && dict_table_get_first_index(*table)) {
1071 /* Update statistics if DICT_TABLE_UPDATE_STATS
1073 dict_update_statistics(*table, FALSE /* update even if
1075 + initialized */, FALSE);
1079 @@ -582,6 +584,61 @@
1080 //#endif /* FOREIGN_NOT_USED */
1082 /********************************************************************//**
1083 +This function parses a SYS_STATS record and extract necessary
1084 +information from the record and return to caller.
1085 +@return error message, or NULL on success */
1088 +dict_process_sys_stats_rec(
1089 +/*=============================*/
1090 + mem_heap_t* heap __attribute__((unused)), /*!< in/out: heap memory */
1091 + const rec_t* rec, /*!< in: current SYS_STATS rec */
1092 + index_id_t* index_id, /*!< out: INDEX_ID */
1093 + ulint* key_cols, /*!< out: KEY_COLS */
1094 + ib_uint64_t* diff_vals) /*!< out: DIFF_VALS */
1097 + const byte* field;
1099 + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1100 + return("delete-marked record in SYS_STATS");
1103 + if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
1104 + return("wrong number of columns in SYS_STATS record");
1107 + field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
1108 + if (UNIV_UNLIKELY(len != 8)) {
1110 + return("incorrect column length in SYS_STATS");
1112 + *index_id = mach_read_from_8(field);
1114 + field = rec_get_nth_field_old(rec, 1/*KEY_COLS*/, &len);
1115 + if (UNIV_UNLIKELY(len != 4)) {
1118 + *key_cols = mach_read_from_4(field);
1120 + rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
1121 + if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
1124 + rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
1125 + if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
1129 + field = rec_get_nth_field_old(rec, 4/*DIFF_VALS*/, &len);
1130 + if (UNIV_UNLIKELY(len != 8)) {
1133 + *diff_vals = mach_read_from_8(field);
1137 +/********************************************************************//**
1138 Determine the flags of a table described in SYS_TABLES.
1139 @return compressed page size in kilobytes; or 0 if the tablespace is
1140 uncompressed, ULINT_UNDEFINED on error */
1141 diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
1142 --- a/storage/innobase/handler/ha_innodb.cc 2010-12-03 17:17:03.665960357 +0900
1143 +++ b/storage/innobase/handler/ha_innodb.cc 2010-12-03 17:22:21.586939783 +0900
1145 static my_bool innobase_rollback_on_timeout = FALSE;
1146 static my_bool innobase_create_status_file = FALSE;
1147 static my_bool innobase_stats_on_metadata = TRUE;
1148 +static my_bool innobase_use_sys_stats_table = FALSE;
1151 static char* internal_innobase_data_file_path = NULL;
1152 @@ -2388,6 +2389,8 @@
1156 + srv_use_sys_stats_table = (ibool) innobase_use_sys_stats_table;
1158 /* -------------- Log files ---------------------------*/
1160 /* The default dir for log files is the datadir of MySQL */
1161 @@ -5192,6 +5195,10 @@
1163 error = row_insert_for_mysql((byte*) record, prebuilt);
1165 +#ifdef EXTENDED_FOR_USERSTAT
1166 + if (error == DB_SUCCESS) rows_changed++;
1169 /* Handle duplicate key errors */
1170 if (auto_inc_used) {
1172 @@ -5528,6 +5535,10 @@
1176 +#ifdef EXTENDED_FOR_USERSTAT
1177 + if (error == DB_SUCCESS) rows_changed++;
1180 innodb_srv_conc_exit_innodb(trx);
1182 error = convert_error_code_to_mysql(error,
1183 @@ -5581,6 +5592,10 @@
1185 error = row_update_for_mysql((byte*) record, prebuilt);
1187 +#ifdef EXTENDED_FOR_USERSTAT
1188 + if (error == DB_SUCCESS) rows_changed++;
1191 innodb_srv_conc_exit_innodb(trx);
1193 error = convert_error_code_to_mysql(
1194 @@ -5899,6 +5914,11 @@
1198 +#ifdef EXTENDED_FOR_USERSTAT
1200 + if (active_index >= 0 && active_index < MAX_KEY)
1201 + index_rows_read[active_index]++;
1204 case DB_RECORD_NOT_FOUND:
1205 error = HA_ERR_KEY_NOT_FOUND;
1206 @@ -6108,6 +6128,11 @@
1210 +#ifdef EXTENDED_FOR_USERSTAT
1212 + if (active_index >= 0 && active_index < MAX_KEY)
1213 + index_rows_read[active_index]++;
1216 case DB_RECORD_NOT_FOUND:
1217 error = HA_ERR_END_OF_FILE;
1218 @@ -7999,11 +8024,31 @@
1219 /* In sql_show we call with this flag: update
1220 then statistics so that they are up-to-date */
1222 + if (srv_use_sys_stats_table && !((ib_table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)
1223 + && called_from_analyze) {
1224 + /* If the indexes on the table don't have enough rows in SYS_STATS system table, */
1225 + /* they need to be created. */
1226 + dict_index_t* index;
1228 + prebuilt->trx->op_info = "confirming rows of SYS_STATS to store statistics";
1230 + ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
1232 + for (index = dict_table_get_first_index(ib_table);
1234 + index = dict_table_get_next_index(index)) {
1235 + row_insert_stats_for_mysql(index, prebuilt->trx);
1236 + innobase_commit_low(prebuilt->trx);
1239 + ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
1242 prebuilt->trx->op_info = "updating table statistics";
1244 dict_update_statistics(ib_table,
1245 FALSE /* update even if stats
1246 - are initialized */);
1247 + are initialized */, called_from_analyze);
1249 prebuilt->trx->op_info = "returning various info to MySQL";
1251 @@ -8081,7 +8126,7 @@
1252 are asked by MySQL to avoid locking. Another reason to
1253 avoid the call is that it uses quite a lot of CPU.
1255 - if (flag & HA_STATUS_NO_LOCK
1256 + if (flag & HA_STATUS_NO_LOCK || !srv_stats_update_need_lock
1257 || !(flag & HA_STATUS_VARIABLE_EXTRA)) {
1258 /* We do not update delete_length if no
1259 locking is requested so the "old" value can
1260 @@ -11281,6 +11326,45 @@
1261 "The number of index pages to sample when calculating statistics (default 8)",
1262 NULL, NULL, 8, 1, ~0ULL, 0);
1264 +const char *innobase_stats_method_names[]=
1271 +TYPELIB innobase_stats_method_typelib=
1273 + array_elements(innobase_stats_method_names) - 1, "innobase_stats_method_typelib",
1274 + innobase_stats_method_names, NULL
1276 +static MYSQL_SYSVAR_ENUM(stats_method, srv_stats_method,
1277 + PLUGIN_VAR_RQCMDARG,
1278 + "Specifies how InnoDB index statistics collection code should threat NULLs. "
1279 + "Possible values of name are same to for 'myisam_stats_method'. "
1280 + "This is startup parameter.",
1281 + NULL, NULL, 0, &innobase_stats_method_typelib);
1283 +static MYSQL_SYSVAR_ULONG(stats_auto_update, srv_stats_auto_update,
1284 + PLUGIN_VAR_RQCMDARG,
1285 + "Enable/Disable InnoDB's auto update statistics of indexes. "
1286 + "(except for ANALYZE TABLE command) 0:disable 1:enable",
1287 + NULL, NULL, 1, 0, 1, 0);
1289 +static MYSQL_SYSVAR_ULONG(stats_update_need_lock, srv_stats_update_need_lock,
1290 + PLUGIN_VAR_RQCMDARG,
1291 + "Enable/Disable InnoDB's update statistics which needs to lock dictionary. "
1292 + "e.g. Data_free.",
1293 + NULL, NULL, 1, 0, 1, 0);
1295 +static MYSQL_SYSVAR_BOOL(use_sys_stats_table, innobase_use_sys_stats_table,
1296 + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
1297 + "Enable to use SYS_STATS system table to store statistics statically, "
1298 + "And avoids to calculate statistics at every first open of the tables. "
1299 + "This option may make the opportunities of update statistics less. "
1300 + "So you should use ANALYZE TABLE command intentionally.",
1301 + NULL, NULL, FALSE);
1303 static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
1304 PLUGIN_VAR_OPCMDARG,
1305 "Enable InnoDB adaptive hash index (enabled by default). "
1306 @@ -11604,6 +11688,10 @@
1307 MYSQL_SYSVAR(overwrite_relay_log_info),
1308 MYSQL_SYSVAR(rollback_on_timeout),
1309 MYSQL_SYSVAR(stats_on_metadata),
1310 + MYSQL_SYSVAR(stats_method),
1311 + MYSQL_SYSVAR(stats_auto_update),
1312 + MYSQL_SYSVAR(stats_update_need_lock),
1313 + MYSQL_SYSVAR(use_sys_stats_table),
1314 MYSQL_SYSVAR(stats_sample_pages),
1315 MYSQL_SYSVAR(adaptive_hash_index),
1316 MYSQL_SYSVAR(replication_delay),
1317 @@ -11672,7 +11760,10 @@
1318 i_s_innodb_sys_columns,
1319 i_s_innodb_sys_fields,
1320 i_s_innodb_sys_foreign,
1321 -i_s_innodb_sys_foreign_cols
1322 +i_s_innodb_sys_foreign_cols,
1323 +i_s_innodb_sys_stats,
1324 +i_s_innodb_table_stats,
1325 +i_s_innodb_index_stats
1326 mysql_declare_plugin_end;
1328 /** @brief Initialize the default value of innodb_commit_concurrency.
1329 diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
1330 --- a/storage/innobase/handler/i_s.cc 2010-12-03 17:17:03.666956117 +0900
1331 +++ b/storage/innobase/handler/i_s.cc 2010-12-03 17:19:24.880964526 +0900
1333 #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
1334 #include "trx0rseg.h" /* for trx_rseg_struct */
1335 #include "trx0sys.h" /* for trx_sys */
1336 +#include "dict0dict.h" /* for dict_sys */
1339 static const char plugin_author[] = "Innobase Oy";
1340 @@ -3457,6 +3458,203 @@
1341 STRUCT_FLD(__reserved1, NULL)
1344 +/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_stats */
1345 +static ST_FIELD_INFO innodb_sys_stats_fields_info[] =
1347 +#define SYS_STATS_INDEX_ID 0
1348 + {STRUCT_FLD(field_name, "INDEX_ID"),
1349 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1350 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1351 + STRUCT_FLD(value, 0),
1352 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1353 + STRUCT_FLD(old_name, ""),
1354 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1356 +#define SYS_STATS_KEY_COLS 1
1357 + {STRUCT_FLD(field_name, "KEY_COLS"),
1358 + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
1359 + STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
1360 + STRUCT_FLD(value, 0),
1361 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1362 + STRUCT_FLD(old_name, ""),
1363 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1365 +#define SYS_STATS_DIFF_VALS 2
1366 + {STRUCT_FLD(field_name, "DIFF_VALS"),
1367 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1368 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1369 + STRUCT_FLD(value, 0),
1370 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1371 + STRUCT_FLD(old_name, ""),
1372 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1374 + END_OF_ST_FIELD_INFO
1376 +/**********************************************************************//**
1377 +Function to fill information_schema.innodb_sys_stats
1378 +@return 0 on success */
1381 +i_s_dict_fill_sys_stats(
1382 +/*====================*/
1383 + THD* thd, /*!< in: thread */
1384 + index_id_t index_id, /*!< in: INDEX_ID */
1385 + ulint key_cols, /*!< in: KEY_COLS */
1386 + ib_uint64_t diff_vals, /*!< in: DIFF_VALS */
1387 + TABLE* table_to_fill) /*!< in/out: fill this table */
1391 + DBUG_ENTER("i_s_dict_fill_sys_stats");
1393 + fields = table_to_fill->field;
1395 + OK(fields[SYS_STATS_INDEX_ID]->store(longlong(index_id), TRUE));
1397 + OK(fields[SYS_STATS_KEY_COLS]->store(key_cols));
1399 + OK(fields[SYS_STATS_DIFF_VALS]->store(longlong(diff_vals), TRUE));
1401 + OK(schema_table_store_record(thd, table_to_fill));
1405 +/*******************************************************************//**
1406 +Function to populate INFORMATION_SCHEMA.innodb_sys_stats table.
1407 +@return 0 on success */
1410 +i_s_sys_stats_fill_table(
1411 +/*=====================*/
1412 + THD* thd, /*!< in: thread */
1413 + TABLE_LIST* tables, /*!< in/out: tables to fill */
1414 + COND* cond) /*!< in: condition (not used) */
1421 + DBUG_ENTER("i_s_sys_stats_fill_table");
1423 + /* deny access to non-superusers */
1424 + if (check_global_access(thd, PROCESS_ACL)) {
1428 + heap = mem_heap_create(1000);
1429 + mutex_enter(&dict_sys->mutex);
1432 + rec = dict_startscan_system(&pcur, &mtr, SYS_STATS);
1435 + const char* err_msg;
1436 + index_id_t index_id;
1438 + ib_uint64_t diff_vals;
1440 + /* Extract necessary information from a SYS_FOREIGN_COLS row */
1441 + err_msg = dict_process_sys_stats_rec(
1442 + heap, rec, &index_id, &key_cols, &diff_vals);
1445 + mutex_exit(&dict_sys->mutex);
1448 + i_s_dict_fill_sys_stats(
1449 + thd, index_id, key_cols, diff_vals,
1452 + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
1453 + ER_CANT_FIND_SYSTEM_REC,
1457 + mem_heap_empty(heap);
1459 + /* Get the next record */
1460 + mutex_enter(&dict_sys->mutex);
1462 + rec = dict_getnext_system(&pcur, &mtr);
1466 + mutex_exit(&dict_sys->mutex);
1467 + mem_heap_free(heap);
1471 +/*******************************************************************//**
1472 +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_stats
1473 +@return 0 on success */
1476 +innodb_sys_stats_init(
1477 +/*========================*/
1478 + void* p) /*!< in/out: table schema object */
1480 + ST_SCHEMA_TABLE* schema;
1482 + DBUG_ENTER("innodb_sys_stats_init");
1484 + schema = (ST_SCHEMA_TABLE*) p;
1486 + schema->fields_info = innodb_sys_stats_fields_info;
1487 + schema->fill_table = i_s_sys_stats_fill_table;
1492 +UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_stats =
1494 + /* the plugin type (a MYSQL_XXX_PLUGIN value) */
1496 + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1498 + /* pointer to type-specific plugin descriptor */
1500 + STRUCT_FLD(info, &i_s_info),
1504 + STRUCT_FLD(name, "INNODB_SYS_STATS"),
1506 + /* plugin author (for SHOW PLUGINS) */
1508 + STRUCT_FLD(author, plugin_author),
1510 + /* general descriptive text (for SHOW PLUGINS) */
1512 + STRUCT_FLD(descr, "XtraDB SYS_STATS table"),
1514 + /* the plugin license (PLUGIN_LICENSE_XXX) */
1516 + STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1518 + /* the function to invoke when plugin is loaded */
1519 + /* int (*)(void*); */
1520 + STRUCT_FLD(init, innodb_sys_stats_init),
1522 + /* the function to invoke when plugin is unloaded */
1523 + /* int (*)(void*); */
1524 + STRUCT_FLD(deinit, i_s_common_deinit),
1526 + /* plugin version (for SHOW PLUGINS) */
1527 + /* unsigned int */
1528 + STRUCT_FLD(version, INNODB_VERSION_SHORT),
1530 + /* struct st_mysql_show_var* */
1531 + STRUCT_FLD(status_vars, NULL),
1533 + /* struct st_mysql_sys_var** */
1534 + STRUCT_FLD(system_vars, NULL),
1536 + /* reserved for dependency checking */
1538 + STRUCT_FLD(__reserved1, NULL)
1541 /***********************************************************************
1543 static ST_FIELD_INFO i_s_innodb_rseg_fields_info[] =
1544 @@ -3619,3 +3817,347 @@
1546 STRUCT_FLD(__reserved1, NULL)
1549 +/***********************************************************************
1551 +static ST_FIELD_INFO i_s_innodb_table_stats_info[] =
1553 + {STRUCT_FLD(field_name, "table_schema"),
1554 + STRUCT_FLD(field_length, NAME_LEN),
1555 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1556 + STRUCT_FLD(value, 0),
1557 + STRUCT_FLD(field_flags, 0),
1558 + STRUCT_FLD(old_name, ""),
1559 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1561 + {STRUCT_FLD(field_name, "table_name"),
1562 + STRUCT_FLD(field_length, NAME_LEN),
1563 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1564 + STRUCT_FLD(value, 0),
1565 + STRUCT_FLD(field_flags, 0),
1566 + STRUCT_FLD(old_name, ""),
1567 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1569 + {STRUCT_FLD(field_name, "rows"),
1570 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1571 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1572 + STRUCT_FLD(value, 0),
1573 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1574 + STRUCT_FLD(old_name, ""),
1575 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1577 + {STRUCT_FLD(field_name, "clust_size"),
1578 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1579 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1580 + STRUCT_FLD(value, 0),
1581 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1582 + STRUCT_FLD(old_name, ""),
1583 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1585 + {STRUCT_FLD(field_name, "other_size"),
1586 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1587 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1588 + STRUCT_FLD(value, 0),
1589 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1590 + STRUCT_FLD(old_name, ""),
1591 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1593 + {STRUCT_FLD(field_name, "modified"),
1594 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1595 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1596 + STRUCT_FLD(value, 0),
1597 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1598 + STRUCT_FLD(old_name, ""),
1599 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1601 + END_OF_ST_FIELD_INFO
1604 +static ST_FIELD_INFO i_s_innodb_index_stats_info[] =
1606 + {STRUCT_FLD(field_name, "table_schema"),
1607 + STRUCT_FLD(field_length, NAME_LEN),
1608 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1609 + STRUCT_FLD(value, 0),
1610 + STRUCT_FLD(field_flags, 0),
1611 + STRUCT_FLD(old_name, ""),
1612 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1614 + {STRUCT_FLD(field_name, "table_name"),
1615 + STRUCT_FLD(field_length, NAME_LEN),
1616 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1617 + STRUCT_FLD(value, 0),
1618 + STRUCT_FLD(field_flags, 0),
1619 + STRUCT_FLD(old_name, ""),
1620 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1622 + {STRUCT_FLD(field_name, "index_name"),
1623 + STRUCT_FLD(field_length, NAME_LEN),
1624 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1625 + STRUCT_FLD(value, 0),
1626 + STRUCT_FLD(field_flags, 0),
1627 + STRUCT_FLD(old_name, ""),
1628 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1630 + {STRUCT_FLD(field_name, "fields"),
1631 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1632 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1633 + STRUCT_FLD(value, 0),
1634 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1635 + STRUCT_FLD(old_name, ""),
1636 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1638 + {STRUCT_FLD(field_name, "rows_per_key"),
1639 + STRUCT_FLD(field_length, 256),
1640 + STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1641 + STRUCT_FLD(value, 0),
1642 + STRUCT_FLD(field_flags, 0),
1643 + STRUCT_FLD(old_name, ""),
1644 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1646 + {STRUCT_FLD(field_name, "index_total_pages"),
1647 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1648 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1649 + STRUCT_FLD(value, 0),
1650 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1651 + STRUCT_FLD(old_name, ""),
1652 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1654 + {STRUCT_FLD(field_name, "index_leaf_pages"),
1655 + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1656 + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1657 + STRUCT_FLD(value, 0),
1658 + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1659 + STRUCT_FLD(old_name, ""),
1660 + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1662 + END_OF_ST_FIELD_INFO
1667 +i_s_innodb_table_stats_fill(
1668 +/*========================*/
1670 + TABLE_LIST* tables,
1673 + TABLE* i_s_table = (TABLE *) tables->table;
1675 + dict_table_t* table;
1677 + DBUG_ENTER("i_s_innodb_table_stats_fill");
1679 + /* deny access to non-superusers */
1680 + if (check_global_access(thd, PROCESS_ACL)) {
1684 + mutex_enter(&(dict_sys->mutex));
1686 + table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1689 + char buf[NAME_LEN * 2 + 2];
1692 + if (table->stat_clustered_index_size == 0) {
1693 + table = UT_LIST_GET_NEXT(table_LRU, table);
1697 + buf[NAME_LEN * 2 + 1] = 0;
1698 + strncpy(buf, table->name, NAME_LEN * 2 + 1);
1699 + ptr = strchr(buf, '/');
1707 + field_store_string(i_s_table->field[0], buf);
1708 + field_store_string(i_s_table->field[1], ptr);
1709 + i_s_table->field[2]->store(table->stat_n_rows);
1710 + i_s_table->field[3]->store(table->stat_clustered_index_size);
1711 + i_s_table->field[4]->store(table->stat_sum_of_other_index_sizes);
1712 + i_s_table->field[5]->store(table->stat_modified_counter);
1714 + if (schema_table_store_record(thd, i_s_table)) {
1719 + table = UT_LIST_GET_NEXT(table_LRU, table);
1722 + mutex_exit(&(dict_sys->mutex));
1724 + DBUG_RETURN(status);
1729 +i_s_innodb_index_stats_fill(
1730 +/*========================*/
1732 + TABLE_LIST* tables,
1735 + TABLE* i_s_table = (TABLE *) tables->table;
1737 + dict_table_t* table;
1738 + dict_index_t* index;
1740 + DBUG_ENTER("i_s_innodb_index_stats_fill");
1742 + /* deny access to non-superusers */
1743 + if (check_global_access(thd, PROCESS_ACL)) {
1747 + mutex_enter(&(dict_sys->mutex));
1749 + table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1752 + if (table->stat_clustered_index_size == 0) {
1753 + table = UT_LIST_GET_NEXT(table_LRU, table);
1757 + ib_int64_t n_rows = table->stat_n_rows;
1763 + index = dict_table_get_first_index(table);
1767 + char row_per_keys[256+1];
1768 + char buf[NAME_LEN * 2 + 2];
1772 + buf[NAME_LEN * 2 + 1] = 0;
1773 + strncpy(buf, table->name, NAME_LEN * 2 + 1);
1774 + ptr = strchr(buf, '/');
1782 + field_store_string(i_s_table->field[0], buf);
1783 + field_store_string(i_s_table->field[1], ptr);
1784 + field_store_string(i_s_table->field[2], index->name);
1785 + i_s_table->field[3]->store(index->n_uniq);
1787 + row_per_keys[0] = '\0';
1789 + /* It is remained optimistic operation still for now */
1790 + //dict_index_stat_mutex_enter(index);
1791 + if (index->stat_n_diff_key_vals) {
1792 + for (i = 1; i <= index->n_uniq; i++) {
1793 + ib_int64_t rec_per_key;
1794 + if (index->stat_n_diff_key_vals[i]) {
1795 + rec_per_key = n_rows / index->stat_n_diff_key_vals[i];
1797 + rec_per_key = n_rows;
1799 + ut_snprintf(buff, 256, (i == index->n_uniq)?"%llu":"%llu, ",
1801 + strncat(row_per_keys, buff, 256 - strlen(row_per_keys));
1804 + //dict_index_stat_mutex_exit(index);
1806 + field_store_string(i_s_table->field[4], row_per_keys);
1808 + i_s_table->field[5]->store(index->stat_index_size);
1809 + i_s_table->field[6]->store(index->stat_n_leaf_pages);
1811 + if (schema_table_store_record(thd, i_s_table)) {
1816 + index = dict_table_get_next_index(index);
1819 + if (status == 1) {
1823 + table = UT_LIST_GET_NEXT(table_LRU, table);
1826 + mutex_exit(&(dict_sys->mutex));
1828 + DBUG_RETURN(status);
1833 +i_s_innodb_table_stats_init(
1834 +/*========================*/
1837 + DBUG_ENTER("i_s_innodb_table_stats_init");
1838 + ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1840 + schema->fields_info = i_s_innodb_table_stats_info;
1841 + schema->fill_table = i_s_innodb_table_stats_fill;
1848 +i_s_innodb_index_stats_init(
1849 +/*========================*/
1852 + DBUG_ENTER("i_s_innodb_index_stats_init");
1853 + ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1855 + schema->fields_info = i_s_innodb_index_stats_info;
1856 + schema->fill_table = i_s_innodb_index_stats_fill;
1861 +UNIV_INTERN struct st_mysql_plugin i_s_innodb_table_stats =
1863 + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1864 + STRUCT_FLD(info, &i_s_info),
1865 + STRUCT_FLD(name, "INNODB_TABLE_STATS"),
1866 + STRUCT_FLD(author, plugin_author),
1867 + STRUCT_FLD(descr, "InnoDB table statistics in memory"),
1868 + STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1869 + STRUCT_FLD(init, i_s_innodb_table_stats_init),
1870 + STRUCT_FLD(deinit, i_s_common_deinit),
1871 + STRUCT_FLD(version, 0x0100 /* 1.0 */),
1872 + STRUCT_FLD(status_vars, NULL),
1873 + STRUCT_FLD(system_vars, NULL),
1874 + STRUCT_FLD(__reserved1, NULL)
1877 +UNIV_INTERN struct st_mysql_plugin i_s_innodb_index_stats =
1879 + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1880 + STRUCT_FLD(info, &i_s_info),
1881 + STRUCT_FLD(name, "INNODB_INDEX_STATS"),
1882 + STRUCT_FLD(author, plugin_author),
1883 + STRUCT_FLD(descr, "InnoDB index statistics in memory"),
1884 + STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1885 + STRUCT_FLD(init, i_s_innodb_index_stats_init),
1886 + STRUCT_FLD(deinit, i_s_common_deinit),
1887 + STRUCT_FLD(version, 0x0100 /* 1.0 */),
1888 + STRUCT_FLD(status_vars, NULL),
1889 + STRUCT_FLD(system_vars, NULL),
1890 + STRUCT_FLD(__reserved1, NULL)
1892 diff -ruN a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h
1893 --- a/storage/innobase/handler/i_s.h 2010-12-03 17:17:03.668953884 +0900
1894 +++ b/storage/innobase/handler/i_s.h 2010-12-03 17:19:24.882947826 +0900
1896 extern struct st_mysql_plugin i_s_innodb_sys_foreign;
1897 extern struct st_mysql_plugin i_s_innodb_sys_foreign_cols;
1898 extern struct st_mysql_plugin i_s_innodb_rseg;
1899 +extern struct st_mysql_plugin i_s_innodb_sys_stats;
1900 +extern struct st_mysql_plugin i_s_innodb_table_stats;
1901 +extern struct st_mysql_plugin i_s_innodb_index_stats;
1904 diff -ruN a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h
1905 --- a/storage/innobase/include/dict0boot.h 2010-11-03 07:01:13.000000000 +0900
1906 +++ b/storage/innobase/include/dict0boot.h 2010-12-03 17:19:24.885947372 +0900
1908 #define DICT_COLUMNS_ID 2
1909 #define DICT_INDEXES_ID 3
1910 #define DICT_FIELDS_ID 4
1911 +#define DICT_STATS_ID 6
1912 /* The following is a secondary index on SYS_TABLES */
1913 #define DICT_TABLE_IDS_ID 5
1915 @@ -131,10 +132,13 @@
1916 #define DICT_HDR_INDEXES 44 /* Root of the index index tree */
1917 #define DICT_HDR_FIELDS 48 /* Root of the index field
1919 +#define DICT_HDR_STATS 52 /* Root of the stats tree */
1921 #define DICT_HDR_FSEG_HEADER 56 /* Segment header for the tablespace
1922 segment into which the dictionary
1923 header is created */
1925 +#define DICT_HDR_XTRADB_MARK 256 /* Flag to distinguish expansion of XtraDB */
1926 /*-------------------------------------------------------------*/
1928 /* The field number of the page number field in the sys_indexes table
1929 @@ -144,11 +148,15 @@
1930 #define DICT_SYS_INDEXES_TYPE_FIELD 6
1931 #define DICT_SYS_INDEXES_NAME_FIELD 4
1933 +#define DICT_SYS_STATS_DIFF_VALS_FIELD 4
1935 /* When a row id which is zero modulo this number (which must be a power of
1936 two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is
1938 #define DICT_HDR_ROW_ID_WRITE_MARGIN 256
1940 +#define DICT_HDR_XTRADB_FLAG 0x5854524144425F31ULL /* "XTRADB_1" */
1943 #include "dict0boot.ic"
1945 diff -ruN a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h
1946 --- a/storage/innobase/include/dict0crea.h 2010-11-03 07:01:13.000000000 +0900
1947 +++ b/storage/innobase/include/dict0crea.h 2010-12-03 17:19:24.886949643 +0900
1949 dict_index_t* index, /*!< in: index to create, built as a memory data
1951 mem_heap_t* heap); /*!< in: heap where created */
1952 +/*********************************************************************//**
1956 +ind_insert_stats_graph_create(
1957 +/*==========================*/
1958 + dict_index_t* index,
1959 + mem_heap_t* heap);
1960 /***********************************************************//**
1961 Creates a table. This is a high-level function used in SQL execution graphs.
1962 @return query thread to run next or NULL */
1964 /*===================*/
1965 que_thr_t* thr); /*!< in: query thread */
1966 /***********************************************************//**
1970 +dict_insert_stats_step(
1971 +/*===================*/
1973 +/***********************************************************//**
1974 Creates an index. This is a high-level function used in SQL execution
1976 @return query thread to run next or NULL */
1978 ins_node_t* field_def; /* child node which does the inserts of
1979 the field definitions; the row to be inserted
1980 is built by the parent node */
1981 + ins_node_t* stats_def;
1982 commit_node_t* commit_node;
1983 /* child node which performs a commit after
1984 a successful index creation */
1986 dict_table_t* table; /*!< table which owns the index */
1987 dtuple_t* ind_row;/* index definition row built */
1988 ulint field_no;/* next field definition to insert */
1990 mem_heap_t* heap; /*!< memory heap used as auxiliary storage */
1994 #define INDEX_CREATE_INDEX_TREE 3
1995 #define INDEX_COMMIT_WORK 4
1996 #define INDEX_ADD_TO_CACHE 5
1997 +#define INDEX_BUILD_STATS_COLS 6
2000 #include "dict0crea.ic"
2001 diff -ruN a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
2002 --- a/storage/innobase/include/dict0dict.h 2010-12-03 15:48:03.073024387 +0900
2003 +++ b/storage/innobase/include/dict0dict.h 2010-12-03 17:19:24.888965622 +0900
2004 @@ -1084,10 +1084,11 @@
2005 dict_update_statistics(
2006 /*===================*/
2007 dict_table_t* table, /*!< in/out: table */
2008 - ibool only_calc_if_missing_stats);/*!< in: only
2009 + ibool only_calc_if_missing_stats, /*!< in: only
2010 update/recalc the stats if they have
2011 not been initialized yet, otherwise
2014 /********************************************************************//**
2015 Reserves the dictionary system mutex for MySQL. */
2017 @@ -1202,6 +1203,7 @@
2018 dict_table_t* sys_columns; /*!< SYS_COLUMNS table */
2019 dict_table_t* sys_indexes; /*!< SYS_INDEXES table */
2020 dict_table_t* sys_fields; /*!< SYS_FIELDS table */
2021 + dict_table_t* sys_stats; /*!< SYS_STATS table */
2023 #endif /* !UNIV_HOTBACKUP */
2025 diff -ruN a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h
2026 --- a/storage/innobase/include/dict0load.h 2010-11-03 07:01:13.000000000 +0900
2027 +++ b/storage/innobase/include/dict0load.h 2010-12-03 17:19:24.889947481 +0900
2034 /* This must be last item. Defines the number of system tables. */
2035 SYS_NUM_SYSTEM_TABLES
2036 @@ -319,6 +320,19 @@
2037 const char** ref_col_name, /*!< out: referenced column name
2038 in referenced table */
2039 ulint* pos); /*!< out: column position */
2040 +/********************************************************************//**
2041 +This function parses a SYS_STATS record and extract necessary
2042 +information from the record and return to caller.
2043 +@return error message, or NULL on success */
2046 +dict_process_sys_stats_rec(
2047 +/*=============================*/
2048 + mem_heap_t* heap, /*!< in/out: heap memory */
2049 + const rec_t* rec, /*!< in: current SYS_STATS rec */
2050 + index_id_t* index_id, /*!< out: INDEX_ID */
2051 + ulint* key_cols, /*!< out: KEY_COLS */
2052 + ib_uint64_t* diff_vals); /*!< out: DIFF_VALS */
2054 #include "dict0load.ic"
2056 diff -ruN a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h
2057 --- a/storage/innobase/include/page0cur.h 2010-11-03 07:01:13.000000000 +0900
2058 +++ b/storage/innobase/include/page0cur.h 2010-12-03 17:19:24.891954511 +0900
2059 @@ -293,6 +293,22 @@
2060 /*==========================*/
2061 buf_block_t* block, /*!< in: page */
2062 page_cur_t* cursor);/*!< out: page cursor */
2066 +page_cur_open_on_nth_user_rec(
2067 +/*==========================*/
2068 + buf_block_t* block, /*!< in: page */
2069 + page_cur_t* cursor, /*!< out: page cursor */
2074 +page_cur_open_on_rnd_user_rec_after_nth(
2075 +/*==========================*/
2076 + buf_block_t* block, /*!< in: page */
2077 + page_cur_t* cursor, /*!< out: page cursor */
2079 #endif /* !UNIV_HOTBACKUP */
2080 /***********************************************************//**
2081 Parses a log record of a record insert on a page.
2082 diff -ruN a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h
2083 --- a/storage/innobase/include/que0que.h 2010-11-03 07:01:13.000000000 +0900
2084 +++ b/storage/innobase/include/que0que.h 2010-12-03 17:19:24.892947946 +0900
2086 #define QUE_NODE_CALL 31
2087 #define QUE_NODE_EXIT 32
2089 +#define QUE_NODE_INSERT_STATS 34
2091 /* Query thread states */
2092 #define QUE_THR_RUNNING 1
2093 #define QUE_THR_PROCEDURE_WAIT 2
2094 diff -ruN a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h
2095 --- a/storage/innobase/include/rem0cmp.h 2010-11-03 07:01:13.000000000 +0900
2096 +++ b/storage/innobase/include/rem0cmp.h 2010-12-03 17:19:24.893953395 +0900
2097 @@ -169,10 +169,11 @@
2098 matched fields; when the function returns,
2099 contains the value the for current
2101 - ulint* matched_bytes);/*!< in/out: number of already matched
2102 + ulint* matched_bytes, /*!< in/out: number of already matched
2103 bytes within the first field not completely
2104 matched; when the function returns, contains
2105 the value for the current comparison */
2106 + ulint stats_method);
2107 /*************************************************************//**
2108 This function is used to compare two physical records. Only the common
2109 first fields are compared.
2110 diff -ruN a/storage/innobase/include/rem0cmp.ic b/storage/innobase/include/rem0cmp.ic
2111 --- a/storage/innobase/include/rem0cmp.ic 2010-11-03 07:01:13.000000000 +0900
2112 +++ b/storage/innobase/include/rem0cmp.ic 2010-12-03 17:19:24.902983425 +0900
2116 return(cmp_rec_rec_with_match(rec1, rec2, offsets1, offsets2, index,
2117 - &match_f, &match_b));
2118 + &match_f, &match_b, 0));
2120 diff -ruN a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
2121 --- a/storage/innobase/include/row0mysql.h 2010-11-03 07:01:13.000000000 +0900
2122 +++ b/storage/innobase/include/row0mysql.h 2010-12-03 17:19:24.904973020 +0900
2123 @@ -387,6 +387,14 @@
2124 then checked for not being too
2126 /*********************************************************************//**
2130 +row_insert_stats_for_mysql(
2131 +/*=======================*/
2132 + dict_index_t* index,
2134 +/*********************************************************************//**
2135 Scans a table create SQL string and adds to the data dictionary
2136 the foreign key constraints declared in the string. This function
2137 should be called after the indexes for a table have been created.
2138 diff -ruN a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
2139 --- a/storage/innobase/include/srv0srv.h 2010-12-03 15:53:54.622036720 +0900
2140 +++ b/storage/innobase/include/srv0srv.h 2010-12-03 17:19:24.906953188 +0900
2141 @@ -209,6 +209,13 @@
2142 extern ibool srv_innodb_status;
2144 extern unsigned long long srv_stats_sample_pages;
2145 +extern ulint srv_stats_method;
2146 +#define SRV_STATS_METHOD_NULLS_EQUAL 0
2147 +#define SRV_STATS_METHOD_NULLS_NOT_EQUAL 1
2148 +#define SRV_STATS_METHOD_IGNORE_NULLS 2
2149 +extern ulint srv_stats_auto_update;
2150 +extern ulint srv_stats_update_need_lock;
2151 +extern ibool srv_use_sys_stats_table;
2153 extern ibool srv_use_doublewrite_buf;
2154 extern ibool srv_use_checksums;
2155 diff -ruN a/storage/innobase/page/page0cur.c b/storage/innobase/page/page0cur.c
2156 --- a/storage/innobase/page/page0cur.c 2010-11-03 07:01:13.000000000 +0900
2157 +++ b/storage/innobase/page/page0cur.c 2010-12-03 17:19:24.908973357 +0900
2158 @@ -564,6 +564,74 @@
2164 +page_cur_open_on_nth_user_rec(
2165 +/*==========================*/
2166 + buf_block_t* block, /*!< in: page */
2167 + page_cur_t* cursor, /*!< out: page cursor */
2170 + ulint n_recs = page_get_n_recs(buf_block_get_frame(block));
2172 + page_cur_set_before_first(block, cursor);
2174 + if (UNIV_UNLIKELY(n_recs == 0)) {
2181 + if (nth >= n_recs) {
2186 + page_cur_move_to_next(cursor);
2192 +page_cur_open_on_rnd_user_rec_after_nth(
2193 +/*==========================*/
2194 + buf_block_t* block, /*!< in: page */
2195 + page_cur_t* cursor, /*!< out: page cursor */
2199 + ulint n_recs = page_get_n_recs(buf_block_get_frame(block));
2202 + page_cur_set_before_first(block, cursor);
2204 + if (UNIV_UNLIKELY(n_recs == 0)) {
2211 + if (nth >= n_recs) {
2215 + rnd = (ulint) (nth + page_cur_lcg_prng() % (n_recs - nth));
2224 + page_cur_move_to_next(cursor);
2230 /***********************************************************//**
2231 Writes the log record of a record insert on a page. */
2233 diff -ruN a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c
2234 --- a/storage/innobase/que/que0que.c 2010-11-03 07:01:13.000000000 +0900
2235 +++ b/storage/innobase/que/que0que.c 2010-12-03 17:19:24.910953422 +0900
2236 @@ -621,11 +621,21 @@
2238 que_graph_free_recursive(cre_ind->ind_def);
2239 que_graph_free_recursive(cre_ind->field_def);
2240 + if (srv_use_sys_stats_table)
2241 + que_graph_free_recursive(cre_ind->stats_def);
2242 que_graph_free_recursive(cre_ind->commit_node);
2244 mem_heap_free(cre_ind->heap);
2247 + case QUE_NODE_INSERT_STATS:
2250 + que_graph_free_recursive(cre_ind->stats_def);
2251 + que_graph_free_recursive(cre_ind->commit_node);
2253 + mem_heap_free(cre_ind->heap);
2256 que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
2258 @@ -1138,6 +1148,8 @@
2259 str = "CREATE TABLE";
2260 } else if (type == QUE_NODE_CREATE_INDEX) {
2261 str = "CREATE INDEX";
2262 + } else if (type == QUE_NODE_INSERT_STATS) {
2263 + str = "INSERT TO SYS_STATS";
2264 } else if (type == QUE_NODE_FOR) {
2266 } else if (type == QUE_NODE_RETURN) {
2267 @@ -1255,6 +1267,8 @@
2268 thr = dict_create_table_step(thr);
2269 } else if (type == QUE_NODE_CREATE_INDEX) {
2270 thr = dict_create_index_step(thr);
2271 + } else if (type == QUE_NODE_INSERT_STATS) {
2272 + thr = dict_insert_stats_step(thr);
2273 } else if (type == QUE_NODE_ROW_PRINTF) {
2274 thr = row_printf_step(thr);
2276 diff -ruN a/storage/innobase/rem/rem0cmp.c b/storage/innobase/rem/rem0cmp.c
2277 --- a/storage/innobase/rem/rem0cmp.c 2010-11-03 07:01:13.000000000 +0900
2278 +++ b/storage/innobase/rem/rem0cmp.c 2010-12-03 17:19:24.911953579 +0900
2279 @@ -866,10 +866,11 @@
2280 matched fields; when the function returns,
2281 contains the value the for current
2283 - ulint* matched_bytes) /*!< in/out: number of already matched
2284 + ulint* matched_bytes, /*!< in/out: number of already matched
2285 bytes within the first field not completely
2286 matched; when the function returns, contains
2287 the value for the current comparison */
2288 + ulint stats_method)
2290 ulint rec1_n_fields; /* the number of fields in rec */
2291 ulint rec1_f_len; /* length of current field in rec */
2292 @@ -962,7 +963,11 @@
2294 if (rec1_f_len == rec2_f_len) {
2297 + if (stats_method == SRV_STATS_METHOD_NULLS_EQUAL) {
2303 } else if (rec2_f_len == UNIV_SQL_NULL) {
2305 diff -ruN a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c
2306 --- a/storage/innobase/row/row0merge.c 2010-11-03 07:01:13.000000000 +0900
2307 +++ b/storage/innobase/row/row0merge.c 2010-12-03 17:19:24.914955391 +0900
2308 @@ -2020,6 +2020,8 @@
2309 "UPDATE SYS_INDEXES SET NAME=CONCAT('"
2310 TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n"
2312 + /* Drop the statistics of the index. */
2313 + "DELETE FROM SYS_STATS WHERE INDEX_ID = :indexid;\n"
2314 /* Drop the field definitions of the index. */
2315 "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
2316 /* Drop the index definition and the B-tree. */
2317 diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
2318 --- a/storage/innobase/row/row0mysql.c 2010-11-03 07:01:13.000000000 +0900
2319 +++ b/storage/innobase/row/row0mysql.c 2010-12-03 17:19:24.918953476 +0900
2322 table->stat_modified_counter = counter + 1;
2324 + if (!srv_stats_auto_update)
2327 /* Calculate new statistics if 1 / 16 of table has been modified
2328 since the last time a statistics batch was run, or if
2329 stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
2331 || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
2333 dict_update_statistics(table, FALSE /* update even if stats
2334 - are initialized */);
2335 + are initialized */, TRUE);
2339 @@ -2103,6 +2106,45 @@
2342 /*********************************************************************//**
2346 +row_insert_stats_for_mysql(
2347 +/*=======================*/
2348 + dict_index_t* index,
2356 + ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2358 + trx->op_info = "try to insert rows to SYS_STATS";
2360 + trx_start_if_not_started(trx);
2361 + trx->error_state = DB_SUCCESS;
2363 + heap = mem_heap_create(512);
2365 + node = ind_insert_stats_graph_create(index, heap);
2367 + thr = pars_complete_graph_for_exec(node, trx, heap);
2369 + ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2370 + que_run_threads(thr);
2372 + err = trx->error_state;
2374 + que_graph_free((que_t*) que_node_get_parent(thr));
2376 + trx->op_info = "";
2378 + return((int) err);
2381 +/*********************************************************************//**
2382 Scans a table create SQL string and adds to the data dictionary
2383 the foreign key constraints declared in the string. This function
2384 should be called after the indexes for a table have been created.
2385 @@ -3022,7 +3064,7 @@
2386 dict_table_autoinc_initialize(table, 1);
2387 dict_table_autoinc_unlock(table);
2388 dict_update_statistics(table, FALSE /* update even if stats are
2390 + initialized */, TRUE);
2392 trx_commit_for_mysql(trx);
2394 @@ -3324,6 +3366,8 @@
2395 " IF (SQL % NOTFOUND) THEN\n"
2398 + " DELETE FROM SYS_STATS\n"
2399 + " WHERE INDEX_ID = index_id;\n"
2400 " DELETE FROM SYS_FIELDS\n"
2401 " WHERE INDEX_ID = index_id;\n"
2402 " DELETE FROM SYS_INDEXES\n"
2403 diff -ruN a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
2404 --- a/storage/innobase/srv/srv0srv.c 2010-12-03 15:53:54.625288512 +0900
2405 +++ b/storage/innobase/srv/srv0srv.c 2010-12-03 17:19:24.922953561 +0900
2406 @@ -397,6 +397,10 @@
2407 /* When estimating number of different key values in an index, sample
2408 this many index pages */
2409 UNIV_INTERN unsigned long long srv_stats_sample_pages = 8;
2410 +UNIV_INTERN ulint srv_stats_method = 0;
2411 +UNIV_INTERN ulint srv_stats_auto_update = 1;
2412 +UNIV_INTERN ulint srv_stats_update_need_lock = 1;
2413 +UNIV_INTERN ibool srv_use_sys_stats_table = FALSE;
2415 UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE;
2416 UNIV_INTERN ibool srv_use_checksums = TRUE;