]> git.pld-linux.org Git - packages/mysql.git/blame - innodb_stats.patch
- rel 0.5 (consider this to be test before rel 1); update percona patches; drop obsol...
[packages/mysql.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 /*************************************************************//**
119@@ -3488,6 +3589,154 @@
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. */
274@@ -3516,18 +3765,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_);
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 }
316@@ -3539,9 +3808,15 @@
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
332@@ -3552,7 +3827,13 @@
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;
346@@ -3561,7 +3842,8 @@
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 }
356@@ -3575,7 +3857,10 @@
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
368@@ -3636,7 +3921,7 @@
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)
377@@ -3651,7 +3936,7 @@
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
386@@ -3660,6 +3945,15 @@
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
738@@ -754,7 +754,7 @@
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);
747@@ -4291,6 +4291,240 @@
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)"
834+ " not fonund in SYS_STATS\n",
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 */
943+ btr_pcur_close(&pcur);
944+ mtr_commit(&mtr);
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
988@@ -4298,10 +4532,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
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;
1001@@ -4318,6 +4553,27 @@
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
1012+ fprintf(stderr, "InnoDB: DEBUG: reload_statistics is scceeded for %s.\n",
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
1029@@ -4378,6 +4634,11 @@
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[
1041@@ -4472,7 +4733,8 @@
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
1054@@ -49,7 +49,8 @@
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.
1064@@ -342,12 +343,13 @@
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);
1079@@ -565,6 +567,61 @@
1080
1081 return(NULL);
1082 }
1083+/********************************************************************//**
1084+This function parses a SYS_STATS record and extract necessary
1085+information from the record and return to caller.
1086+@return error message, or NULL on success */
1087+UNIV_INTERN
1088+const char*
1089+dict_process_sys_stats_rec(
1090+/*=============================*/
1091+ mem_heap_t* heap, /*!< in/out: heap memory */
1092+ const rec_t* rec, /*!< in: current SYS_STATS rec */
1093+ index_id_t* index_id, /*!< out: INDEX_ID */
1094+ ulint* key_cols, /*!< out: KEY_COLS */
1095+ ib_uint64_t* diff_vals) /*!< out: DIFF_VALS */
1096+{
1097+ ulint len;
1098+ const byte* field;
1099+
1100+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1101+ return("delete-marked record in SYS_STATS");
1102+ }
1103+
1104+ if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
1105+ return("wrong number of columns in SYS_STATS record");
1106+ }
1107+
1108+ field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
1109+ if (UNIV_UNLIKELY(len != 8)) {
1110+err_len:
1111+ return("incorrect column length in SYS_STATS");
1112+ }
1113+ *index_id = mach_read_from_8(field);
1114+
1115+ field = rec_get_nth_field_old(rec, 1/*KEY_COLS*/, &len);
1116+ if (UNIV_UNLIKELY(len != 4)) {
1117+ goto err_len;
1118+ }
1119+ *key_cols = mach_read_from_4(field);
1120+
1121+ rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
1122+ if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
1123+ goto err_len;
1124+ }
1125+ rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
1126+ if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
1127+ goto err_len;
1128+ }
1129+
1130+ field = rec_get_nth_field_old(rec, 4/*DIFF_VALS*/, &len);
1131+ if (UNIV_UNLIKELY(len != 8)) {
1132+ goto err_len;
1133+ }
1134+ *diff_vals = mach_read_from_8(field);
1135+
1136+ return(NULL);
1137+}
1138 /********************************************************************//**
1139 Determine the flags of a table described in SYS_TABLES.
1140 @return compressed page size in kilobytes; or 0 if the tablespace is
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;
1152@@ -2387,6 +2388,8 @@
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 */
1161@@ -5190,6 +5193,10 @@
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;
1172@@ -5526,6 +5533,10 @@
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,
1183@@ -5579,6 +5590,10 @@
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(
1194@@ -6106,6 +6121,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_END_OF_FILE;
1206@@ -8000,11 +8020,31 @@
1207 /* In sql_show we call with this flag: update
1208 then statistics so that they are up-to-date */
1209
1210+ if (srv_use_sys_stats_table && !((ib_table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)
1211+ && called_from_analyze) {
1212+ /* If the indexes on the table don't have enough rows in SYS_STATS system table, */
1213+ /* they need to be created. */
1214+ dict_index_t* index;
1215+
1216+ prebuilt->trx->op_info = "confirming rows of SYS_STATS to store statistics";
1217+
1218+ ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
1219+
1220+ for (index = dict_table_get_first_index(ib_table);
1221+ index != NULL;
1222+ index = dict_table_get_next_index(index)) {
1223+ row_insert_stats_for_mysql(index, prebuilt->trx);
1224+ innobase_commit_low(prebuilt->trx);
1225+ }
1226+
1227+ ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
1228+ }
1229+
1230 prebuilt->trx->op_info = "updating table statistics";
1231
1232 dict_update_statistics(ib_table,
1233 FALSE /* update even if stats
1234- are initialized */);
1235+ are initialized */, called_from_analyze);
1236
1237 prebuilt->trx->op_info = "returning various info to MySQL";
1238 }
1239@@ -8082,7 +8122,7 @@
1240 are asked by MySQL to avoid locking. Another reason to
1241 avoid the call is that it uses quite a lot of CPU.
1242 See Bug#38185. */
1243- if (flag & HA_STATUS_NO_LOCK) {
1244+ if (flag & HA_STATUS_NO_LOCK || !srv_stats_update_need_lock) {
1245 /* We do not update delete_length if no
1246 locking is requested so the "old" value can
1247 remain. delete_length is initialized to 0 in
1248@@ -11283,6 +11323,45 @@
1249 "The number of index pages to sample when calculating statistics (default 8)",
1250 NULL, NULL, 8, 1, ~0ULL, 0);
1251
1252+const char *innobase_stats_method_names[]=
1253+{
1254+ "nulls_equal",
1255+ "nulls_unequal",
1256+ "nulls_ignored",
1257+ NullS
1258+};
1259+TYPELIB innobase_stats_method_typelib=
1260+{
1261+ array_elements(innobase_stats_method_names) - 1, "innobase_stats_method_typelib",
1262+ innobase_stats_method_names, NULL
1263+};
1264+static MYSQL_SYSVAR_ENUM(stats_method, srv_stats_method,
1265+ PLUGIN_VAR_RQCMDARG,
1266+ "Specifies how InnoDB index statistics collection code should threat NULLs. "
1267+ "Possible values of name are same to for 'myisam_stats_method'. "
1268+ "This is startup parameter.",
1269+ NULL, NULL, 0, &innobase_stats_method_typelib);
1270+
1271+static MYSQL_SYSVAR_ULONG(stats_auto_update, srv_stats_auto_update,
1272+ PLUGIN_VAR_RQCMDARG,
1273+ "Enable/Disable InnoDB's auto update statistics of indexes. "
1274+ "(except for ANALYZE TABLE command) 0:disable 1:enable",
1275+ NULL, NULL, 1, 0, 1, 0);
1276+
1277+static MYSQL_SYSVAR_ULONG(stats_update_need_lock, srv_stats_update_need_lock,
1278+ PLUGIN_VAR_RQCMDARG,
1279+ "Enable/Disable InnoDB's update statistics which needs to lock dictionary. "
1280+ "e.g. Data_free.",
1281+ NULL, NULL, 1, 0, 1, 0);
1282+
1283+static MYSQL_SYSVAR_BOOL(use_sys_stats_table, innobase_use_sys_stats_table,
1284+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
1285+ "Enable to use SYS_STATS system table to store statistics statically, "
1286+ "And avoids to calculate statistics at every first open of the tables. "
1287+ "This option may make the opportunities of update statistics less. "
1288+ "So you should use ANALYZE TABLE command intentionally.",
1289+ NULL, NULL, FALSE);
1290+
1291 static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
1292 PLUGIN_VAR_OPCMDARG,
1293 "Enable InnoDB adaptive hash index (enabled by default). "
1294@@ -11611,6 +11690,10 @@
1295 MYSQL_SYSVAR(overwrite_relay_log_info),
1296 MYSQL_SYSVAR(rollback_on_timeout),
1297 MYSQL_SYSVAR(stats_on_metadata),
1298+ MYSQL_SYSVAR(stats_method),
1299+ MYSQL_SYSVAR(stats_auto_update),
1300+ MYSQL_SYSVAR(stats_update_need_lock),
1301+ MYSQL_SYSVAR(use_sys_stats_table),
1302 MYSQL_SYSVAR(stats_sample_pages),
1303 MYSQL_SYSVAR(adaptive_hash_index),
1304 MYSQL_SYSVAR(replication_delay),
1305@@ -11680,7 +11763,10 @@
1306 i_s_innodb_sys_columns,
1307 i_s_innodb_sys_fields,
1308 i_s_innodb_sys_foreign,
1309-i_s_innodb_sys_foreign_cols
1310+i_s_innodb_sys_foreign_cols,
1311+i_s_innodb_sys_stats,
1312+i_s_innodb_table_stats,
1313+i_s_innodb_index_stats
1314 mysql_declare_plugin_end;
1315
1316 /** @brief Initialize the default value of innodb_commit_concurrency.
1317diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
1318--- a/storage/innobase/handler/i_s.cc 2010-12-03 17:17:03.666956117 +0900
1319+++ b/storage/innobase/handler/i_s.cc 2010-12-03 17:19:24.880964526 +0900
1320@@ -49,6 +49,7 @@
1321 #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
1322 #include "trx0rseg.h" /* for trx_rseg_struct */
1323 #include "trx0sys.h" /* for trx_sys */
1324+#include "dict0dict.h" /* for dict_sys */
1325 }
1326
1327 static const char plugin_author[] = "Innobase Oy";
1328@@ -3458,6 +3459,203 @@
1329 STRUCT_FLD(__reserved1, NULL)
1330 };
1331
1332+/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_stats */
1333+static ST_FIELD_INFO innodb_sys_stats_fields_info[] =
1334+{
1335+#define SYS_STATS_INDEX_ID 0
1336+ {STRUCT_FLD(field_name, "INDEX_ID"),
1337+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1338+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1339+ STRUCT_FLD(value, 0),
1340+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1341+ STRUCT_FLD(old_name, ""),
1342+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1343+
1344+#define SYS_STATS_KEY_COLS 1
1345+ {STRUCT_FLD(field_name, "KEY_COLS"),
1346+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
1347+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
1348+ STRUCT_FLD(value, 0),
1349+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1350+ STRUCT_FLD(old_name, ""),
1351+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1352+
1353+#define SYS_STATS_DIFF_VALS 2
1354+ {STRUCT_FLD(field_name, "DIFF_VALS"),
1355+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1356+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1357+ STRUCT_FLD(value, 0),
1358+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1359+ STRUCT_FLD(old_name, ""),
1360+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1361+
1362+ END_OF_ST_FIELD_INFO
1363+};
1364+/**********************************************************************//**
1365+Function to fill information_schema.innodb_sys_stats
1366+@return 0 on success */
1367+static
1368+int
1369+i_s_dict_fill_sys_stats(
1370+/*====================*/
1371+ THD* thd, /*!< in: thread */
1372+ index_id_t index_id, /*!< in: INDEX_ID */
1373+ ulint key_cols, /*!< in: KEY_COLS */
1374+ ib_uint64_t diff_vals, /*!< in: DIFF_VALS */
1375+ TABLE* table_to_fill) /*!< in/out: fill this table */
1376+{
1377+ Field** fields;
1378+
1379+ DBUG_ENTER("i_s_dict_fill_sys_stats");
1380+
1381+ fields = table_to_fill->field;
1382+
1383+ OK(fields[SYS_STATS_INDEX_ID]->store(longlong(index_id), TRUE));
1384+
1385+ OK(fields[SYS_STATS_KEY_COLS]->store(key_cols));
1386+
1387+ OK(fields[SYS_STATS_DIFF_VALS]->store(longlong(diff_vals), TRUE));
1388+
1389+ OK(schema_table_store_record(thd, table_to_fill));
1390+
1391+ DBUG_RETURN(0);
1392+}
1393+/*******************************************************************//**
1394+Function to populate INFORMATION_SCHEMA.innodb_sys_stats table.
1395+@return 0 on success */
1396+static
1397+int
1398+i_s_sys_stats_fill_table(
1399+/*=====================*/
1400+ THD* thd, /*!< in: thread */
1401+ TABLE_LIST* tables, /*!< in/out: tables to fill */
1402+ COND* cond) /*!< in: condition (not used) */
1403+{
1404+ btr_pcur_t pcur;
1405+ const rec_t* rec;
1406+ mem_heap_t* heap;
1407+ mtr_t mtr;
1408+
1409+ DBUG_ENTER("i_s_sys_stats_fill_table");
1410+
1411+ /* deny access to non-superusers */
1412+ if (check_global_access(thd, PROCESS_ACL)) {
1413+ DBUG_RETURN(0);
1414+ }
1415+
1416+ heap = mem_heap_create(1000);
1417+ mutex_enter(&dict_sys->mutex);
1418+ mtr_start(&mtr);
1419+
1420+ rec = dict_startscan_system(&pcur, &mtr, SYS_STATS);
1421+
1422+ while (rec) {
1423+ const char* err_msg;
1424+ index_id_t index_id;
1425+ ulint key_cols;
1426+ ib_uint64_t diff_vals;
1427+
1428+ /* Extract necessary information from a SYS_FOREIGN_COLS row */
1429+ err_msg = dict_process_sys_stats_rec(
1430+ heap, rec, &index_id, &key_cols, &diff_vals);
1431+
1432+ mtr_commit(&mtr);
1433+ mutex_exit(&dict_sys->mutex);
1434+
1435+ if (!err_msg) {
1436+ i_s_dict_fill_sys_stats(
1437+ thd, index_id, key_cols, diff_vals,
1438+ tables->table);
1439+ } else {
1440+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
1441+ ER_CANT_FIND_SYSTEM_REC,
1442+ err_msg);
1443+ }
1444+
1445+ mem_heap_empty(heap);
1446+
1447+ /* Get the next record */
1448+ mutex_enter(&dict_sys->mutex);
1449+ mtr_start(&mtr);
1450+ rec = dict_getnext_system(&pcur, &mtr);
1451+ }
1452+
1453+ mtr_commit(&mtr);
1454+ mutex_exit(&dict_sys->mutex);
1455+ mem_heap_free(heap);
1456+
1457+ DBUG_RETURN(0);
1458+}
1459+/*******************************************************************//**
1460+Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_stats
1461+@return 0 on success */
1462+static
1463+int
1464+innodb_sys_stats_init(
1465+/*========================*/
1466+ void* p) /*!< in/out: table schema object */
1467+{
1468+ ST_SCHEMA_TABLE* schema;
1469+
1470+ DBUG_ENTER("innodb_sys_stats_init");
1471+
1472+ schema = (ST_SCHEMA_TABLE*) p;
1473+
1474+ schema->fields_info = innodb_sys_stats_fields_info;
1475+ schema->fill_table = i_s_sys_stats_fill_table;
1476+
1477+ DBUG_RETURN(0);
1478+}
1479+
1480+UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_stats =
1481+{
1482+ /* the plugin type (a MYSQL_XXX_PLUGIN value) */
1483+ /* int */
1484+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1485+
1486+ /* pointer to type-specific plugin descriptor */
1487+ /* void* */
1488+ STRUCT_FLD(info, &i_s_info),
1489+
1490+ /* plugin name */
1491+ /* const char* */
1492+ STRUCT_FLD(name, "INNODB_SYS_STATS"),
1493+
1494+ /* plugin author (for SHOW PLUGINS) */
1495+ /* const char* */
1496+ STRUCT_FLD(author, plugin_author),
1497+
1498+ /* general descriptive text (for SHOW PLUGINS) */
1499+ /* const char* */
1500+ STRUCT_FLD(descr, "XtraDB SYS_STATS table"),
1501+
1502+ /* the plugin license (PLUGIN_LICENSE_XXX) */
1503+ /* int */
1504+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1505+
1506+ /* the function to invoke when plugin is loaded */
1507+ /* int (*)(void*); */
1508+ STRUCT_FLD(init, innodb_sys_stats_init),
1509+
1510+ /* the function to invoke when plugin is unloaded */
1511+ /* int (*)(void*); */
1512+ STRUCT_FLD(deinit, i_s_common_deinit),
1513+
1514+ /* plugin version (for SHOW PLUGINS) */
1515+ /* unsigned int */
1516+ STRUCT_FLD(version, INNODB_VERSION_SHORT),
1517+
1518+ /* struct st_mysql_show_var* */
1519+ STRUCT_FLD(status_vars, NULL),
1520+
1521+ /* struct st_mysql_sys_var** */
1522+ STRUCT_FLD(system_vars, NULL),
1523+
1524+ /* reserved for dependency checking */
1525+ /* void* */
1526+ STRUCT_FLD(__reserved1, NULL)
1527+};
1528+
1529 /***********************************************************************
1530 */
1531 static ST_FIELD_INFO i_s_innodb_rseg_fields_info[] =
1532@@ -3620,3 +3818,347 @@
1533 /* void* */
1534 STRUCT_FLD(__reserved1, NULL)
1535 };
1536+
1537+/***********************************************************************
1538+*/
1539+static ST_FIELD_INFO i_s_innodb_table_stats_info[] =
1540+{
1541+ {STRUCT_FLD(field_name, "table_schema"),
1542+ STRUCT_FLD(field_length, NAME_LEN),
1543+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1544+ STRUCT_FLD(value, 0),
1545+ STRUCT_FLD(field_flags, 0),
1546+ STRUCT_FLD(old_name, ""),
1547+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1548+
1549+ {STRUCT_FLD(field_name, "table_name"),
1550+ STRUCT_FLD(field_length, NAME_LEN),
1551+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1552+ STRUCT_FLD(value, 0),
1553+ STRUCT_FLD(field_flags, 0),
1554+ STRUCT_FLD(old_name, ""),
1555+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1556+
1557+ {STRUCT_FLD(field_name, "rows"),
1558+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1559+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1560+ STRUCT_FLD(value, 0),
1561+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1562+ STRUCT_FLD(old_name, ""),
1563+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1564+
1565+ {STRUCT_FLD(field_name, "clust_size"),
1566+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1567+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1568+ STRUCT_FLD(value, 0),
1569+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1570+ STRUCT_FLD(old_name, ""),
1571+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1572+
1573+ {STRUCT_FLD(field_name, "other_size"),
1574+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1575+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1576+ STRUCT_FLD(value, 0),
1577+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1578+ STRUCT_FLD(old_name, ""),
1579+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1580+
1581+ {STRUCT_FLD(field_name, "modified"),
1582+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1583+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1584+ STRUCT_FLD(value, 0),
1585+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1586+ STRUCT_FLD(old_name, ""),
1587+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1588+
1589+ END_OF_ST_FIELD_INFO
1590+};
1591+
1592+static ST_FIELD_INFO i_s_innodb_index_stats_info[] =
1593+{
1594+ {STRUCT_FLD(field_name, "table_schema"),
1595+ STRUCT_FLD(field_length, NAME_LEN),
1596+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1597+ STRUCT_FLD(value, 0),
1598+ STRUCT_FLD(field_flags, 0),
1599+ STRUCT_FLD(old_name, ""),
1600+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1601+
1602+ {STRUCT_FLD(field_name, "table_name"),
1603+ STRUCT_FLD(field_length, NAME_LEN),
1604+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1605+ STRUCT_FLD(value, 0),
1606+ STRUCT_FLD(field_flags, 0),
1607+ STRUCT_FLD(old_name, ""),
1608+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1609+
1610+ {STRUCT_FLD(field_name, "index_name"),
1611+ STRUCT_FLD(field_length, NAME_LEN),
1612+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1613+ STRUCT_FLD(value, 0),
1614+ STRUCT_FLD(field_flags, 0),
1615+ STRUCT_FLD(old_name, ""),
1616+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1617+
1618+ {STRUCT_FLD(field_name, "fields"),
1619+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1620+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1621+ STRUCT_FLD(value, 0),
1622+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1623+ STRUCT_FLD(old_name, ""),
1624+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1625+
1626+ {STRUCT_FLD(field_name, "rows_per_key"),
1627+ STRUCT_FLD(field_length, 256),
1628+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1629+ STRUCT_FLD(value, 0),
1630+ STRUCT_FLD(field_flags, 0),
1631+ STRUCT_FLD(old_name, ""),
1632+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1633+
1634+ {STRUCT_FLD(field_name, "index_total_pages"),
1635+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1636+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1637+ STRUCT_FLD(value, 0),
1638+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1639+ STRUCT_FLD(old_name, ""),
1640+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1641+
1642+ {STRUCT_FLD(field_name, "index_leaf_pages"),
1643+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1644+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1645+ STRUCT_FLD(value, 0),
1646+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1647+ STRUCT_FLD(old_name, ""),
1648+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1649+
1650+ END_OF_ST_FIELD_INFO
1651+};
1652+
1653+static
1654+int
1655+i_s_innodb_table_stats_fill(
1656+/*========================*/
1657+ THD* thd,
1658+ TABLE_LIST* tables,
1659+ COND* cond)
1660+{
1661+ TABLE* i_s_table = (TABLE *) tables->table;
1662+ int status = 0;
1663+ dict_table_t* table;
1664+
1665+ DBUG_ENTER("i_s_innodb_table_stats_fill");
1666+
1667+ /* deny access to non-superusers */
1668+ if (check_global_access(thd, PROCESS_ACL)) {
1669+ DBUG_RETURN(0);
1670+ }
1671+
1672+ mutex_enter(&(dict_sys->mutex));
1673+
1674+ table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1675+
1676+ while (table) {
1677+ char buf[NAME_LEN * 2 + 2];
1678+ char* ptr;
1679+
1680+ if (table->stat_clustered_index_size == 0) {
1681+ table = UT_LIST_GET_NEXT(table_LRU, table);
1682+ continue;
1683+ }
1684+
1685+ buf[NAME_LEN * 2 + 1] = 0;
1686+ strncpy(buf, table->name, NAME_LEN * 2 + 1);
1687+ ptr = strchr(buf, '/');
1688+ if (ptr) {
1689+ *ptr = '\0';
1690+ ++ptr;
1691+ } else {
1692+ ptr = buf;
1693+ }
1694+
1695+ field_store_string(i_s_table->field[0], buf);
1696+ field_store_string(i_s_table->field[1], ptr);
1697+ i_s_table->field[2]->store(table->stat_n_rows);
1698+ i_s_table->field[3]->store(table->stat_clustered_index_size);
1699+ i_s_table->field[4]->store(table->stat_sum_of_other_index_sizes);
1700+ i_s_table->field[5]->store(table->stat_modified_counter);
1701+
1702+ if (schema_table_store_record(thd, i_s_table)) {
1703+ status = 1;
1704+ break;
1705+ }
1706+
1707+ table = UT_LIST_GET_NEXT(table_LRU, table);
1708+ }
1709+
1710+ mutex_exit(&(dict_sys->mutex));
1711+
1712+ DBUG_RETURN(status);
1713+}
1714+
1715+static
1716+int
1717+i_s_innodb_index_stats_fill(
1718+/*========================*/
1719+ THD* thd,
1720+ TABLE_LIST* tables,
1721+ COND* cond)
1722+{
1723+ TABLE* i_s_table = (TABLE *) tables->table;
1724+ int status = 0;
1725+ dict_table_t* table;
1726+ dict_index_t* index;
1727+
1728+ DBUG_ENTER("i_s_innodb_index_stats_fill");
1729+
1730+ /* deny access to non-superusers */
1731+ if (check_global_access(thd, PROCESS_ACL)) {
1732+ DBUG_RETURN(0);
1733+ }
1734+
1735+ mutex_enter(&(dict_sys->mutex));
1736+
1737+ table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1738+
1739+ while (table) {
1740+ if (table->stat_clustered_index_size == 0) {
1741+ table = UT_LIST_GET_NEXT(table_LRU, table);
1742+ continue;
1743+ }
1744+
1745+ ib_int64_t n_rows = table->stat_n_rows;
1746+
1747+ if (n_rows < 0) {
1748+ n_rows = 0;
1749+ }
1750+
1751+ index = dict_table_get_first_index(table);
1752+
1753+ while (index) {
1754+ char buff[256+1];
1755+ char row_per_keys[256+1];
1756+ char buf[NAME_LEN * 2 + 2];
1757+ char* ptr;
1758+ ulint i;
1759+
1760+ buf[NAME_LEN * 2 + 1] = 0;
1761+ strncpy(buf, table->name, NAME_LEN * 2 + 1);
1762+ ptr = strchr(buf, '/');
1763+ if (ptr) {
1764+ *ptr = '\0';
1765+ ++ptr;
1766+ } else {
1767+ ptr = buf;
1768+ }
1769+
1770+ field_store_string(i_s_table->field[0], buf);
1771+ field_store_string(i_s_table->field[1], ptr);
1772+ field_store_string(i_s_table->field[2], index->name);
1773+ i_s_table->field[3]->store(index->n_uniq);
1774+
1775+ row_per_keys[0] = '\0';
1776+
1777+ /* It is remained optimistic operation still for now */
1778+ //dict_index_stat_mutex_enter(index);
1779+ if (index->stat_n_diff_key_vals) {
1780+ for (i = 1; i <= index->n_uniq; i++) {
1781+ ib_int64_t rec_per_key;
1782+ if (index->stat_n_diff_key_vals[i]) {
1783+ rec_per_key = n_rows / index->stat_n_diff_key_vals[i];
1784+ } else {
1785+ rec_per_key = n_rows;
1786+ }
1787+ ut_snprintf(buff, 256, (i == index->n_uniq)?"%llu":"%llu, ",
1788+ rec_per_key);
1789+ strncat(row_per_keys, buff, 256 - strlen(row_per_keys));
1790+ }
1791+ }
1792+ //dict_index_stat_mutex_exit(index);
1793+
1794+ field_store_string(i_s_table->field[4], row_per_keys);
1795+
1796+ i_s_table->field[5]->store(index->stat_index_size);
1797+ i_s_table->field[6]->store(index->stat_n_leaf_pages);
1798+
1799+ if (schema_table_store_record(thd, i_s_table)) {
1800+ status = 1;
1801+ break;
1802+ }
1803+
1804+ index = dict_table_get_next_index(index);
1805+ }
1806+
1807+ if (status == 1) {
1808+ break;
1809+ }
1810+
1811+ table = UT_LIST_GET_NEXT(table_LRU, table);
1812+ }
1813+
1814+ mutex_exit(&(dict_sys->mutex));
1815+
1816+ DBUG_RETURN(status);
1817+}
1818+
1819+static
1820+int
1821+i_s_innodb_table_stats_init(
1822+/*========================*/
1823+ void* p)
1824+{
1825+ DBUG_ENTER("i_s_innodb_table_stats_init");
1826+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1827+
1828+ schema->fields_info = i_s_innodb_table_stats_info;
1829+ schema->fill_table = i_s_innodb_table_stats_fill;
1830+
1831+ DBUG_RETURN(0);
1832+}
1833+
1834+static
1835+int
1836+i_s_innodb_index_stats_init(
1837+/*========================*/
1838+ void* p)
1839+{
1840+ DBUG_ENTER("i_s_innodb_index_stats_init");
1841+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1842+
1843+ schema->fields_info = i_s_innodb_index_stats_info;
1844+ schema->fill_table = i_s_innodb_index_stats_fill;
1845+
1846+ DBUG_RETURN(0);
1847+}
1848+
1849+UNIV_INTERN struct st_mysql_plugin i_s_innodb_table_stats =
1850+{
1851+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1852+ STRUCT_FLD(info, &i_s_info),
1853+ STRUCT_FLD(name, "INNODB_TABLE_STATS"),
1854+ STRUCT_FLD(author, plugin_author),
1855+ STRUCT_FLD(descr, "InnoDB table statistics in memory"),
1856+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1857+ STRUCT_FLD(init, i_s_innodb_table_stats_init),
1858+ STRUCT_FLD(deinit, i_s_common_deinit),
1859+ STRUCT_FLD(version, 0x0100 /* 1.0 */),
1860+ STRUCT_FLD(status_vars, NULL),
1861+ STRUCT_FLD(system_vars, NULL),
1862+ STRUCT_FLD(__reserved1, NULL)
1863+};
1864+
1865+UNIV_INTERN struct st_mysql_plugin i_s_innodb_index_stats =
1866+{
1867+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1868+ STRUCT_FLD(info, &i_s_info),
1869+ STRUCT_FLD(name, "INNODB_INDEX_STATS"),
1870+ STRUCT_FLD(author, plugin_author),
1871+ STRUCT_FLD(descr, "InnoDB index statistics in memory"),
1872+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1873+ STRUCT_FLD(init, i_s_innodb_index_stats_init),
1874+ STRUCT_FLD(deinit, i_s_common_deinit),
1875+ STRUCT_FLD(version, 0x0100 /* 1.0 */),
1876+ STRUCT_FLD(status_vars, NULL),
1877+ STRUCT_FLD(system_vars, NULL),
1878+ STRUCT_FLD(__reserved1, NULL)
1879+};
1880diff -ruN a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h
1881--- a/storage/innobase/handler/i_s.h 2010-12-03 17:17:03.668953884 +0900
1882+++ b/storage/innobase/handler/i_s.h 2010-12-03 17:19:24.882947826 +0900
1883@@ -41,5 +41,8 @@
1884 extern struct st_mysql_plugin i_s_innodb_sys_foreign;
1885 extern struct st_mysql_plugin i_s_innodb_sys_foreign_cols;
1886 extern struct st_mysql_plugin i_s_innodb_rseg;
1887+extern struct st_mysql_plugin i_s_innodb_sys_stats;
1888+extern struct st_mysql_plugin i_s_innodb_table_stats;
1889+extern struct st_mysql_plugin i_s_innodb_index_stats;
1890
1891 #endif /* i_s_h */
1892diff -ruN a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h
1893--- a/storage/innobase/include/dict0boot.h 2010-11-03 07:01:13.000000000 +0900
1894+++ b/storage/innobase/include/dict0boot.h 2010-12-03 17:19:24.885947372 +0900
1895@@ -104,6 +104,7 @@
1896 #define DICT_COLUMNS_ID 2
1897 #define DICT_INDEXES_ID 3
1898 #define DICT_FIELDS_ID 4
1899+#define DICT_STATS_ID 6
1900 /* The following is a secondary index on SYS_TABLES */
1901 #define DICT_TABLE_IDS_ID 5
1902
1903@@ -131,10 +132,13 @@
1904 #define DICT_HDR_INDEXES 44 /* Root of the index index tree */
1905 #define DICT_HDR_FIELDS 48 /* Root of the index field
1906 index tree */
1907+#define DICT_HDR_STATS 52 /* Root of the stats tree */
1908
1909 #define DICT_HDR_FSEG_HEADER 56 /* Segment header for the tablespace
1910 segment into which the dictionary
1911 header is created */
1912+
1913+#define DICT_HDR_XTRADB_MARK 256 /* Flag to distinguish expansion of XtraDB */
1914 /*-------------------------------------------------------------*/
1915
1916 /* The field number of the page number field in the sys_indexes table
1917@@ -144,11 +148,15 @@
1918 #define DICT_SYS_INDEXES_TYPE_FIELD 6
1919 #define DICT_SYS_INDEXES_NAME_FIELD 4
1920
1921+#define DICT_SYS_STATS_DIFF_VALS_FIELD 4
1922+
1923 /* When a row id which is zero modulo this number (which must be a power of
1924 two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is
1925 updated */
1926 #define DICT_HDR_ROW_ID_WRITE_MARGIN 256
1927
1928+#define DICT_HDR_XTRADB_FLAG 0x5854524144425F31ULL /* "XTRADB_1" */
1929+
1930 #ifndef UNIV_NONINL
1931 #include "dict0boot.ic"
1932 #endif
1933diff -ruN a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h
1934--- a/storage/innobase/include/dict0crea.h 2010-11-03 07:01:13.000000000 +0900
1935+++ b/storage/innobase/include/dict0crea.h 2010-12-03 17:19:24.886949643 +0900
1936@@ -53,6 +53,14 @@
1937 dict_index_t* index, /*!< in: index to create, built as a memory data
1938 structure */
1939 mem_heap_t* heap); /*!< in: heap where created */
1940+/*********************************************************************//**
1941+*/
1942+UNIV_INTERN
1943+ind_node_t*
1944+ind_insert_stats_graph_create(
1945+/*==========================*/
1946+ dict_index_t* index,
1947+ mem_heap_t* heap);
1948 /***********************************************************//**
1949 Creates a table. This is a high-level function used in SQL execution graphs.
1950 @return query thread to run next or NULL */
1951@@ -62,6 +70,13 @@
1952 /*===================*/
1953 que_thr_t* thr); /*!< in: query thread */
1954 /***********************************************************//**
1955+*/
1956+UNIV_INTERN
1957+que_thr_t*
1958+dict_insert_stats_step(
1959+/*===================*/
1960+ que_thr_t* thr);
1961+/***********************************************************//**
1962 Creates an index. This is a high-level function used in SQL execution
1963 graphs.
1964 @return query thread to run next or NULL */
1965@@ -170,6 +185,7 @@
1966 ins_node_t* field_def; /* child node which does the inserts of
1967 the field definitions; the row to be inserted
1968 is built by the parent node */
1969+ ins_node_t* stats_def;
1970 commit_node_t* commit_node;
1971 /* child node which performs a commit after
1972 a successful index creation */
1973@@ -180,6 +196,7 @@
1974 dict_table_t* table; /*!< table which owns the index */
1975 dtuple_t* ind_row;/* index definition row built */
1976 ulint field_no;/* next field definition to insert */
1977+ ulint stats_no;
1978 mem_heap_t* heap; /*!< memory heap used as auxiliary storage */
1979 };
1980
1981@@ -189,6 +206,7 @@
1982 #define INDEX_CREATE_INDEX_TREE 3
1983 #define INDEX_COMMIT_WORK 4
1984 #define INDEX_ADD_TO_CACHE 5
1985+#define INDEX_BUILD_STATS_COLS 6
1986
1987 #ifndef UNIV_NONINL
1988 #include "dict0crea.ic"
1989diff -ruN a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
1990--- a/storage/innobase/include/dict0dict.h 2010-12-03 15:48:03.073024387 +0900
1991+++ b/storage/innobase/include/dict0dict.h 2010-12-03 17:19:24.888965622 +0900
1992@@ -1084,10 +1084,11 @@
1993 dict_update_statistics(
1994 /*===================*/
1995 dict_table_t* table, /*!< in/out: table */
1996- ibool only_calc_if_missing_stats);/*!< in: only
1997+ ibool only_calc_if_missing_stats, /*!< in: only
1998 update/recalc the stats if they have
1999 not been initialized yet, otherwise
2000 do nothing */
2001+ ibool sync);
2002 /********************************************************************//**
2003 Reserves the dictionary system mutex for MySQL. */
2004 UNIV_INTERN
2005@@ -1202,6 +1203,7 @@
2006 dict_table_t* sys_columns; /*!< SYS_COLUMNS table */
2007 dict_table_t* sys_indexes; /*!< SYS_INDEXES table */
2008 dict_table_t* sys_fields; /*!< SYS_FIELDS table */
2009+ dict_table_t* sys_stats; /*!< SYS_STATS table */
2010 };
2011 #endif /* !UNIV_HOTBACKUP */
2012
2013diff -ruN a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h
2014--- a/storage/innobase/include/dict0load.h 2010-11-03 07:01:13.000000000 +0900
2015+++ b/storage/innobase/include/dict0load.h 2010-12-03 17:19:24.889947481 +0900
2016@@ -41,6 +41,7 @@
2017 SYS_FIELDS,
2018 SYS_FOREIGN,
2019 SYS_FOREIGN_COLS,
2020+ SYS_STATS,
2021
2022 /* This must be last item. Defines the number of system tables. */
2023 SYS_NUM_SYSTEM_TABLES
2024@@ -319,6 +320,19 @@
2025 const char** ref_col_name, /*!< out: referenced column name
2026 in referenced table */
2027 ulint* pos); /*!< out: column position */
2028+/********************************************************************//**
2029+This function parses a SYS_STATS record and extract necessary
2030+information from the record and return to caller.
2031+@return error message, or NULL on success */
2032+UNIV_INTERN
2033+const char*
2034+dict_process_sys_stats_rec(
2035+/*=============================*/
2036+ mem_heap_t* heap, /*!< in/out: heap memory */
2037+ const rec_t* rec, /*!< in: current SYS_STATS rec */
2038+ index_id_t* index_id, /*!< out: INDEX_ID */
2039+ ulint* key_cols, /*!< out: KEY_COLS */
2040+ ib_uint64_t* diff_vals); /*!< out: DIFF_VALS */
2041 #ifndef UNIV_NONINL
2042 #include "dict0load.ic"
2043 #endif
2044diff -ruN a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h
2045--- a/storage/innobase/include/page0cur.h 2010-11-03 07:01:13.000000000 +0900
2046+++ b/storage/innobase/include/page0cur.h 2010-12-03 17:19:24.891954511 +0900
2047@@ -293,6 +293,22 @@
2048 /*==========================*/
2049 buf_block_t* block, /*!< in: page */
2050 page_cur_t* cursor);/*!< out: page cursor */
2051+
2052+UNIV_INTERN
2053+void
2054+page_cur_open_on_nth_user_rec(
2055+/*==========================*/
2056+ buf_block_t* block, /*!< in: page */
2057+ page_cur_t* cursor, /*!< out: page cursor */
2058+ ulint nth);
2059+
2060+UNIV_INTERN
2061+ibool
2062+page_cur_open_on_rnd_user_rec_after_nth(
2063+/*==========================*/
2064+ buf_block_t* block, /*!< in: page */
2065+ page_cur_t* cursor, /*!< out: page cursor */
2066+ ulint nth);
2067 #endif /* !UNIV_HOTBACKUP */
2068 /***********************************************************//**
2069 Parses a log record of a record insert on a page.
2070diff -ruN a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h
2071--- a/storage/innobase/include/que0que.h 2010-11-03 07:01:13.000000000 +0900
2072+++ b/storage/innobase/include/que0que.h 2010-12-03 17:19:24.892947946 +0900
2073@@ -492,6 +492,8 @@
2074 #define QUE_NODE_CALL 31
2075 #define QUE_NODE_EXIT 32
2076
2077+#define QUE_NODE_INSERT_STATS 34
2078+
2079 /* Query thread states */
2080 #define QUE_THR_RUNNING 1
2081 #define QUE_THR_PROCEDURE_WAIT 2
2082diff -ruN a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h
2083--- a/storage/innobase/include/rem0cmp.h 2010-11-03 07:01:13.000000000 +0900
2084+++ b/storage/innobase/include/rem0cmp.h 2010-12-03 17:19:24.893953395 +0900
2085@@ -169,10 +169,11 @@
2086 matched fields; when the function returns,
2087 contains the value the for current
2088 comparison */
2089- ulint* matched_bytes);/*!< in/out: number of already matched
2090+ ulint* matched_bytes, /*!< in/out: number of already matched
2091 bytes within the first field not completely
2092 matched; when the function returns, contains
2093 the value for the current comparison */
2094+ ulint stats_method);
2095 /*************************************************************//**
2096 This function is used to compare two physical records. Only the common
2097 first fields are compared.
2098diff -ruN a/storage/innobase/include/rem0cmp.ic b/storage/innobase/include/rem0cmp.ic
2099--- a/storage/innobase/include/rem0cmp.ic 2010-11-03 07:01:13.000000000 +0900
2100+++ b/storage/innobase/include/rem0cmp.ic 2010-12-03 17:19:24.902983425 +0900
2101@@ -87,5 +87,5 @@
2102 ulint match_b = 0;
2103
2104 return(cmp_rec_rec_with_match(rec1, rec2, offsets1, offsets2, index,
2105- &match_f, &match_b));
2106+ &match_f, &match_b, 0));
2107 }
2108diff -ruN a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
2109--- a/storage/innobase/include/row0mysql.h 2010-11-03 07:01:13.000000000 +0900
2110+++ b/storage/innobase/include/row0mysql.h 2010-12-03 17:19:24.904973020 +0900
2111@@ -387,6 +387,14 @@
2112 then checked for not being too
2113 large. */
2114 /*********************************************************************//**
2115+*/
2116+UNIV_INTERN
2117+int
2118+row_insert_stats_for_mysql(
2119+/*=======================*/
2120+ dict_index_t* index,
2121+ trx_t* trx);
2122+/*********************************************************************//**
2123 Scans a table create SQL string and adds to the data dictionary
2124 the foreign key constraints declared in the string. This function
2125 should be called after the indexes for a table have been created.
2126diff -ruN a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
2127--- a/storage/innobase/include/srv0srv.h 2010-12-03 15:53:54.622036720 +0900
2128+++ b/storage/innobase/include/srv0srv.h 2010-12-03 17:19:24.906953188 +0900
2129@@ -209,6 +209,13 @@
2130 extern ibool srv_innodb_status;
2131
2132 extern unsigned long long srv_stats_sample_pages;
2133+extern ulint srv_stats_method;
2134+#define SRV_STATS_METHOD_NULLS_EQUAL 0
2135+#define SRV_STATS_METHOD_NULLS_NOT_EQUAL 1
2136+#define SRV_STATS_METHOD_IGNORE_NULLS 2
2137+extern ulint srv_stats_auto_update;
2138+extern ulint srv_stats_update_need_lock;
2139+extern ibool srv_use_sys_stats_table;
2140
2141 extern ibool srv_use_doublewrite_buf;
2142 extern ibool srv_use_checksums;
2143diff -ruN a/storage/innobase/page/page0cur.c b/storage/innobase/page/page0cur.c
2144--- a/storage/innobase/page/page0cur.c 2010-11-03 07:01:13.000000000 +0900
2145+++ b/storage/innobase/page/page0cur.c 2010-12-03 17:19:24.908973357 +0900
2146@@ -564,6 +564,74 @@
2147 } while (rnd--);
2148 }
2149
2150+UNIV_INTERN
2151+void
2152+page_cur_open_on_nth_user_rec(
2153+/*==========================*/
2154+ buf_block_t* block, /*!< in: page */
2155+ page_cur_t* cursor, /*!< out: page cursor */
2156+ ulint nth)
2157+{
2158+ ulint n_recs = page_get_n_recs(buf_block_get_frame(block));
2159+
2160+ page_cur_set_before_first(block, cursor);
2161+
2162+ if (UNIV_UNLIKELY(n_recs == 0)) {
2163+
2164+ return;
2165+ }
2166+
2167+ nth--;
2168+
2169+ if (nth >= n_recs) {
2170+ nth = n_recs - 1;
2171+ }
2172+
2173+ do {
2174+ page_cur_move_to_next(cursor);
2175+ } while (nth--);
2176+}
2177+
2178+UNIV_INTERN
2179+ibool
2180+page_cur_open_on_rnd_user_rec_after_nth(
2181+/*==========================*/
2182+ buf_block_t* block, /*!< in: page */
2183+ page_cur_t* cursor, /*!< out: page cursor */
2184+ ulint nth)
2185+{
2186+ ulint rnd;
2187+ ulint n_recs = page_get_n_recs(buf_block_get_frame(block));
2188+ ibool ret;
2189+
2190+ page_cur_set_before_first(block, cursor);
2191+
2192+ if (UNIV_UNLIKELY(n_recs == 0)) {
2193+
2194+ return (FALSE);
2195+ }
2196+
2197+ nth--;
2198+
2199+ if (nth >= n_recs) {
2200+ nth = n_recs - 1;
2201+ }
2202+
2203+ rnd = (ulint) (nth + page_cur_lcg_prng() % (n_recs - nth));
2204+
2205+ if (rnd == nth) {
2206+ ret = TRUE;
2207+ } else {
2208+ ret = FALSE;
2209+ }
2210+
2211+ do {
2212+ page_cur_move_to_next(cursor);
2213+ } while (rnd--);
2214+
2215+ return (ret);
2216+}
2217+
2218 /***********************************************************//**
2219 Writes the log record of a record insert on a page. */
2220 static
2221diff -ruN a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c
2222--- a/storage/innobase/que/que0que.c 2010-11-03 07:01:13.000000000 +0900
2223+++ b/storage/innobase/que/que0que.c 2010-12-03 17:19:24.910953422 +0900
2224@@ -621,11 +621,21 @@
2225
2226 que_graph_free_recursive(cre_ind->ind_def);
2227 que_graph_free_recursive(cre_ind->field_def);
2228+ if (srv_use_sys_stats_table)
2229+ que_graph_free_recursive(cre_ind->stats_def);
2230 que_graph_free_recursive(cre_ind->commit_node);
2231
2232 mem_heap_free(cre_ind->heap);
2233
2234 break;
2235+ case QUE_NODE_INSERT_STATS:
2236+ cre_ind = node;
2237+
2238+ que_graph_free_recursive(cre_ind->stats_def);
2239+ que_graph_free_recursive(cre_ind->commit_node);
2240+
2241+ mem_heap_free(cre_ind->heap);
2242+ break;
2243 case QUE_NODE_PROC:
2244 que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
2245
2246@@ -1138,6 +1148,8 @@
2247 str = "CREATE TABLE";
2248 } else if (type == QUE_NODE_CREATE_INDEX) {
2249 str = "CREATE INDEX";
2250+ } else if (type == QUE_NODE_INSERT_STATS) {
2251+ str = "INSERT TO SYS_STATS";
2252 } else if (type == QUE_NODE_FOR) {
2253 str = "FOR LOOP";
2254 } else if (type == QUE_NODE_RETURN) {
2255@@ -1255,6 +1267,8 @@
2256 thr = dict_create_table_step(thr);
2257 } else if (type == QUE_NODE_CREATE_INDEX) {
2258 thr = dict_create_index_step(thr);
2259+ } else if (type == QUE_NODE_INSERT_STATS) {
2260+ thr = dict_insert_stats_step(thr);
2261 } else if (type == QUE_NODE_ROW_PRINTF) {
2262 thr = row_printf_step(thr);
2263 } else {
2264diff -ruN a/storage/innobase/rem/rem0cmp.c b/storage/innobase/rem/rem0cmp.c
2265--- a/storage/innobase/rem/rem0cmp.c 2010-11-03 07:01:13.000000000 +0900
2266+++ b/storage/innobase/rem/rem0cmp.c 2010-12-03 17:19:24.911953579 +0900
2267@@ -866,10 +866,11 @@
2268 matched fields; when the function returns,
2269 contains the value the for current
2270 comparison */
2271- ulint* matched_bytes) /*!< in/out: number of already matched
2272+ ulint* matched_bytes, /*!< in/out: number of already matched
2273 bytes within the first field not completely
2274 matched; when the function returns, contains
2275 the value for the current comparison */
2276+ ulint stats_method)
2277 {
2278 ulint rec1_n_fields; /* the number of fields in rec */
2279 ulint rec1_f_len; /* length of current field in rec */
2280@@ -962,7 +963,11 @@
2281
2282 if (rec1_f_len == rec2_f_len) {
2283
2284- goto next_field;
2285+ if (stats_method == SRV_STATS_METHOD_NULLS_EQUAL) {
2286+ goto next_field;
2287+ } else {
2288+ ret = -1;
2289+ }
2290
2291 } else if (rec2_f_len == UNIV_SQL_NULL) {
2292
2293diff -ruN a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c
2294--- a/storage/innobase/row/row0merge.c 2010-11-03 07:01:13.000000000 +0900
2295+++ b/storage/innobase/row/row0merge.c 2010-12-03 17:19:24.914955391 +0900
2296@@ -2020,6 +2020,8 @@
2297 "UPDATE SYS_INDEXES SET NAME=CONCAT('"
2298 TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n"
2299 "COMMIT WORK;\n"
2300+ /* Drop the statistics of the index. */
2301+ "DELETE FROM SYS_STATS WHERE INDEX_ID = :indexid;\n"
2302 /* Drop the field definitions of the index. */
2303 "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
2304 /* Drop the index definition and the B-tree. */
2305diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
2306--- a/storage/innobase/row/row0mysql.c 2010-11-03 07:01:13.000000000 +0900
2307+++ b/storage/innobase/row/row0mysql.c 2010-12-03 17:19:24.918953476 +0900
2308@@ -921,6 +921,9 @@
2309
2310 table->stat_modified_counter = counter + 1;
2311
2312+ if (!srv_stats_auto_update)
2313+ return;
2314+
2315 /* Calculate new statistics if 1 / 16 of table has been modified
2316 since the last time a statistics batch was run, or if
2317 stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
2318@@ -931,7 +934,7 @@
2319 || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
2320
2321 dict_update_statistics(table, FALSE /* update even if stats
2322- are initialized */);
2323+ are initialized */, TRUE);
2324 }
2325 }
2326
2327@@ -2105,6 +2108,45 @@
2328 }
2329
2330 /*********************************************************************//**
2331+*/
2332+UNIV_INTERN
2333+int
2334+row_insert_stats_for_mysql(
2335+/*=======================*/
2336+ dict_index_t* index,
2337+ trx_t* trx)
2338+{
2339+ ind_node_t* node;
2340+ mem_heap_t* heap;
2341+ que_thr_t* thr;
2342+ ulint err;
2343+
2344+ ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2345+
2346+ trx->op_info = "try to insert rows to SYS_STATS";
2347+
2348+ trx_start_if_not_started(trx);
2349+ trx->error_state = DB_SUCCESS;
2350+
2351+ heap = mem_heap_create(512);
2352+
2353+ node = ind_insert_stats_graph_create(index, heap);
2354+
2355+ thr = pars_complete_graph_for_exec(node, trx, heap);
2356+
2357+ ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2358+ que_run_threads(thr);
2359+
2360+ err = trx->error_state;
2361+
2362+ que_graph_free((que_t*) que_node_get_parent(thr));
2363+
2364+ trx->op_info = "";
2365+
2366+ return((int) err);
2367+}
2368+
2369+/*********************************************************************//**
2370 Scans a table create SQL string and adds to the data dictionary
2371 the foreign key constraints declared in the string. This function
2372 should be called after the indexes for a table have been created.
2373@@ -3024,7 +3066,7 @@
2374 dict_table_autoinc_initialize(table, 1);
2375 dict_table_autoinc_unlock(table);
2376 dict_update_statistics(table, FALSE /* update even if stats are
2377- initialized */);
2378+ initialized */, TRUE);
2379
2380 trx_commit_for_mysql(trx);
2381
2382@@ -3326,6 +3368,8 @@
2383 " IF (SQL % NOTFOUND) THEN\n"
2384 " found := 0;\n"
2385 " ELSE\n"
2386+ " DELETE FROM SYS_STATS\n"
2387+ " WHERE INDEX_ID = index_id;\n"
2388 " DELETE FROM SYS_FIELDS\n"
2389 " WHERE INDEX_ID = index_id;\n"
2390 " DELETE FROM SYS_INDEXES\n"
2391diff -ruN a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
2392--- a/storage/innobase/srv/srv0srv.c 2010-12-03 15:53:54.625288512 +0900
2393+++ b/storage/innobase/srv/srv0srv.c 2010-12-03 17:19:24.922953561 +0900
2394@@ -395,6 +395,10 @@
2395 /* When estimating number of different key values in an index, sample
2396 this many index pages */
2397 UNIV_INTERN unsigned long long srv_stats_sample_pages = 8;
2398+UNIV_INTERN ulint srv_stats_method = 0;
2399+UNIV_INTERN ulint srv_stats_auto_update = 1;
2400+UNIV_INTERN ulint srv_stats_update_need_lock = 1;
2401+UNIV_INTERN ibool srv_use_sys_stats_table = FALSE;
2402
2403 UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE;
2404 UNIV_INTERN ibool srv_use_checksums = TRUE;
This page took 0.44639 seconds and 4 git commands to generate.