]> git.pld-linux.org Git - packages/percona-server.git/blame - innodb_stats.patch
- symbolic-links=0 from fedora
[packages/percona-server.git] / innodb_stats.patch
CommitLineData
b4e1fa2c
AM
1# name : innodb_stats.patch
2# introduced : 11 or before
3# maintainer : Yasufumi
4#
5#!!! notice !!!
6# Any small change to this file in the main branch
7# should be done or reviewed by the maintainer!
8diff -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 @@
12 }
13 }
14
15+/**********************************************************************//**
16+Positions a cursor at a randomly chosen position within a B-tree
17+after the given path
18+@return TRUE if the position is at the first page, and cursor must point
19+ the first record for used by the caller.*/
20+UNIV_INTERN
21+ibool
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 */
29+{
30+ page_cur_t* page_cursor;
31+ btr_path_t* slot;
32+ ibool is_first_rec = TRUE;
33+ ulint page_no;
34+ ulint space;
35+ ulint zip_size;
36+ ulint height;
37+ rec_t* node_ptr;
38+ mem_heap_t* heap = NULL;
39+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
40+ ulint* offsets = offsets_;
41+ rec_offs_init(offsets_);
42+
43+ if (latch_mode == BTR_MODIFY_TREE) {
44+ mtr_x_lock(dict_index_get_lock(index), mtr);
45+ } else {
46+ mtr_s_lock(dict_index_get_lock(index), mtr);
47+ }
48+
49+ page_cursor = btr_cur_get_page_cur(cursor);
50+ cursor->index = index;
51+
52+ space = dict_index_get_space(index);
53+ zip_size = dict_table_zip_size(index->table);
54+ page_no = dict_index_get_page(index);
55+
56+ height = ULINT_UNDEFINED;
57+ slot = first_rec_path;
58+
59+ for (;;) {
60+ buf_block_t* block;
61+ page_t* page;
62+
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));
68+
69+ if (height == ULINT_UNDEFINED) {
70+ /* We are in the root node */
71+
72+ height = btr_page_get_level(page, mtr);
73+ }
74+
75+ if (height == 0) {
76+ btr_cur_latch_leaves(page, space, zip_size, page_no,
77+ latch_mode, cursor, mtr);
78+ }
79+
80+ if (is_first_rec && slot->nth_rec != ULINT_UNDEFINED) {
81+ if (height == 0) {
82+ /* must open the first rec */
83+ page_cur_open_on_nth_user_rec(block, page_cursor, slot->nth_rec);
84+ } else {
85+ is_first_rec = page_cur_open_on_rnd_user_rec_after_nth(block,
86+ page_cursor, slot->nth_rec);
87+ }
88+ } else {
89+ is_first_rec = FALSE;
90+ page_cur_open_on_rnd_user_rec(block, page_cursor);
91+ }
92+
93+ if (height == 0) {
94+ break;
95+ }
96+
97+ ut_ad(height > 0);
98+
99+ height--;
100+ slot++;
101+
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);
107+ }
108+
109+ if (UNIV_LIKELY_NULL(heap)) {
110+ mem_heap_free(heap);
111+ }
112+
113+ return (is_first_rec);
114+}
115+
116 /*==================== B-TREE INSERT =========================*/
117
118 /*************************************************************//**
d8778560 119@@ -3479,6 +3580,154 @@
b4e1fa2c
AM
120 }
121
122 /*******************************************************************//**
123+Estimates the number of pages which have not null value of the key of n_cols.
124+@return estimated number of pages */
125+UNIV_INTERN
126+ulint
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] */
132+{
133+ dtuple_t* tuple1;
134+ btr_path_t path2[BTR_PATH_ARRAY_N_SLOTS];
135+ btr_cur_t cursor;
136+ btr_path_t* slot1;
137+ btr_path_t* slot2;
138+ ibool diverged;
139+ ibool diverged_lot;
140+ ulint divergence_level;
141+ ulint n_pages;
142+ ulint i;
143+ mtr_t mtr;
144+ mem_heap_t* heap;
145+
146+ heap = mem_heap_create(n_cols * sizeof(dfield_t)
147+ + sizeof(dtuple_t));
148+
149+ /* make tuple1 (NULL,NULL,,,) from n_cols */
150+ tuple1 = dtuple_create(heap, n_cols);
151+ dict_index_copy_types(tuple1, index, n_cols);
152+
153+ for (i = 0; i < n_cols; i++) {
154+ dfield_set_null(dtuple_get_nth_field(tuple1, i));
155+ }
156+
157+ mtr_start(&mtr);
158+
159+ cursor.path_arr = path1;
160+
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);
164+
165+ mtr_commit(&mtr);
166+
167+
168+
169+ mtr_start(&mtr);
170+
171+ cursor.path_arr = path2;
172+
173+ btr_cur_open_at_index_side(FALSE, index,
174+ BTR_SEARCH_LEAF | BTR_ESTIMATE,
175+ &cursor, &mtr);
176+
177+ mtr_commit(&mtr);
178+
179+ mem_heap_free(heap);
180+
181+ /* We have the path information for the range in path1 and path2 */
182+
183+ n_pages = 1;
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
189+ a lot */
190+ for (i = 0; ; i++) {
191+ ut_ad(i < BTR_PATH_ARRAY_N_SLOTS);
192+
193+ slot1 = path1 + i;
194+ slot2 = path2 + i;
195+
196+ if ((slot1 + 1)->nth_rec == ULINT_UNDEFINED
197+ || (slot2 + 1)->nth_rec == ULINT_UNDEFINED) {
198+
199+ if (i > divergence_level + 1) {
200+ /* In trees whose height is > 1 our algorithm
201+ tends to underestimate: multiply the estimate
202+ by 2: */
203+
204+ n_pages = n_pages * 2;
205+ }
206+
207+ /* Do not estimate the number of rows in the range
208+ to over 1 / 2 of the estimated rows in the whole
209+ table */
210+
211+ if (n_pages > index->stat_n_leaf_pages / 2) {
212+ n_pages = index->stat_n_leaf_pages / 2;
213+
214+ /* If there are just 0 or 1 rows in the table,
215+ then we estimate all rows are in the range */
216+
217+ if (n_pages == 0) {
218+ n_pages = index->stat_n_leaf_pages;
219+ }
220+ }
221+
222+ return(n_pages);
223+ }
224+
225+ if (!diverged && slot1->nth_rec != slot2->nth_rec) {
226+
227+ diverged = TRUE;
228+
229+ if (slot1->nth_rec < slot2->nth_rec) {
230+ n_pages = slot2->nth_rec - slot1->nth_rec;
231+
232+ if (n_pages > 1) {
233+ diverged_lot = TRUE;
234+ divergence_level = i;
235+ }
236+ } else {
237+ /* Maybe the tree has changed between
238+ searches */
239+
240+ return(10);
241+ }
242+
243+ } else if (diverged && !diverged_lot) {
244+
245+ if (slot1->nth_rec < slot1->n_recs
246+ || slot2->nth_rec > 1) {
247+
248+ diverged_lot = TRUE;
249+ divergence_level = i;
250+
251+ n_pages = 0;
252+
253+ if (slot1->nth_rec < slot1->n_recs) {
254+ n_pages += slot1->n_recs
255+ - slot1->nth_rec;
256+ }
257+
258+ if (slot2->nth_rec > 1) {
259+ n_pages += slot2->nth_rec - 1;
260+ }
261+ }
262+ } else if (diverged_lot) {
263+
264+ n_pages = (n_pages * (slot1->n_recs + slot2->n_recs))
265+ / 2;
266+ }
267+ }
268+}
269+
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. */
d8778560 274@@ -3507,18 +3756,38 @@
b4e1fa2c
AM
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_);
283
284 n_cols = dict_index_get_n_unique(index);
285
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);
290+
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;
294+ }
295+ return;
296+ } else if (effective_pages > index->stat_n_leaf_pages) {
297+ effective_pages = index->stat_n_leaf_pages;
298+ }
299+ } else {
300+ effective_pages = index->stat_n_leaf_pages;
301+ }
302+
303 n_diff = mem_zalloc((n_cols + 1) * sizeof(ib_int64_t));
304
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;
313 } else {
314 n_sample_pages = 1;
315 }
d8778560 316@@ -3530,9 +3799,15 @@
b4e1fa2c
AM
317
318 for (i = 0; i < n_sample_pages; i++) {
319 rec_t* supremum;
320+ ibool is_first_page = TRUE;
321 mtr_start(&mtr);
322
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);
326+ } else {
327 btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
328+ }
329
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
d8778560 332@@ -3543,7 +3818,13 @@
b4e1fa2c
AM
333 page = btr_cur_get_page(&cursor);
334
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);
340+ } else {
341 rec = page_rec_get_next(page_get_infimum_rec(page));
342+ }
343
344 if (rec != supremum) {
345 not_empty_flag = 1;
d8778560 346@@ -3552,7 +3833,8 @@
b4e1fa2c
AM
347 }
348
349 while (rec != supremum) {
350- rec_t* next_rec = page_rec_get_next(rec);
351+ rec_t* next_rec;
352+ next_rec = page_rec_get_next(rec);
353 if (next_rec == supremum) {
354 break;
355 }
d8778560 356@@ -3566,7 +3848,10 @@
b4e1fa2c
AM
357 cmp_rec_rec_with_match(rec, next_rec,
358 offsets_rec, offsets_next_rec,
359 index, &matched_fields,
360- &matched_bytes);
361+ &matched_bytes,
362+ (stats_method==SRV_STATS_METHOD_NULLS_NOT_EQUAL) ?
363+ SRV_STATS_METHOD_NULLS_NOT_EQUAL :
364+ SRV_STATS_METHOD_NULLS_EQUAL);
365
366 for (j = matched_fields + 1; j <= n_cols; j++) {
367 /* We add one if this index record has
d8778560 368@@ -3627,7 +3912,7 @@
b4e1fa2c
AM
369 for (j = 0; j <= n_cols; j++) {
370 index->stat_n_diff_key_vals[j]
371 = ((n_diff[j]
372- * (ib_int64_t)index->stat_n_leaf_pages
373+ * (ib_int64_t)effective_pages
374 + n_sample_pages - 1
375 + total_external_size
376 + not_empty_flag)
d8778560 377@@ -3642,7 +3927,7 @@
b4e1fa2c
AM
378 different key values, or even more. Let us try to approximate
379 that: */
380
381- add_on = index->stat_n_leaf_pages
382+ add_on = effective_pages
383 / (10 * (n_sample_pages
384 + total_external_size));
385
d8778560 386@@ -3651,6 +3936,15 @@
b4e1fa2c
AM
387 }
388
389 index->stat_n_diff_key_vals[j] += add_on;
390+
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;
398+ }
399 }
400
401 mem_free(n_diff);
402diff -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
405@@ -266,6 +266,29 @@
406 /* Get the dictionary header */
407 dict_hdr = dict_hdr_get(&mtr);
408
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;
413+
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;
420+ } else {
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);
425+ }
426+ mtr_commit(&mtr);
427+ /* restart mtr */
428+ mtr_start(&mtr);
429+ dict_hdr = dict_hdr_get(&mtr);
430+ }
431+
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
435@@ -425,7 +448,7 @@
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);
441
442 index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
443 DICT_HDR_SPACE,
444@@ -442,6 +465,41 @@
445 FALSE);
446 ut_a(error == DB_SUCCESS);
447
448+ /*-------------------------*/
449+ table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 3, 0);
450+ table->n_mysql_handles_opened = 1; /* for pin */
451+
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);
455+
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"
459+#endif
460+
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);
465+
466+ index = dict_mem_index_create("SYS_STATS", "CLUST_IND",
467+ DICT_HDR_SPACE,
468+ DICT_UNIQUE | DICT_CLUSTERED, 2);
469+
470+ dict_mem_index_add_field(index, "INDEX_ID", 0);
471+ dict_mem_index_add_field(index, "KEY_COLS", 0);
472+
473+ index->id = DICT_STATS_ID;
474+ error = dict_index_add_to_cache(table, index,
475+ mtr_read_ulint(dict_hdr
476+ + DICT_HDR_STATS,
477+ MLOG_4BYTES, &mtr),
478+ FALSE);
479+ ut_a(error == DB_SUCCESS);
480+
481+ mem_heap_free(heap);
482+
483 mtr_commit(&mtr);
484 /*-------------------------*/
485
486@@ -455,6 +513,7 @@
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);
491
492 mutex_exit(&(dict_sys->mutex));
493 }
494diff -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
497@@ -508,6 +508,51 @@
498 }
499
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 */
504+static
505+dtuple_t*
506+dict_create_sys_stats_tuple(
507+/*========================*/
508+ const dict_index_t* index,
509+ ulint i,
510+ mem_heap_t* heap)
511+{
512+ dict_table_t* sys_stats;
513+ dtuple_t* entry;
514+ dfield_t* dfield;
515+ byte* ptr;
516+
517+ ut_ad(index);
518+ ut_ad(heap);
519+
520+ sys_stats = dict_sys->sys_stats;
521+
522+ entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);
523+
524+ dict_table_copy_types(entry, sys_stats);
525+
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);
541+
542+ return(entry);
543+}
544+
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 */
549@@ -617,6 +662,27 @@
550 }
551
552 /***************************************************************//**
553+Builds a row for storing stats to insert.
554+@return DB_SUCCESS */
555+static
556+ulint
557+dict_build_stats_def_step(
558+/*======================*/
559+ ind_node_t* node)
560+{
561+ dict_index_t* index;
562+ dtuple_t* row;
563+
564+ index = node->index;
565+
566+ row = dict_create_sys_stats_tuple(index, node->stats_no, node->heap);
567+
568+ ins_node_set_new_row(node->stats_def, row);
569+
570+ return(DB_SUCCESS);
571+}
572+
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 */
576 static
577@@ -937,6 +1003,49 @@
578 dict_sys->sys_fields, heap);
579 node->field_def->common.parent = node;
580
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;
585+ } else {
586+ node->stats_def = NULL;
587+ }
588+
589+ node->commit_node = commit_node_create(heap);
590+ node->commit_node->common.parent = node;
591+
592+ return(node);
593+}
594+
595+/*********************************************************************//**
596+*/
597+UNIV_INTERN
598+ind_node_t*
599+ind_insert_stats_graph_create(
600+/*==========================*/
601+ dict_index_t* index,
602+ mem_heap_t* heap)
603+{
604+ ind_node_t* node;
605+
606+ node = mem_heap_alloc(heap, sizeof(ind_node_t));
607+
608+ node->common.type = QUE_NODE_INSERT_STATS;
609+
610+ node->index = index;
611+
612+ node->state = INDEX_BUILD_STATS_COLS;
613+ node->page_no = FIL_NULL;
614+ node->heap = mem_heap_create(256);
615+
616+ node->ind_def = NULL;
617+ node->field_def = NULL;
618+
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;
623+
624 node->commit_node = commit_node_create(heap);
625 node->commit_node->common.parent = node;
626
627@@ -1087,6 +1196,7 @@
628
629 node->state = INDEX_BUILD_FIELD_DEF;
630 node->field_no = 0;
631+ node->stats_no = 0;
632
633 thr->run_node = node->ind_def;
634
635@@ -1132,7 +1242,31 @@
636 goto function_exit;
637 }
638
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;
643+ } else {
644+ node->state = INDEX_CREATE_INDEX_TREE;
645+ }
646+ }
647+ if (node->state == INDEX_BUILD_STATS_COLS) {
648+ if (node->stats_no <= dict_index_get_n_unique(node->index)) {
649+
650+ err = dict_build_stats_def_step(node);
651+
652+ if (err != DB_SUCCESS) {
653+
654+ goto function_exit;
655+ }
656+
657+ node->stats_no++;
658+
659+ thr->run_node = node->stats_def;
660+
661+ return(thr);
662+ } else {
663+ node->state = INDEX_CREATE_INDEX_TREE;
664+ }
665 }
666
667 if (node->state == INDEX_CREATE_INDEX_TREE) {
668@@ -1178,6 +1312,66 @@
669 return(NULL);
670 }
671
672+ thr->run_node = que_node_get_parent(node);
673+
674+ return(thr);
675+}
676+
677+/****************************************************************//**
678+*/
679+UNIV_INTERN
680+que_thr_t*
681+dict_insert_stats_step(
682+/*===================*/
683+ que_thr_t* thr) /*!< in: query thread */
684+{
685+ ind_node_t* node;
686+ ulint err = DB_ERROR;
687+ trx_t* trx;
688+
689+ ut_ad(thr);
690+
691+ trx = thr_get_trx(thr);
692+
693+ node = thr->run_node;
694+
695+ if (thr->prev_node == que_node_get_parent(node)) {
696+ node->state = INDEX_BUILD_STATS_COLS;
697+ }
698+
699+ if (node->state == INDEX_BUILD_STATS_COLS) {
700+ if (node->stats_no <= dict_index_get_n_unique(node->index)) {
701+
702+ err = dict_build_stats_def_step(node);
703+
704+ if (err != DB_SUCCESS) {
705+
706+ goto function_exit;
707+ }
708+
709+ node->stats_no++;
710+
711+ thr->run_node = node->stats_def;
712+
713+ return(thr);
714+ } else {
715+ node->state = INDEX_COMMIT_WORK;
716+ }
717+ }
718+
719+ if (node->state == INDEX_COMMIT_WORK) {
720+
721+ /* do not commit transaction here for now */
722+ }
723+
724+function_exit:
725+ trx->error_state = err;
726+
727+ if (err == DB_SUCCESS) {
728+ } else {
729+ return(NULL);
730+ }
731+
732 thr->run_node = que_node_get_parent(node);
733
734 return(thr);
735diff -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
d8778560 738@@ -756,7 +756,7 @@
b4e1fa2c
AM
739 print an error message and return without doing
740 anything. */
741 dict_update_statistics(table, TRUE /* only update stats
742- if they have not been initialized */);
743+ if they have not been initialized */, FALSE);
744 }
745
746 return(table);
d8778560 747@@ -4304,6 +4304,240 @@
b4e1fa2c
AM
748 }
749
750 /*********************************************************************//**
751+functions to use SYS_STATS system table. */
752+static
753+ibool
754+dict_reload_statistics(
755+/*===================*/
756+ dict_table_t* table,
757+ ulint* sum_of_index_sizes)
758+{
759+ dict_index_t* index;
760+ ulint size;
761+ mem_heap_t* heap;
762+
763+ index = dict_table_get_first_index(table);
764+
765+ if (index == NULL) {
766+ /* Table definition is corrupt */
767+
768+ return(FALSE);
769+ }
770+
771+ heap = mem_heap_create(1000);
772+
773+ while (index) {
774+ size = btr_get_size(index, BTR_TOTAL_SIZE);
775+
776+ index->stat_index_size = size;
777+
778+ *sum_of_index_sizes += size;
779+
780+ size = btr_get_size(index, BTR_N_LEAF_PAGES);
781+
782+ if (size == 0) {
783+ /* The root node of the tree is a leaf */
784+ size = 1;
785+ }
786+
787+ index->stat_n_leaf_pages = size;
788+
789+/*===========================================*/
790+{
791+ dict_table_t* sys_stats;
792+ dict_index_t* sys_index;
793+ btr_pcur_t pcur;
794+ dtuple_t* tuple;
795+ dfield_t* dfield;
796+ ulint key_cols;
797+ ulint n_cols;
798+ const rec_t* rec;
799+ const byte* field;
800+ ulint len;
801+ ib_int64_t* stat_n_diff_key_vals_tmp;
802+ byte* buf;
803+ ulint i;
804+ mtr_t mtr;
805+
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));
808+
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));
812+
813+ tuple = dtuple_create(heap, 1);
814+ dfield = dtuple_get_nth_field(tuple, 0);
815+
816+ buf = mem_heap_alloc(heap, 8);
817+ mach_write_to_8(buf, index->id);
818+
819+ dfield_set_data(dfield, buf, 8);
820+ dict_index_copy_types(tuple, sys_index, 1);
821+
822+ mtr_start(&mtr);
823+
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);
828+
829+ if (!btr_pcur_is_on_user_rec(&pcur)
830+ || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
831+ != index->id) {
832+ /* not found: even 1 if not found should not be alowed */
833+ fprintf(stderr, "InnoDB: Warning: stats for %s/%s (%lu/%lu)"
d8778560 834+ " not found in SYS_STATS\n",
b4e1fa2c
AM
835+ index->table_name, index->name, i, n_cols);
836+ btr_pcur_close(&pcur);
837+ mtr_commit(&mtr);
838+ mem_heap_free(heap);
839+ return(FALSE);
840+ }
841+
842+ if (rec_get_deleted_flag(rec, 0)) {
843+ goto next_rec;
844+ }
845+
846+ field = rec_get_nth_field_old(rec, 1, &len);
847+ ut_a(len == 4);
848+
849+ key_cols = mach_read_from_4(field);
850+
851+ ut_a(i == key_cols);
852+
853+ field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
854+ ut_a(len == 8);
855+
856+ stat_n_diff_key_vals_tmp[i] = mach_read_from_8(field);
857+next_rec:
858+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
859+ }
860+
861+ btr_pcur_close(&pcur);
862+ mtr_commit(&mtr);
863+
864+ for (i = 0; i <= n_cols; i++) {
865+ index->stat_n_diff_key_vals[i] = stat_n_diff_key_vals_tmp[i];
866+ }
867+}
868+/*===========================================*/
869+
870+ index = dict_table_get_next_index(index);
871+ }
872+
873+ mem_heap_free(heap);
874+ return(TRUE);
875+}
876+
877+static
878+void
879+dict_store_statistics(
880+/*==================*/
881+ dict_table_t* table)
882+{
883+ dict_index_t* index;
884+ mem_heap_t* heap;
885+
886+ index = dict_table_get_first_index(table);
887+
888+ ut_a(index);
889+
890+ heap = mem_heap_create(1000);
891+
892+ while (index) {
893+/*===========================================*/
894+{
895+ dict_table_t* sys_stats;
896+ dict_index_t* sys_index;
897+ btr_pcur_t pcur;
898+ dtuple_t* tuple;
899+ dfield_t* dfield;
900+ ulint key_cols;
901+ ulint n_cols;
902+ ulint rests;
903+ const rec_t* rec;
904+ const byte* field;
905+ ulint len;
906+ ib_int64_t* stat_n_diff_key_vals_tmp;
907+ byte* buf;
908+ ulint i;
909+ mtr_t mtr;
910+
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));
913+
914+ for (i = 0; i <= n_cols; i++) {
915+ stat_n_diff_key_vals_tmp[i] = index->stat_n_diff_key_vals[i];
916+ }
917+
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));
921+
922+ tuple = dtuple_create(heap, 1);
923+ dfield = dtuple_get_nth_field(tuple, 0);
924+
925+ buf = mem_heap_alloc(heap, 8);
926+ mach_write_to_8(buf, index->id);
927+
928+ dfield_set_data(dfield, buf, 8);
929+ dict_index_copy_types(tuple, sys_index, 1);
930+
931+ mtr_start(&mtr);
932+
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);
938+
939+ if (!btr_pcur_is_on_user_rec(&pcur)
940+ || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
941+ != index->id) {
942+ /* not found */
d8778560
AM
943+
944+
b4e1fa2c
AM
945+ break;
946+ }
947+
948+ if (rec_get_deleted_flag(rec, 0)) {
949+ goto next_rec;
950+ }
951+
952+ field = rec_get_nth_field_old(rec, 1, &len);
953+ ut_a(len == 4);
954+
955+ key_cols = mach_read_from_4(field);
956+
957+ field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
958+ ut_a(len == 8);
959+
960+ mlog_write_ull((byte*)field, stat_n_diff_key_vals_tmp[key_cols], &mtr);
961+
962+ rests--;
963+
964+next_rec:
965+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
966+ }
967+ btr_pcur_close(&pcur);
968+ mtr_commit(&mtr);
969+
970+ if (rests) {
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);
974+ }
975+}
976+/*===========================================*/
977+
978+ index = dict_table_get_next_index(index);
979+ }
980+
981+ mem_heap_free(heap);
982+}
983+
984+/*********************************************************************//**
985 Calculates new estimates for table and index statistics. The statistics
986 are used in query optimization. */
987 UNIV_INTERN
d8778560 988@@ -4311,10 +4545,11 @@
b4e1fa2c
AM
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
996 do nothing */
997+ ibool sync) /*!< in: TRUE if must update SYS_STATS */
998 {
999 dict_index_t* index;
1000 ulint sum_of_index_sizes = 0;
d8778560 1001@@ -4331,6 +4566,27 @@
b4e1fa2c
AM
1002 return;
1003 }
1004
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);
1007+
1008+ /* reload statistics from SYS_STATS table */
1009+ if (dict_reload_statistics(table, &sum_of_index_sizes)) {
1010+ /* success */
1011+#ifdef UNIV_DEBUG
d8778560 1012+ fprintf(stderr, "InnoDB: DEBUG: reload_statistics succeeded for %s.\n",
b4e1fa2c
AM
1013+ table->name);
1014+#endif
1015+ goto end;
1016+ }
1017+
1018+ dict_table_stats_unlock(table, RW_X_LATCH);
1019+ }
1020+#ifdef UNIV_DEBUG
1021+ fprintf(stderr, "InnoDB: DEBUG: update_statistics for %s.\n",
1022+ table->name);
1023+#endif
1024+ sum_of_index_sizes = 0;
1025+
1026 /* Find out the sizes of the indexes and how many different values
1027 for the key they approximately have */
1028
d8778560 1029@@ -4391,6 +4647,11 @@
b4e1fa2c
AM
1030 index = dict_table_get_next_index(index);
1031 } while (index);
1032
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);
1036+ }
1037+end:
1038 index = dict_table_get_first_index(table);
1039
1040 table->stat_n_rows = index->stat_n_diff_key_vals[
d8778560 1041@@ -4485,7 +4746,8 @@
b4e1fa2c
AM
1042
1043 ut_ad(mutex_own(&(dict_sys->mutex)));
1044
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);
1048
1049 dict_table_stats_lock(table, RW_S_LATCH);
1050
1051diff -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
d8778560 1054@@ -50,7 +50,8 @@
b4e1fa2c
AM
1055 "SYS_COLUMNS",
1056 "SYS_FIELDS",
1057 "SYS_FOREIGN",
1058- "SYS_FOREIGN_COLS"
1059+ "SYS_FOREIGN_COLS",
1060+ "SYS_STATS"
1061 };
1062 /****************************************************************//**
1063 Compare the name of an index column.
d8778560 1064@@ -343,12 +344,13 @@
b4e1fa2c
AM
1065 }
1066
1067 if ((status & DICT_TABLE_UPDATE_STATS)
1068+ && srv_stats_auto_update
1069 && dict_table_get_first_index(*table)) {
1070
1071 /* Update statistics if DICT_TABLE_UPDATE_STATS
1072 is set */
1073 dict_update_statistics(*table, FALSE /* update even if
1074- initialized */);
1075+ initialized */, FALSE);
1076 }
1077
1078 return(NULL);
d8778560
AM
1079@@ -582,6 +584,61 @@
1080 //#endif /* FOREIGN_NOT_USED */
b4e1fa2c 1081
d8778560 1082 /********************************************************************//**
b4e1fa2c
AM
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 */
1086+UNIV_INTERN
1087+const char*
1088+dict_process_sys_stats_rec(
1089+/*=============================*/
d8778560 1090+ mem_heap_t* heap __attribute__((unused)), /*!< in/out: heap memory */
b4e1fa2c
AM
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 */
1095+{
1096+ ulint len;
1097+ const byte* field;
1098+
1099+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1100+ return("delete-marked record in SYS_STATS");
1101+ }
1102+
1103+ if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
1104+ return("wrong number of columns in SYS_STATS record");
1105+ }
1106+
1107+ field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
1108+ if (UNIV_UNLIKELY(len != 8)) {
1109+err_len:
1110+ return("incorrect column length in SYS_STATS");
1111+ }
1112+ *index_id = mach_read_from_8(field);
1113+
1114+ field = rec_get_nth_field_old(rec, 1/*KEY_COLS*/, &len);
1115+ if (UNIV_UNLIKELY(len != 4)) {
1116+ goto err_len;
1117+ }
1118+ *key_cols = mach_read_from_4(field);
1119+
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)) {
1122+ goto err_len;
1123+ }
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)) {
1126+ goto err_len;
1127+ }
1128+
1129+ field = rec_get_nth_field_old(rec, 4/*DIFF_VALS*/, &len);
1130+ if (UNIV_UNLIKELY(len != 8)) {
1131+ goto err_len;
1132+ }
1133+ *diff_vals = mach_read_from_8(field);
1134+
1135+ return(NULL);
1136+}
d8778560 1137+/********************************************************************//**
b4e1fa2c
AM
1138 Determine the flags of a table described in SYS_TABLES.
1139 @return compressed page size in kilobytes; or 0 if the tablespace is
d8778560 1140 uncompressed, ULINT_UNDEFINED on error */
b4e1fa2c
AM
1141diff -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
1144@@ -187,6 +187,7 @@
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;
1149
1150
1151 static char* internal_innobase_data_file_path = NULL;
d8778560 1152@@ -2388,6 +2389,8 @@
b4e1fa2c
AM
1153 goto error;
1154 }
1155
1156+ srv_use_sys_stats_table = (ibool) innobase_use_sys_stats_table;
1157+
1158 /* -------------- Log files ---------------------------*/
1159
1160 /* The default dir for log files is the datadir of MySQL */
d8778560 1161@@ -5192,6 +5195,10 @@
b4e1fa2c
AM
1162
1163 error = row_insert_for_mysql((byte*) record, prebuilt);
1164
1165+#ifdef EXTENDED_FOR_USERSTAT
1166+ if (error == DB_SUCCESS) rows_changed++;
1167+#endif
1168+
1169 /* Handle duplicate key errors */
1170 if (auto_inc_used) {
1171 ulint err;
d8778560 1172@@ -5528,6 +5535,10 @@
b4e1fa2c
AM
1173 }
1174 }
1175
1176+#ifdef EXTENDED_FOR_USERSTAT
1177+ if (error == DB_SUCCESS) rows_changed++;
1178+#endif
1179+
1180 innodb_srv_conc_exit_innodb(trx);
1181
1182 error = convert_error_code_to_mysql(error,
d8778560 1183@@ -5581,6 +5592,10 @@
b4e1fa2c
AM
1184
1185 error = row_update_for_mysql((byte*) record, prebuilt);
1186
1187+#ifdef EXTENDED_FOR_USERSTAT
1188+ if (error == DB_SUCCESS) rows_changed++;
1189+#endif
1190+
1191 innodb_srv_conc_exit_innodb(trx);
1192
1193 error = convert_error_code_to_mysql(
d8778560
AM
1194@@ -5899,6 +5914,11 @@
1195 case DB_SUCCESS:
1196 error = 0;
1197 table->status = 0;
1198+#ifdef EXTENDED_FOR_USERSTAT
1199+ rows_read++;
1200+ if (active_index >= 0 && active_index < MAX_KEY)
1201+ index_rows_read[active_index]++;
1202+#endif
1203 break;
1204 case DB_RECORD_NOT_FOUND:
1205 error = HA_ERR_KEY_NOT_FOUND;
1206@@ -6108,6 +6128,11 @@
b4e1fa2c
AM
1207 case DB_SUCCESS:
1208 error = 0;
1209 table->status = 0;
1210+#ifdef EXTENDED_FOR_USERSTAT
1211+ rows_read++;
1212+ if (active_index >= 0 && active_index < MAX_KEY)
1213+ index_rows_read[active_index]++;
1214+#endif
1215 break;
1216 case DB_RECORD_NOT_FOUND:
1217 error = HA_ERR_END_OF_FILE;
d8778560 1218@@ -7999,11 +8024,31 @@
b4e1fa2c
AM
1219 /* In sql_show we call with this flag: update
1220 then statistics so that they are up-to-date */
1221
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;
1227+
1228+ prebuilt->trx->op_info = "confirming rows of SYS_STATS to store statistics";
1229+
1230+ ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
1231+
1232+ for (index = dict_table_get_first_index(ib_table);
1233+ index != NULL;
1234+ index = dict_table_get_next_index(index)) {
1235+ row_insert_stats_for_mysql(index, prebuilt->trx);
1236+ innobase_commit_low(prebuilt->trx);
1237+ }
1238+
1239+ ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
1240+ }
1241+
1242 prebuilt->trx->op_info = "updating table statistics";
1243
1244 dict_update_statistics(ib_table,
1245 FALSE /* update even if stats
1246- are initialized */);
1247+ are initialized */, called_from_analyze);
1248
1249 prebuilt->trx->op_info = "returning various info to MySQL";
1250 }
d8778560 1251@@ -8081,7 +8126,7 @@
b4e1fa2c
AM
1252 are asked by MySQL to avoid locking. Another reason to
1253 avoid the call is that it uses quite a lot of CPU.
1254 See Bug#38185. */
d8778560
AM
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)) {
b4e1fa2c
AM
1258 /* We do not update delete_length if no
1259 locking is requested so the "old" value can
d8778560 1260@@ -11281,6 +11326,45 @@
b4e1fa2c
AM
1261 "The number of index pages to sample when calculating statistics (default 8)",
1262 NULL, NULL, 8, 1, ~0ULL, 0);
1263
1264+const char *innobase_stats_method_names[]=
1265+{
1266+ "nulls_equal",
1267+ "nulls_unequal",
1268+ "nulls_ignored",
1269+ NullS
1270+};
1271+TYPELIB innobase_stats_method_typelib=
1272+{
1273+ array_elements(innobase_stats_method_names) - 1, "innobase_stats_method_typelib",
1274+ innobase_stats_method_names, NULL
1275+};
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);
1282+
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);
1288+
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);
1294+
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);
1302+
1303 static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
1304 PLUGIN_VAR_OPCMDARG,
1305 "Enable InnoDB adaptive hash index (enabled by default). "
d8778560 1306@@ -11604,6 +11688,10 @@
a9ee80b9 1307 MYSQL_SYSVAR(recovery_update_relay_log),
b4e1fa2c
AM
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),
d8778560 1317@@ -11672,7 +11760,10 @@
b4e1fa2c
AM
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;
1327
1328 /** @brief Initialize the default value of innodb_commit_concurrency.
1329diff -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
1332@@ -49,6 +49,7 @@
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 */
1337 }
1338
1339 static const char plugin_author[] = "Innobase Oy";
d8778560 1340@@ -3457,6 +3458,203 @@
b4e1fa2c
AM
1341 STRUCT_FLD(__reserved1, NULL)
1342 };
1343
1344+/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_stats */
1345+static ST_FIELD_INFO innodb_sys_stats_fields_info[] =
1346+{
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)},
1355+
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)},
1364+
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)},
1373+
1374+ END_OF_ST_FIELD_INFO
1375+};
1376+/**********************************************************************//**
1377+Function to fill information_schema.innodb_sys_stats
1378+@return 0 on success */
1379+static
1380+int
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 */
1388+{
1389+ Field** fields;
1390+
1391+ DBUG_ENTER("i_s_dict_fill_sys_stats");
1392+
1393+ fields = table_to_fill->field;
1394+
1395+ OK(fields[SYS_STATS_INDEX_ID]->store(longlong(index_id), TRUE));
1396+
1397+ OK(fields[SYS_STATS_KEY_COLS]->store(key_cols));
1398+
1399+ OK(fields[SYS_STATS_DIFF_VALS]->store(longlong(diff_vals), TRUE));
1400+
1401+ OK(schema_table_store_record(thd, table_to_fill));
1402+
1403+ DBUG_RETURN(0);
1404+}
1405+/*******************************************************************//**
1406+Function to populate INFORMATION_SCHEMA.innodb_sys_stats table.
1407+@return 0 on success */
1408+static
1409+int
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) */
1415+{
1416+ btr_pcur_t pcur;
1417+ const rec_t* rec;
1418+ mem_heap_t* heap;
1419+ mtr_t mtr;
1420+
1421+ DBUG_ENTER("i_s_sys_stats_fill_table");
1422+
1423+ /* deny access to non-superusers */
1424+ if (check_global_access(thd, PROCESS_ACL)) {
1425+ DBUG_RETURN(0);
1426+ }
1427+
1428+ heap = mem_heap_create(1000);
1429+ mutex_enter(&dict_sys->mutex);
1430+ mtr_start(&mtr);
1431+
1432+ rec = dict_startscan_system(&pcur, &mtr, SYS_STATS);
1433+
1434+ while (rec) {
1435+ const char* err_msg;
1436+ index_id_t index_id;
1437+ ulint key_cols;
1438+ ib_uint64_t diff_vals;
1439+
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);
1443+
1444+ mtr_commit(&mtr);
1445+ mutex_exit(&dict_sys->mutex);
1446+
1447+ if (!err_msg) {
1448+ i_s_dict_fill_sys_stats(
1449+ thd, index_id, key_cols, diff_vals,
1450+ tables->table);
1451+ } else {
1452+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
1453+ ER_CANT_FIND_SYSTEM_REC,
1454+ err_msg);
1455+ }
1456+
1457+ mem_heap_empty(heap);
1458+
1459+ /* Get the next record */
1460+ mutex_enter(&dict_sys->mutex);
1461+ mtr_start(&mtr);
1462+ rec = dict_getnext_system(&pcur, &mtr);
1463+ }
1464+
1465+ mtr_commit(&mtr);
1466+ mutex_exit(&dict_sys->mutex);
1467+ mem_heap_free(heap);
1468+
1469+ DBUG_RETURN(0);
1470+}
1471+/*******************************************************************//**
1472+Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_stats
1473+@return 0 on success */
1474+static
1475+int
1476+innodb_sys_stats_init(
1477+/*========================*/
1478+ void* p) /*!< in/out: table schema object */
1479+{
1480+ ST_SCHEMA_TABLE* schema;
1481+
1482+ DBUG_ENTER("innodb_sys_stats_init");
1483+
1484+ schema = (ST_SCHEMA_TABLE*) p;
1485+
1486+ schema->fields_info = innodb_sys_stats_fields_info;
1487+ schema->fill_table = i_s_sys_stats_fill_table;
1488+
1489+ DBUG_RETURN(0);
1490+}
1491+
1492+UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_stats =
1493+{
1494+ /* the plugin type (a MYSQL_XXX_PLUGIN value) */
1495+ /* int */
1496+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1497+
1498+ /* pointer to type-specific plugin descriptor */
1499+ /* void* */
1500+ STRUCT_FLD(info, &i_s_info),
1501+
1502+ /* plugin name */
1503+ /* const char* */
1504+ STRUCT_FLD(name, "INNODB_SYS_STATS"),
1505+
1506+ /* plugin author (for SHOW PLUGINS) */
1507+ /* const char* */
1508+ STRUCT_FLD(author, plugin_author),
1509+
1510+ /* general descriptive text (for SHOW PLUGINS) */
1511+ /* const char* */
1512+ STRUCT_FLD(descr, "XtraDB SYS_STATS table"),
1513+
1514+ /* the plugin license (PLUGIN_LICENSE_XXX) */
1515+ /* int */
1516+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1517+
1518+ /* the function to invoke when plugin is loaded */
1519+ /* int (*)(void*); */
1520+ STRUCT_FLD(init, innodb_sys_stats_init),
1521+
1522+ /* the function to invoke when plugin is unloaded */
1523+ /* int (*)(void*); */
1524+ STRUCT_FLD(deinit, i_s_common_deinit),
1525+
1526+ /* plugin version (for SHOW PLUGINS) */
1527+ /* unsigned int */
1528+ STRUCT_FLD(version, INNODB_VERSION_SHORT),
1529+
1530+ /* struct st_mysql_show_var* */
1531+ STRUCT_FLD(status_vars, NULL),
1532+
1533+ /* struct st_mysql_sys_var** */
1534+ STRUCT_FLD(system_vars, NULL),
1535+
1536+ /* reserved for dependency checking */
1537+ /* void* */
1538+ STRUCT_FLD(__reserved1, NULL)
1539+};
1540+
1541 /***********************************************************************
1542 */
1543 static ST_FIELD_INFO i_s_innodb_rseg_fields_info[] =
d8778560 1544@@ -3619,3 +3817,347 @@
b4e1fa2c
AM
1545 /* void* */
1546 STRUCT_FLD(__reserved1, NULL)
1547 };
1548+
1549+/***********************************************************************
1550+*/
1551+static ST_FIELD_INFO i_s_innodb_table_stats_info[] =
1552+{
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)},
1560+
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)},
1568+
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)},
1576+
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)},
1584+
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)},
1592+
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)},
1600+
1601+ END_OF_ST_FIELD_INFO
1602+};
1603+
1604+static ST_FIELD_INFO i_s_innodb_index_stats_info[] =
1605+{
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)},
1613+
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)},
1621+
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)},
1629+
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)},
1637+
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)},
1645+
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)},
1653+
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)},
1661+
1662+ END_OF_ST_FIELD_INFO
1663+};
1664+
1665+static
1666+int
1667+i_s_innodb_table_stats_fill(
1668+/*========================*/
1669+ THD* thd,
1670+ TABLE_LIST* tables,
1671+ COND* cond)
1672+{
1673+ TABLE* i_s_table = (TABLE *) tables->table;
1674+ int status = 0;
1675+ dict_table_t* table;
1676+
1677+ DBUG_ENTER("i_s_innodb_table_stats_fill");
1678+
1679+ /* deny access to non-superusers */
1680+ if (check_global_access(thd, PROCESS_ACL)) {
1681+ DBUG_RETURN(0);
1682+ }
1683+
1684+ mutex_enter(&(dict_sys->mutex));
1685+
1686+ table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1687+
1688+ while (table) {
1689+ char buf[NAME_LEN * 2 + 2];
1690+ char* ptr;
1691+
1692+ if (table->stat_clustered_index_size == 0) {
1693+ table = UT_LIST_GET_NEXT(table_LRU, table);
1694+ continue;
1695+ }
1696+
1697+ buf[NAME_LEN * 2 + 1] = 0;
1698+ strncpy(buf, table->name, NAME_LEN * 2 + 1);
1699+ ptr = strchr(buf, '/');
1700+ if (ptr) {
1701+ *ptr = '\0';
1702+ ++ptr;
1703+ } else {
1704+ ptr = buf;
1705+ }
1706+
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);
1713+
1714+ if (schema_table_store_record(thd, i_s_table)) {
1715+ status = 1;
1716+ break;
1717+ }
1718+
1719+ table = UT_LIST_GET_NEXT(table_LRU, table);
1720+ }
1721+
1722+ mutex_exit(&(dict_sys->mutex));
1723+
1724+ DBUG_RETURN(status);
1725+}
1726+
1727+static
1728+int
1729+i_s_innodb_index_stats_fill(
1730+/*========================*/
1731+ THD* thd,
1732+ TABLE_LIST* tables,
1733+ COND* cond)
1734+{
1735+ TABLE* i_s_table = (TABLE *) tables->table;
1736+ int status = 0;
1737+ dict_table_t* table;
1738+ dict_index_t* index;
1739+
1740+ DBUG_ENTER("i_s_innodb_index_stats_fill");
1741+
1742+ /* deny access to non-superusers */
1743+ if (check_global_access(thd, PROCESS_ACL)) {
1744+ DBUG_RETURN(0);
1745+ }
1746+
1747+ mutex_enter(&(dict_sys->mutex));
1748+
1749+ table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1750+
1751+ while (table) {
1752+ if (table->stat_clustered_index_size == 0) {
1753+ table = UT_LIST_GET_NEXT(table_LRU, table);
1754+ continue;
1755+ }
1756+
1757+ ib_int64_t n_rows = table->stat_n_rows;
1758+
1759+ if (n_rows < 0) {
1760+ n_rows = 0;
1761+ }
1762+
1763+ index = dict_table_get_first_index(table);
1764+
1765+ while (index) {
1766+ char buff[256+1];
1767+ char row_per_keys[256+1];
1768+ char buf[NAME_LEN * 2 + 2];
1769+ char* ptr;
1770+ ulint i;
1771+
1772+ buf[NAME_LEN * 2 + 1] = 0;
1773+ strncpy(buf, table->name, NAME_LEN * 2 + 1);
1774+ ptr = strchr(buf, '/');
1775+ if (ptr) {
1776+ *ptr = '\0';
1777+ ++ptr;
1778+ } else {
1779+ ptr = buf;
1780+ }
1781+
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);
1786+
1787+ row_per_keys[0] = '\0';
1788+
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];
1796+ } else {
1797+ rec_per_key = n_rows;
1798+ }
1799+ ut_snprintf(buff, 256, (i == index->n_uniq)?"%llu":"%llu, ",
1800+ rec_per_key);
1801+ strncat(row_per_keys, buff, 256 - strlen(row_per_keys));
1802+ }
1803+ }
1804+ //dict_index_stat_mutex_exit(index);
1805+
1806+ field_store_string(i_s_table->field[4], row_per_keys);
1807+
1808+ i_s_table->field[5]->store(index->stat_index_size);
1809+ i_s_table->field[6]->store(index->stat_n_leaf_pages);
1810+
1811+ if (schema_table_store_record(thd, i_s_table)) {
1812+ status = 1;
1813+ break;
1814+ }
1815+
1816+ index = dict_table_get_next_index(index);
1817+ }
1818+
1819+ if (status == 1) {
1820+ break;
1821+ }
1822+
1823+ table = UT_LIST_GET_NEXT(table_LRU, table);
1824+ }
1825+
1826+ mutex_exit(&(dict_sys->mutex));
1827+
1828+ DBUG_RETURN(status);
1829+}
1830+
1831+static
1832+int
1833+i_s_innodb_table_stats_init(
1834+/*========================*/
1835+ void* p)
1836+{
1837+ DBUG_ENTER("i_s_innodb_table_stats_init");
1838+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1839+
1840+ schema->fields_info = i_s_innodb_table_stats_info;
1841+ schema->fill_table = i_s_innodb_table_stats_fill;
1842+
1843+ DBUG_RETURN(0);
1844+}
1845+
1846+static
1847+int
1848+i_s_innodb_index_stats_init(
1849+/*========================*/
1850+ void* p)
1851+{
1852+ DBUG_ENTER("i_s_innodb_index_stats_init");
1853+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1854+
1855+ schema->fields_info = i_s_innodb_index_stats_info;
1856+ schema->fill_table = i_s_innodb_index_stats_fill;
1857+
1858+ DBUG_RETURN(0);
1859+}
1860+
1861+UNIV_INTERN struct st_mysql_plugin i_s_innodb_table_stats =
1862+{
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)
1875+};
1876+
1877+UNIV_INTERN struct st_mysql_plugin i_s_innodb_index_stats =
1878+{
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)
1891+};
1892diff -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
1895@@ -41,5 +41,8 @@
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;
1902
1903 #endif /* i_s_h */
1904diff -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
1907@@ -104,6 +104,7 @@
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
1914
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
1918 index tree */
1919+#define DICT_HDR_STATS 52 /* Root of the stats tree */
1920
1921 #define DICT_HDR_FSEG_HEADER 56 /* Segment header for the tablespace
1922 segment into which the dictionary
1923 header is created */
1924+
1925+#define DICT_HDR_XTRADB_MARK 256 /* Flag to distinguish expansion of XtraDB */
1926 /*-------------------------------------------------------------*/
1927
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
1932
1933+#define DICT_SYS_STATS_DIFF_VALS_FIELD 4
1934+
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
1937 updated */
1938 #define DICT_HDR_ROW_ID_WRITE_MARGIN 256
1939
1940+#define DICT_HDR_XTRADB_FLAG 0x5854524144425F31ULL /* "XTRADB_1" */
1941+
1942 #ifndef UNIV_NONINL
1943 #include "dict0boot.ic"
1944 #endif
1945diff -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
1948@@ -53,6 +53,14 @@
1949 dict_index_t* index, /*!< in: index to create, built as a memory data
1950 structure */
1951 mem_heap_t* heap); /*!< in: heap where created */
1952+/*********************************************************************//**
1953+*/
1954+UNIV_INTERN
1955+ind_node_t*
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 */
1963@@ -62,6 +70,13 @@
1964 /*===================*/
1965 que_thr_t* thr); /*!< in: query thread */
1966 /***********************************************************//**
1967+*/
1968+UNIV_INTERN
1969+que_thr_t*
1970+dict_insert_stats_step(
1971+/*===================*/
1972+ que_thr_t* thr);
1973+/***********************************************************//**
1974 Creates an index. This is a high-level function used in SQL execution
1975 graphs.
1976 @return query thread to run next or NULL */
1977@@ -170,6 +185,7 @@
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 */
1985@@ -180,6 +196,7 @@
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 */
1989+ ulint stats_no;
1990 mem_heap_t* heap; /*!< memory heap used as auxiliary storage */
1991 };
1992
1993@@ -189,6 +206,7 @@
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
1998
1999 #ifndef UNIV_NONINL
2000 #include "dict0crea.ic"
2001diff -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
2012 do nothing */
2013+ ibool sync);
2014 /********************************************************************//**
2015 Reserves the dictionary system mutex for MySQL. */
2016 UNIV_INTERN
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 */
2022 };
2023 #endif /* !UNIV_HOTBACKUP */
2024
2025diff -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
2028@@ -41,6 +41,7 @@
2029 SYS_FIELDS,
2030 SYS_FOREIGN,
2031 SYS_FOREIGN_COLS,
2032+ SYS_STATS,
2033
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 */
2044+UNIV_INTERN
2045+const char*
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 */
2053 #ifndef UNIV_NONINL
2054 #include "dict0load.ic"
2055 #endif
2056diff -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 */
2063+
2064+UNIV_INTERN
2065+void
2066+page_cur_open_on_nth_user_rec(
2067+/*==========================*/
2068+ buf_block_t* block, /*!< in: page */
2069+ page_cur_t* cursor, /*!< out: page cursor */
2070+ ulint nth);
2071+
2072+UNIV_INTERN
2073+ibool
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 */
2078+ ulint nth);
2079 #endif /* !UNIV_HOTBACKUP */
2080 /***********************************************************//**
2081 Parses a log record of a record insert on a page.
2082diff -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
2085@@ -492,6 +492,8 @@
2086 #define QUE_NODE_CALL 31
2087 #define QUE_NODE_EXIT 32
2088
2089+#define QUE_NODE_INSERT_STATS 34
2090+
2091 /* Query thread states */
2092 #define QUE_THR_RUNNING 1
2093 #define QUE_THR_PROCEDURE_WAIT 2
2094diff -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
2100 comparison */
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.
2110diff -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
2113@@ -87,5 +87,5 @@
2114 ulint match_b = 0;
2115
2116 return(cmp_rec_rec_with_match(rec1, rec2, offsets1, offsets2, index,
2117- &match_f, &match_b));
2118+ &match_f, &match_b, 0));
2119 }
2120diff -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
2125 large. */
2126 /*********************************************************************//**
2127+*/
2128+UNIV_INTERN
2129+int
2130+row_insert_stats_for_mysql(
2131+/*=======================*/
2132+ dict_index_t* index,
2133+ trx_t* trx);
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.
2138diff -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;
2143
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;
2152
2153 extern ibool srv_use_doublewrite_buf;
2154 extern ibool srv_use_checksums;
2155diff -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 @@
2159 } while (rnd--);
2160 }
2161
2162+UNIV_INTERN
2163+void
2164+page_cur_open_on_nth_user_rec(
2165+/*==========================*/
2166+ buf_block_t* block, /*!< in: page */
2167+ page_cur_t* cursor, /*!< out: page cursor */
2168+ ulint nth)
2169+{
2170+ ulint n_recs = page_get_n_recs(buf_block_get_frame(block));
2171+
2172+ page_cur_set_before_first(block, cursor);
2173+
2174+ if (UNIV_UNLIKELY(n_recs == 0)) {
2175+
2176+ return;
2177+ }
2178+
2179+ nth--;
2180+
2181+ if (nth >= n_recs) {
2182+ nth = n_recs - 1;
2183+ }
2184+
2185+ do {
2186+ page_cur_move_to_next(cursor);
2187+ } while (nth--);
2188+}
2189+
2190+UNIV_INTERN
2191+ibool
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 */
2196+ ulint nth)
2197+{
2198+ ulint rnd;
2199+ ulint n_recs = page_get_n_recs(buf_block_get_frame(block));
2200+ ibool ret;
2201+
2202+ page_cur_set_before_first(block, cursor);
2203+
2204+ if (UNIV_UNLIKELY(n_recs == 0)) {
2205+
2206+ return (FALSE);
2207+ }
2208+
2209+ nth--;
2210+
2211+ if (nth >= n_recs) {
2212+ nth = n_recs - 1;
2213+ }
2214+
2215+ rnd = (ulint) (nth + page_cur_lcg_prng() % (n_recs - nth));
2216+
2217+ if (rnd == nth) {
2218+ ret = TRUE;
2219+ } else {
2220+ ret = FALSE;
2221+ }
2222+
2223+ do {
2224+ page_cur_move_to_next(cursor);
2225+ } while (rnd--);
2226+
2227+ return (ret);
2228+}
2229+
2230 /***********************************************************//**
2231 Writes the log record of a record insert on a page. */
2232 static
2233diff -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 @@
2237
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);
2243
2244 mem_heap_free(cre_ind->heap);
2245
2246 break;
2247+ case QUE_NODE_INSERT_STATS:
2248+ cre_ind = node;
2249+
2250+ que_graph_free_recursive(cre_ind->stats_def);
2251+ que_graph_free_recursive(cre_ind->commit_node);
2252+
2253+ mem_heap_free(cre_ind->heap);
2254+ break;
2255 case QUE_NODE_PROC:
2256 que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
2257
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) {
2265 str = "FOR LOOP";
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);
2275 } else {
2276diff -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
2282 comparison */
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)
2289 {
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 @@
2293
2294 if (rec1_f_len == rec2_f_len) {
2295
2296- goto next_field;
2297+ if (stats_method == SRV_STATS_METHOD_NULLS_EQUAL) {
2298+ goto next_field;
2299+ } else {
2300+ ret = -1;
2301+ }
2302
2303 } else if (rec2_f_len == UNIV_SQL_NULL) {
2304
2305diff -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"
2311 "COMMIT WORK;\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. */
2317diff -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
2320@@ -921,6 +921,9 @@
2321
2322 table->stat_modified_counter = counter + 1;
2323
2324+ if (!srv_stats_auto_update)
2325+ return;
2326+
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).
2330@@ -931,7 +934,7 @@
2331 || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
2332
2333 dict_update_statistics(table, FALSE /* update even if stats
2334- are initialized */);
2335+ are initialized */, TRUE);
2336 }
2337 }
2338
d8778560 2339@@ -2103,6 +2106,45 @@
b4e1fa2c
AM
2340 }
2341
2342 /*********************************************************************//**
2343+*/
2344+UNIV_INTERN
2345+int
2346+row_insert_stats_for_mysql(
2347+/*=======================*/
2348+ dict_index_t* index,
2349+ trx_t* trx)
2350+{
2351+ ind_node_t* node;
2352+ mem_heap_t* heap;
2353+ que_thr_t* thr;
2354+ ulint err;
2355+
2356+ ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2357+
2358+ trx->op_info = "try to insert rows to SYS_STATS";
2359+
2360+ trx_start_if_not_started(trx);
2361+ trx->error_state = DB_SUCCESS;
2362+
2363+ heap = mem_heap_create(512);
2364+
2365+ node = ind_insert_stats_graph_create(index, heap);
2366+
2367+ thr = pars_complete_graph_for_exec(node, trx, heap);
2368+
2369+ ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2370+ que_run_threads(thr);
2371+
2372+ err = trx->error_state;
2373+
2374+ que_graph_free((que_t*) que_node_get_parent(thr));
2375+
2376+ trx->op_info = "";
2377+
2378+ return((int) err);
2379+}
2380+
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.
d8778560 2385@@ -3022,7 +3064,7 @@
b4e1fa2c
AM
2386 dict_table_autoinc_initialize(table, 1);
2387 dict_table_autoinc_unlock(table);
2388 dict_update_statistics(table, FALSE /* update even if stats are
2389- initialized */);
2390+ initialized */, TRUE);
2391
2392 trx_commit_for_mysql(trx);
2393
d8778560 2394@@ -3324,6 +3366,8 @@
b4e1fa2c
AM
2395 " IF (SQL % NOTFOUND) THEN\n"
2396 " found := 0;\n"
2397 " ELSE\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"
2403diff -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
d8778560 2406@@ -397,6 +397,10 @@
b4e1fa2c
AM
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;
2414
2415 UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE;
2416 UNIV_INTERN ibool srv_use_checksums = TRUE;
This page took 4.415575 seconds and 4 git commands to generate.