]> git.pld-linux.org Git - packages/mysql.git/blame - innodb_stats.patch
- cosmetics
[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!
db82db79
AM
8--- a/storage/innobase/dict/dict0boot.c
9+++ b/storage/innobase/dict/dict0boot.c
b4e1fa2c
AM
10@@ -266,6 +266,29 @@
11 /* Get the dictionary header */
12 dict_hdr = dict_hdr_get(&mtr);
13
14+ if (mach_read_from_8(dict_hdr + DICT_HDR_XTRADB_MARK)
15+ != DICT_HDR_XTRADB_FLAG) {
16+ /* not extended yet by XtraDB, need to be extended */
17+ ulint root_page_no;
18+
19+ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
20+ DICT_HDR_SPACE, 0, DICT_STATS_ID,
21+ dict_ind_redundant, &mtr);
22+ if (root_page_no == FIL_NULL) {
23+ fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n");
24+ srv_use_sys_stats_table = FALSE;
25+ } else {
26+ mlog_write_ulint(dict_hdr + DICT_HDR_STATS, root_page_no,
27+ MLOG_4BYTES, &mtr);
28+ mlog_write_ull(dict_hdr + DICT_HDR_XTRADB_MARK,
29+ DICT_HDR_XTRADB_FLAG, &mtr);
30+ }
31+ mtr_commit(&mtr);
32+ /* restart mtr */
33+ mtr_start(&mtr);
34+ dict_hdr = dict_hdr_get(&mtr);
35+ }
36+
37 /* Because we only write new row ids to disk-based data structure
38 (dictionary header) when it is divisible by
39 DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover
40@@ -425,7 +448,7 @@
41 table->id = DICT_FIELDS_ID;
42 dict_table_add_to_cache(table, heap);
43 dict_sys->sys_fields = table;
44- mem_heap_free(heap);
45+ mem_heap_empty(heap);
46
47 index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
48 DICT_HDR_SPACE,
11822e22 49@@ -442,6 +465,45 @@
b4e1fa2c
AM
50 FALSE);
51 ut_a(error == DB_SUCCESS);
52
53+ /*-------------------------*/
11822e22 54+ table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 4, 0);
b4e1fa2c
AM
55+ table->n_mysql_handles_opened = 1; /* for pin */
56+
57+ dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
58+ dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
59+ dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
11822e22 60+ dict_mem_table_add_col(table, heap, "NON_NULL_VALS", DATA_BINARY, 0, 0);
b4e1fa2c
AM
61+
62+ /* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
63+#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
64+#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
65+#endif
11822e22
AM
66+#if DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2
67+#error "DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2"
68+#endif
b4e1fa2c
AM
69+
70+ table->id = DICT_STATS_ID;
71+ dict_table_add_to_cache(table, heap);
72+ dict_sys->sys_stats = table;
73+ mem_heap_empty(heap);
74+
75+ index = dict_mem_index_create("SYS_STATS", "CLUST_IND",
76+ DICT_HDR_SPACE,
77+ DICT_UNIQUE | DICT_CLUSTERED, 2);
78+
79+ dict_mem_index_add_field(index, "INDEX_ID", 0);
80+ dict_mem_index_add_field(index, "KEY_COLS", 0);
81+
82+ index->id = DICT_STATS_ID;
83+ error = dict_index_add_to_cache(table, index,
84+ mtr_read_ulint(dict_hdr
85+ + DICT_HDR_STATS,
86+ MLOG_4BYTES, &mtr),
87+ FALSE);
88+ ut_a(error == DB_SUCCESS);
89+
90+ mem_heap_free(heap);
91+
92 mtr_commit(&mtr);
93 /*-------------------------*/
94
11822e22 95@@ -455,6 +517,7 @@
b4e1fa2c
AM
96 dict_load_sys_table(dict_sys->sys_columns);
97 dict_load_sys_table(dict_sys->sys_indexes);
98 dict_load_sys_table(dict_sys->sys_fields);
99+ dict_load_sys_table(dict_sys->sys_stats);
100
101 mutex_exit(&(dict_sys->mutex));
102 }
db82db79
AM
103--- a/storage/innobase/dict/dict0crea.c
104+++ b/storage/innobase/dict/dict0crea.c
11822e22 105@@ -508,6 +508,56 @@
b4e1fa2c
AM
106 }
107
108 /*****************************************************************//**
109+Based on an index object, this function builds the entry to be inserted
110+in the SYS_STATS system table.
111+@return the tuple which should be inserted */
112+static
113+dtuple_t*
114+dict_create_sys_stats_tuple(
115+/*========================*/
116+ const dict_index_t* index,
117+ ulint i,
118+ mem_heap_t* heap)
119+{
120+ dict_table_t* sys_stats;
121+ dtuple_t* entry;
122+ dfield_t* dfield;
123+ byte* ptr;
124+
125+ ut_ad(index);
126+ ut_ad(heap);
127+
128+ sys_stats = dict_sys->sys_stats;
129+
11822e22 130+ entry = dtuple_create(heap, 4 + DATA_N_SYS_COLS);
b4e1fa2c
AM
131+
132+ dict_table_copy_types(entry, sys_stats);
133+
134+ /* 0: INDEX_ID -----------------------*/
135+ dfield = dtuple_get_nth_field(entry, 0/*INDEX_ID*/);
136+ ptr = mem_heap_alloc(heap, 8);
137+ mach_write_to_8(ptr, index->id);
138+ dfield_set_data(dfield, ptr, 8);
139+ /* 1: KEY_COLS -----------------------*/
140+ dfield = dtuple_get_nth_field(entry, 1/*KEY_COLS*/);
141+ ptr = mem_heap_alloc(heap, 4);
142+ mach_write_to_4(ptr, i);
143+ dfield_set_data(dfield, ptr, 4);
144+ /* 4: DIFF_VALS ----------------------*/
145+ dfield = dtuple_get_nth_field(entry, 2/*DIFF_VALS*/);
146+ ptr = mem_heap_alloc(heap, 8);
147+ mach_write_to_8(ptr, 0); /* initial value is 0 */
148+ dfield_set_data(dfield, ptr, 8);
11822e22
AM
149+ /* 5: NON_NULL_VALS ------------------*/
150+ dfield = dtuple_get_nth_field(entry, 3/*NON_NULL_VALS*/);
151+ ptr = mem_heap_alloc(heap, 8);
152+ mach_write_to_8(ptr, 0); /* initial value is 0 */
153+ dfield_set_data(dfield, ptr, 8);
b4e1fa2c
AM
154+
155+ return(entry);
156+}
157+
158+/*****************************************************************//**
159 Creates the tuple with which the index entry is searched for writing the index
160 tree root page number, if such a tree is created.
161 @return the tuple for search */
11822e22 162@@ -617,6 +667,27 @@
b4e1fa2c
AM
163 }
164
165 /***************************************************************//**
166+Builds a row for storing stats to insert.
167+@return DB_SUCCESS */
168+static
169+ulint
170+dict_build_stats_def_step(
171+/*======================*/
172+ ind_node_t* node)
173+{
174+ dict_index_t* index;
175+ dtuple_t* row;
176+
177+ index = node->index;
178+
179+ row = dict_create_sys_stats_tuple(index, node->stats_no, node->heap);
180+
181+ ins_node_set_new_row(node->stats_def, row);
182+
183+ return(DB_SUCCESS);
184+}
185+
186+/***************************************************************//**
187 Creates an index tree for the index if it is not a member of a cluster.
188 @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
189 static
db82db79 190@@ -936,6 +1007,49 @@
b4e1fa2c
AM
191 dict_sys->sys_fields, heap);
192 node->field_def->common.parent = node;
193
194+ if (srv_use_sys_stats_table) {
195+ node->stats_def = ins_node_create(INS_DIRECT,
196+ dict_sys->sys_stats, heap);
197+ node->stats_def->common.parent = node;
198+ } else {
199+ node->stats_def = NULL;
200+ }
201+
202+ node->commit_node = commit_node_create(heap);
203+ node->commit_node->common.parent = node;
204+
205+ return(node);
206+}
207+
208+/*********************************************************************//**
209+*/
210+UNIV_INTERN
211+ind_node_t*
212+ind_insert_stats_graph_create(
213+/*==========================*/
214+ dict_index_t* index,
215+ mem_heap_t* heap)
216+{
217+ ind_node_t* node;
218+
219+ node = mem_heap_alloc(heap, sizeof(ind_node_t));
220+
221+ node->common.type = QUE_NODE_INSERT_STATS;
222+
223+ node->index = index;
224+
225+ node->state = INDEX_BUILD_STATS_COLS;
226+ node->page_no = FIL_NULL;
227+ node->heap = mem_heap_create(256);
228+
229+ node->ind_def = NULL;
230+ node->field_def = NULL;
231+
232+ node->stats_def = ins_node_create(INS_DIRECT,
233+ dict_sys->sys_stats, heap);
234+ node->stats_def->common.parent = node;
235+ node->stats_no = 0;
236+
237 node->commit_node = commit_node_create(heap);
238 node->commit_node->common.parent = node;
239
db82db79 240@@ -1086,6 +1200,7 @@
b4e1fa2c
AM
241
242 node->state = INDEX_BUILD_FIELD_DEF;
243 node->field_no = 0;
244+ node->stats_no = 0;
245
246 thr->run_node = node->ind_def;
247
db82db79 248@@ -1131,7 +1246,31 @@
b4e1fa2c
AM
249 goto function_exit;
250 }
251
252- node->state = INDEX_CREATE_INDEX_TREE;
253+ if (srv_use_sys_stats_table
254+ && !((node->table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)) {
255+ node->state = INDEX_BUILD_STATS_COLS;
256+ } else {
257+ node->state = INDEX_CREATE_INDEX_TREE;
258+ }
259+ }
260+ if (node->state == INDEX_BUILD_STATS_COLS) {
261+ if (node->stats_no <= dict_index_get_n_unique(node->index)) {
262+
263+ err = dict_build_stats_def_step(node);
264+
265+ if (err != DB_SUCCESS) {
266+
267+ goto function_exit;
268+ }
269+
270+ node->stats_no++;
271+
272+ thr->run_node = node->stats_def;
273+
274+ return(thr);
275+ } else {
276+ node->state = INDEX_CREATE_INDEX_TREE;
277+ }
278 }
279
280 if (node->state == INDEX_CREATE_INDEX_TREE) {
1bfc1981
AM
281@@ -1183,6 +1322,66 @@
282 }
b4e1fa2c 283
1bfc1981 284 /****************************************************************//**
b4e1fa2c
AM
285+*/
286+UNIV_INTERN
287+que_thr_t*
288+dict_insert_stats_step(
289+/*===================*/
290+ que_thr_t* thr) /*!< in: query thread */
291+{
292+ ind_node_t* node;
293+ ulint err = DB_ERROR;
294+ trx_t* trx;
295+
296+ ut_ad(thr);
297+
298+ trx = thr_get_trx(thr);
299+
300+ node = thr->run_node;
301+
302+ if (thr->prev_node == que_node_get_parent(node)) {
303+ node->state = INDEX_BUILD_STATS_COLS;
304+ }
305+
306+ if (node->state == INDEX_BUILD_STATS_COLS) {
307+ if (node->stats_no <= dict_index_get_n_unique(node->index)) {
308+
309+ err = dict_build_stats_def_step(node);
310+
311+ if (err != DB_SUCCESS) {
312+
313+ goto function_exit;
314+ }
315+
316+ node->stats_no++;
317+
318+ thr->run_node = node->stats_def;
319+
320+ return(thr);
321+ } else {
322+ node->state = INDEX_COMMIT_WORK;
323+ }
324+ }
325+
326+ if (node->state == INDEX_COMMIT_WORK) {
327+
328+ /* do not commit transaction here for now */
329+ }
330+
331+function_exit:
332+ trx->error_state = err;
333+
334+ if (err == DB_SUCCESS) {
335+ } else {
336+ return(NULL);
337+ }
338+
1bfc1981
AM
339+ thr->run_node = que_node_get_parent(node);
340+
341+ return(thr);
342+}
343+
344+/****************************************************************//**
345 Creates the foreign key constraints system tables inside InnoDB
346 at database creation or database start if they are not found or are
347 not of the right form.
db82db79
AM
348--- a/storage/innobase/dict/dict0dict.c
349+++ b/storage/innobase/dict/dict0dict.c
adf0fb13 350@@ -755,7 +755,7 @@
b4e1fa2c
AM
351 print an error message and return without doing
352 anything. */
353 dict_update_statistics(table, TRUE /* only update stats
354- if they have not been initialized */);
355+ if they have not been initialized */, FALSE);
356 }
357
358 return(table);
734d6226 359@@ -4344,6 +4344,295 @@
b4e1fa2c
AM
360 }
361
362 /*********************************************************************//**
363+functions to use SYS_STATS system table. */
364+static
365+ibool
366+dict_reload_statistics(
367+/*===================*/
368+ dict_table_t* table,
369+ ulint* sum_of_index_sizes)
370+{
371+ dict_index_t* index;
372+ ulint size;
373+ mem_heap_t* heap;
374+
375+ index = dict_table_get_first_index(table);
376+
377+ if (index == NULL) {
378+ /* Table definition is corrupt */
379+
380+ return(FALSE);
381+ }
382+
383+ heap = mem_heap_create(1000);
384+
385+ while (index) {
386+ size = btr_get_size(index, BTR_TOTAL_SIZE);
387+
388+ index->stat_index_size = size;
389+
390+ *sum_of_index_sizes += size;
391+
392+ size = btr_get_size(index, BTR_N_LEAF_PAGES);
393+
394+ if (size == 0) {
395+ /* The root node of the tree is a leaf */
396+ size = 1;
397+ }
398+
399+ index->stat_n_leaf_pages = size;
400+
401+/*===========================================*/
402+{
403+ dict_table_t* sys_stats;
404+ dict_index_t* sys_index;
405+ btr_pcur_t pcur;
406+ dtuple_t* tuple;
407+ dfield_t* dfield;
408+ ulint key_cols;
409+ ulint n_cols;
410+ const rec_t* rec;
11822e22 411+ ulint n_fields;
b4e1fa2c
AM
412+ const byte* field;
413+ ulint len;
414+ ib_int64_t* stat_n_diff_key_vals_tmp;
11822e22 415+ ib_int64_t* stat_n_non_null_key_vals_tmp;
b4e1fa2c
AM
416+ byte* buf;
417+ ulint i;
418+ mtr_t mtr;
419+
420+ n_cols = dict_index_get_n_unique(index);
421+ stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
11822e22 422+ stat_n_non_null_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
b4e1fa2c
AM
423+
424+ sys_stats = dict_sys->sys_stats;
425+ sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
426+ ut_a(!dict_table_is_comp(sys_stats));
427+
428+ tuple = dtuple_create(heap, 1);
429+ dfield = dtuple_get_nth_field(tuple, 0);
430+
431+ buf = mem_heap_alloc(heap, 8);
432+ mach_write_to_8(buf, index->id);
433+
434+ dfield_set_data(dfield, buf, 8);
435+ dict_index_copy_types(tuple, sys_index, 1);
436+
437+ mtr_start(&mtr);
438+
439+ btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
440+ BTR_SEARCH_LEAF, &pcur, &mtr);
441+ for (i = 0; i <= n_cols; i++) {
442+ rec = btr_pcur_get_rec(&pcur);
443+
444+ if (!btr_pcur_is_on_user_rec(&pcur)
445+ || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
446+ != index->id) {
447+ /* not found: even 1 if not found should not be alowed */
448+ fprintf(stderr, "InnoDB: Warning: stats for %s/%s (%lu/%lu)"
d8778560 449+ " not found in SYS_STATS\n",
b4e1fa2c
AM
450+ index->table_name, index->name, i, n_cols);
451+ btr_pcur_close(&pcur);
452+ mtr_commit(&mtr);
453+ mem_heap_free(heap);
454+ return(FALSE);
455+ }
456+
457+ if (rec_get_deleted_flag(rec, 0)) {
11822e22
AM
458+ /* don't count */
459+ i--;
b4e1fa2c
AM
460+ goto next_rec;
461+ }
462+
11822e22
AM
463+ n_fields = rec_get_n_fields_old(rec);
464+
b4e1fa2c
AM
465+ field = rec_get_nth_field_old(rec, 1, &len);
466+ ut_a(len == 4);
467+
468+ key_cols = mach_read_from_4(field);
469+
470+ ut_a(i == key_cols);
471+
472+ field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
473+ ut_a(len == 8);
474+
475+ stat_n_diff_key_vals_tmp[i] = mach_read_from_8(field);
11822e22
AM
476+
477+ if (n_fields > DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
478+ field = rec_get_nth_field_old(rec, DICT_SYS_STATS_NON_NULL_VALS_FIELD, &len);
479+ ut_a(len == 8);
480+
481+ stat_n_non_null_key_vals_tmp[i] = mach_read_from_8(field);
482+ } else {
483+ /* not enough fields: should be older */
484+ fprintf(stderr, "InnoDB: Notice: stats for %s/%s (%lu/%lu)"
485+ " in SYS_STATS seems older format. "
486+ "Please execute ANALYZE TABLE for it.\n",
487+ index->table_name, index->name, i, n_cols);
488+
489+ stat_n_non_null_key_vals_tmp[i] = ((ib_int64_t)(-1));
490+ }
b4e1fa2c
AM
491+next_rec:
492+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
493+ }
494+
495+ btr_pcur_close(&pcur);
496+ mtr_commit(&mtr);
497+
498+ for (i = 0; i <= n_cols; i++) {
499+ index->stat_n_diff_key_vals[i] = stat_n_diff_key_vals_tmp[i];
11822e22
AM
500+ if (stat_n_non_null_key_vals_tmp[i] == ((ib_int64_t)(-1))) {
501+ /* approximate value */
502+ index->stat_n_non_null_key_vals[i] = stat_n_diff_key_vals_tmp[n_cols];
503+ } else {
504+ index->stat_n_non_null_key_vals[i] = stat_n_non_null_key_vals_tmp[i];
505+ }
b4e1fa2c
AM
506+ }
507+}
508+/*===========================================*/
509+
510+ index = dict_table_get_next_index(index);
511+ }
512+
513+ mem_heap_free(heap);
514+ return(TRUE);
515+}
516+
517+static
518+void
519+dict_store_statistics(
520+/*==================*/
521+ dict_table_t* table)
522+{
523+ dict_index_t* index;
524+ mem_heap_t* heap;
525+
526+ index = dict_table_get_first_index(table);
527+
528+ ut_a(index);
529+
530+ heap = mem_heap_create(1000);
531+
532+ while (index) {
533+/*===========================================*/
534+{
535+ dict_table_t* sys_stats;
536+ dict_index_t* sys_index;
537+ btr_pcur_t pcur;
538+ dtuple_t* tuple;
539+ dfield_t* dfield;
540+ ulint key_cols;
541+ ulint n_cols;
542+ ulint rests;
543+ const rec_t* rec;
11822e22 544+ ulint n_fields;
b4e1fa2c
AM
545+ const byte* field;
546+ ulint len;
547+ ib_int64_t* stat_n_diff_key_vals_tmp;
11822e22 548+ ib_int64_t* stat_n_non_null_key_vals_tmp;
b4e1fa2c
AM
549+ byte* buf;
550+ ulint i;
551+ mtr_t mtr;
552+
553+ n_cols = dict_index_get_n_unique(index);
554+ stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
11822e22 555+ stat_n_non_null_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
b4e1fa2c
AM
556+
557+ for (i = 0; i <= n_cols; i++) {
558+ stat_n_diff_key_vals_tmp[i] = index->stat_n_diff_key_vals[i];
11822e22 559+ stat_n_non_null_key_vals_tmp[i] = index->stat_n_non_null_key_vals[i];
b4e1fa2c
AM
560+ }
561+
562+ sys_stats = dict_sys->sys_stats;
563+ sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
564+ ut_a(!dict_table_is_comp(sys_stats));
565+
566+ tuple = dtuple_create(heap, 1);
567+ dfield = dtuple_get_nth_field(tuple, 0);
568+
569+ buf = mem_heap_alloc(heap, 8);
570+ mach_write_to_8(buf, index->id);
571+
572+ dfield_set_data(dfield, buf, 8);
573+ dict_index_copy_types(tuple, sys_index, 1);
574+
575+ mtr_start(&mtr);
576+
577+ btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
578+ BTR_MODIFY_LEAF, &pcur, &mtr);
579+ rests = n_cols + 1;
580+ for (i = 0; i <= n_cols; i++) {
581+ rec = btr_pcur_get_rec(&pcur);
582+
583+ if (!btr_pcur_is_on_user_rec(&pcur)
584+ || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
585+ != index->id) {
586+ /* not found */
d8778560
AM
587+
588+
b4e1fa2c
AM
589+ break;
590+ }
591+
adf0fb13
AM
592+ btr_pcur_store_position(&pcur, &mtr);
593+
b4e1fa2c 594+ if (rec_get_deleted_flag(rec, 0)) {
11822e22
AM
595+ /* don't count */
596+ i--;
597+ goto next_rec;
598+ }
599+
600+ n_fields = rec_get_n_fields_old(rec);
601+
602+ if (n_fields <= DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
603+ /* not update for the older smaller format */
604+ fprintf(stderr, "InnoDB: Notice: stats for %s/%s (%lu/%lu)"
605+ " in SYS_STATS seems older format. Please ANALYZE TABLE it.\n",
606+ index->table_name, index->name, i, n_cols);
b4e1fa2c
AM
607+ goto next_rec;
608+ }
609+
610+ field = rec_get_nth_field_old(rec, 1, &len);
611+ ut_a(len == 4);
612+
613+ key_cols = mach_read_from_4(field);
614+
615+ field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
616+ ut_a(len == 8);
617+
618+ mlog_write_ull((byte*)field, stat_n_diff_key_vals_tmp[key_cols], &mtr);
619+
11822e22
AM
620+ field = rec_get_nth_field_old(rec, DICT_SYS_STATS_NON_NULL_VALS_FIELD, &len);
621+ ut_a(len == 8);
622+
623+ mlog_write_ull((byte*)field, stat_n_non_null_key_vals_tmp[key_cols], &mtr);
624+
b4e1fa2c
AM
625+ rests--;
626+
627+next_rec:
adf0fb13
AM
628+ mtr_commit(&mtr);
629+ mtr_start(&mtr);
630+ btr_pcur_restore_position(BTR_MODIFY_LEAF, &pcur, &mtr);
631+
b4e1fa2c
AM
632+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
633+ }
634+ btr_pcur_close(&pcur);
635+ mtr_commit(&mtr);
636+
637+ if (rests) {
638+ fprintf(stderr, "InnoDB: Warning: failed to store %lu stats entries"
639+ " of %s/%s to SYS_STATS system table.\n",
640+ rests, index->table_name, index->name);
641+ }
642+}
643+/*===========================================*/
644+
645+ index = dict_table_get_next_index(index);
646+ }
647+
648+ mem_heap_free(heap);
649+}
650+
651+/*********************************************************************//**
652 Calculates new estimates for table and index statistics. The statistics
653 are used in query optimization. */
654 UNIV_INTERN
734d6226 655@@ -4351,10 +4640,11 @@
b4e1fa2c
AM
656 dict_update_statistics(
657 /*===================*/
658 dict_table_t* table, /*!< in/out: table */
659- ibool only_calc_if_missing_stats)/*!< in: only
660+ ibool only_calc_if_missing_stats,/*!< in: only
661 update/recalc the stats if they have
662 not been initialized yet, otherwise
663 do nothing */
664+ ibool sync) /*!< in: TRUE if must update SYS_STATS */
665 {
666 dict_index_t* index;
667 ulint sum_of_index_sizes = 0;
734d6226 668@@ -4371,6 +4661,27 @@
b4e1fa2c
AM
669 return;
670 }
671
672+ if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) && !sync) {
673+ dict_table_stats_lock(table, RW_X_LATCH);
674+
675+ /* reload statistics from SYS_STATS table */
676+ if (dict_reload_statistics(table, &sum_of_index_sizes)) {
677+ /* success */
678+#ifdef UNIV_DEBUG
d8778560 679+ fprintf(stderr, "InnoDB: DEBUG: reload_statistics succeeded for %s.\n",
b4e1fa2c
AM
680+ table->name);
681+#endif
682+ goto end;
683+ }
684+
685+ dict_table_stats_unlock(table, RW_X_LATCH);
686+ }
687+#ifdef UNIV_DEBUG
688+ fprintf(stderr, "InnoDB: DEBUG: update_statistics for %s.\n",
689+ table->name);
690+#endif
691+ sum_of_index_sizes = 0;
692+
693 /* Find out the sizes of the indexes and how many different values
694 for the key they approximately have */
695
734d6226 696@@ -4435,6 +4746,11 @@
b4e1fa2c
AM
697 index = dict_table_get_next_index(index);
698 } while (index);
699
700+ if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)) {
701+ /* store statistics to SYS_STATS table */
702+ dict_store_statistics(table);
703+ }
704+end:
705 index = dict_table_get_first_index(table);
706
707 table->stat_n_rows = index->stat_n_diff_key_vals[
734d6226 708@@ -4452,6 +4768,78 @@
11822e22
AM
709 dict_table_stats_unlock(table, RW_X_LATCH);
710 }
711
712+/*********************************************************************//**
713+*/
714+UNIV_INTERN
715+ibool
716+dict_is_older_statistics(
717+/*=====================*/
718+ dict_index_t* index)
719+{
720+ mem_heap_t* heap;
721+ dict_table_t* sys_stats;
722+ dict_index_t* sys_index;
723+ btr_pcur_t pcur;
724+ dtuple_t* tuple;
725+ dfield_t* dfield;
726+ const rec_t* rec;
727+ ulint n_fields;
728+ ulint len;
729+ byte* buf;
730+ mtr_t mtr;
731+
732+ heap = mem_heap_create(100);
733+
734+ sys_stats = dict_sys->sys_stats;
735+ sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
736+ ut_a(!dict_table_is_comp(sys_stats));
737+
738+ tuple = dtuple_create(heap, 1);
739+ dfield = dtuple_get_nth_field(tuple, 0);
740+
741+ buf = mem_heap_alloc(heap, 8);
742+ mach_write_to_8(buf, index->id);
743+
744+ dfield_set_data(dfield, buf, 8);
745+ dict_index_copy_types(tuple, sys_index, 1);
746+
747+ mtr_start(&mtr);
748+
749+ btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
750+ BTR_SEARCH_LEAF, &pcur, &mtr);
751+
752+next_rec:
753+ rec = btr_pcur_get_rec(&pcur);
754+
755+ if (!btr_pcur_is_on_user_rec(&pcur)
756+ || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
757+ != index->id) {
758+ /* not found */
759+ btr_pcur_close(&pcur);
760+ mtr_commit(&mtr);
761+ mem_heap_free(heap);
762+ /* no statistics == not older statistics */
763+ return(FALSE);
764+ }
765+
766+ if (rec_get_deleted_flag(rec, 0)) {
767+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
768+ goto next_rec;
769+ }
770+
771+ n_fields = rec_get_n_fields_old(rec);
772+
773+ btr_pcur_close(&pcur);
774+ mtr_commit(&mtr);
775+ mem_heap_free(heap);
776+
777+ if (n_fields > DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
778+ return(FALSE);
779+ } else {
780+ return(TRUE);
781+ }
782+}
783+
784 /**********************************************************************//**
785 Prints info of a foreign key constraint. */
786 static
734d6226 787@@ -4529,7 +4917,8 @@
b4e1fa2c
AM
788
789 ut_ad(mutex_own(&(dict_sys->mutex)));
790
791- dict_update_statistics(table, FALSE /* update even if initialized */);
792+ if (srv_stats_auto_update)
793+ dict_update_statistics(table, FALSE /* update even if initialized */, FALSE);
794
795 dict_table_stats_lock(table, RW_S_LATCH);
796
db82db79
AM
797--- a/storage/innobase/dict/dict0load.c
798+++ b/storage/innobase/dict/dict0load.c
d8778560 799@@ -50,7 +50,8 @@
b4e1fa2c
AM
800 "SYS_COLUMNS",
801 "SYS_FIELDS",
802 "SYS_FOREIGN",
803- "SYS_FOREIGN_COLS"
804+ "SYS_FOREIGN_COLS",
805+ "SYS_STATS"
806 };
734d6226
AM
807
808 /* If this flag is TRUE, then we will load the cluster index's (and tables')
809@@ -348,12 +349,13 @@
b4e1fa2c
AM
810 }
811
812 if ((status & DICT_TABLE_UPDATE_STATS)
813+ && srv_stats_auto_update
814 && dict_table_get_first_index(*table)) {
815
816 /* Update statistics if DICT_TABLE_UPDATE_STATS
817 is set */
818 dict_update_statistics(*table, FALSE /* update even if
819- initialized */);
820+ initialized */, FALSE);
821 }
822
823 return(NULL);
734d6226 824@@ -587,6 +589,75 @@
d8778560 825 //#endif /* FOREIGN_NOT_USED */
b4e1fa2c 826
d8778560 827 /********************************************************************//**
b4e1fa2c
AM
828+This function parses a SYS_STATS record and extract necessary
829+information from the record and return to caller.
830+@return error message, or NULL on success */
831+UNIV_INTERN
832+const char*
833+dict_process_sys_stats_rec(
834+/*=============================*/
d8778560 835+ mem_heap_t* heap __attribute__((unused)), /*!< in/out: heap memory */
b4e1fa2c
AM
836+ const rec_t* rec, /*!< in: current SYS_STATS rec */
837+ index_id_t* index_id, /*!< out: INDEX_ID */
838+ ulint* key_cols, /*!< out: KEY_COLS */
11822e22
AM
839+ ib_uint64_t* diff_vals, /*!< out: DIFF_VALS */
840+ ib_uint64_t* non_null_vals) /*!< out: NON_NULL_VALS */
b4e1fa2c
AM
841+{
842+ ulint len;
843+ const byte* field;
11822e22 844+ ulint n_fields;
b4e1fa2c
AM
845+
846+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
847+ return("delete-marked record in SYS_STATS");
848+ }
849+
11822e22
AM
850+ n_fields = rec_get_n_fields_old(rec);
851+
852+ if (UNIV_UNLIKELY(n_fields < 5)) {
b4e1fa2c
AM
853+ return("wrong number of columns in SYS_STATS record");
854+ }
855+
856+ field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
857+ if (UNIV_UNLIKELY(len != 8)) {
858+err_len:
859+ return("incorrect column length in SYS_STATS");
860+ }
861+ *index_id = mach_read_from_8(field);
862+
863+ field = rec_get_nth_field_old(rec, 1/*KEY_COLS*/, &len);
864+ if (UNIV_UNLIKELY(len != 4)) {
865+ goto err_len;
866+ }
867+ *key_cols = mach_read_from_4(field);
868+
869+ rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
870+ if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
871+ goto err_len;
872+ }
873+ rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
874+ if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
875+ goto err_len;
876+ }
877+
878+ field = rec_get_nth_field_old(rec, 4/*DIFF_VALS*/, &len);
879+ if (UNIV_UNLIKELY(len != 8)) {
880+ goto err_len;
881+ }
882+ *diff_vals = mach_read_from_8(field);
883+
11822e22
AM
884+ if (n_fields < 6) {
885+ *non_null_vals = ((ib_uint64_t)(-1));
886+ } else {
887+ field = rec_get_nth_field_old(rec, 5/*NON_NULL_VALS*/, &len);
888+ if (UNIV_UNLIKELY(len != 8)) {
889+ goto err_len;
890+ }
891+ *non_null_vals = mach_read_from_8(field);
892+ }
893+
b4e1fa2c
AM
894+ return(NULL);
895+}
d8778560 896+/********************************************************************//**
b4e1fa2c
AM
897 Determine the flags of a table described in SYS_TABLES.
898 @return compressed page size in kilobytes; or 0 if the tablespace is
d8778560 899 uncompressed, ULINT_UNDEFINED on error */
db82db79
AM
900--- a/storage/innobase/handler/ha_innodb.cc
901+++ b/storage/innobase/handler/ha_innodb.cc
902@@ -188,6 +188,7 @@
b4e1fa2c
AM
903 static my_bool innobase_create_status_file = FALSE;
904 static my_bool innobase_stats_on_metadata = TRUE;
db82db79 905 static my_bool innobase_large_prefix = FALSE;
b4e1fa2c
AM
906+static my_bool innobase_use_sys_stats_table = FALSE;
907
908
909 static char* internal_innobase_data_file_path = NULL;
734d6226 910@@ -2468,6 +2469,8 @@
b4e1fa2c
AM
911 goto error;
912 }
913
914+ srv_use_sys_stats_table = (ibool) innobase_use_sys_stats_table;
915+
916 /* -------------- Log files ---------------------------*/
917
918 /* The default dir for log files is the datadir of MySQL */
13ceb006 919@@ -5256,6 +5259,10 @@
b4e1fa2c
AM
920
921 error = row_insert_for_mysql((byte*) record, prebuilt);
922
923+#ifdef EXTENDED_FOR_USERSTAT
924+ if (error == DB_SUCCESS) rows_changed++;
925+#endif
926+
927 /* Handle duplicate key errors */
928 if (auto_inc_used) {
929 ulint err;
1bfc1981 930@@ -5591,6 +5598,10 @@
b4e1fa2c
AM
931 }
932 }
933
934+#ifdef EXTENDED_FOR_USERSTAT
935+ if (error == DB_SUCCESS) rows_changed++;
936+#endif
937+
938 innodb_srv_conc_exit_innodb(trx);
939
940 error = convert_error_code_to_mysql(error,
1bfc1981 941@@ -5644,6 +5655,10 @@
b4e1fa2c
AM
942
943 error = row_update_for_mysql((byte*) record, prebuilt);
944
945+#ifdef EXTENDED_FOR_USERSTAT
946+ if (error == DB_SUCCESS) rows_changed++;
947+#endif
948+
949 innodb_srv_conc_exit_innodb(trx);
950
951 error = convert_error_code_to_mysql(
1bfc1981 952@@ -5965,6 +5980,11 @@
d8778560
AM
953 case DB_SUCCESS:
954 error = 0;
955 table->status = 0;
956+#ifdef EXTENDED_FOR_USERSTAT
957+ rows_read++;
db82db79 958+ if (active_index < MAX_KEY)
d8778560
AM
959+ index_rows_read[active_index]++;
960+#endif
961 break;
962 case DB_RECORD_NOT_FOUND:
963 error = HA_ERR_KEY_NOT_FOUND;
1bfc1981 964@@ -6197,6 +6217,11 @@
b4e1fa2c
AM
965 case DB_SUCCESS:
966 error = 0;
967 table->status = 0;
968+#ifdef EXTENDED_FOR_USERSTAT
969+ rows_read++;
db82db79 970+ if (active_index < MAX_KEY)
b4e1fa2c
AM
971+ index_rows_read[active_index]++;
972+#endif
973 break;
974 case DB_RECORD_NOT_FOUND:
975 error = HA_ERR_END_OF_FILE;
1bfc1981 976@@ -8150,11 +8175,35 @@
b4e1fa2c
AM
977 /* In sql_show we call with this flag: update
978 then statistics so that they are up-to-date */
979
980+ if (srv_use_sys_stats_table && !((ib_table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)
981+ && called_from_analyze) {
982+ /* If the indexes on the table don't have enough rows in SYS_STATS system table, */
983+ /* they need to be created. */
984+ dict_index_t* index;
985+
986+ prebuilt->trx->op_info = "confirming rows of SYS_STATS to store statistics";
987+
988+ ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
989+
990+ for (index = dict_table_get_first_index(ib_table);
991+ index != NULL;
992+ index = dict_table_get_next_index(index)) {
11822e22
AM
993+ if (dict_is_older_statistics(index)) {
994+ row_delete_stats_for_mysql(index, prebuilt->trx);
995+ innobase_commit_low(prebuilt->trx);
996+ }
b4e1fa2c
AM
997+ row_insert_stats_for_mysql(index, prebuilt->trx);
998+ innobase_commit_low(prebuilt->trx);
999+ }
1000+
1001+ ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
1002+ }
1003+
1004 prebuilt->trx->op_info = "updating table statistics";
1005
1006 dict_update_statistics(ib_table,
1007 FALSE /* update even if stats
1008- are initialized */);
1009+ are initialized */, called_from_analyze);
1010
1011 prebuilt->trx->op_info = "returning various info to MySQL";
1012 }
1bfc1981 1013@@ -8239,7 +8288,7 @@
b4e1fa2c
AM
1014 are asked by MySQL to avoid locking. Another reason to
1015 avoid the call is that it uses quite a lot of CPU.
1016 See Bug#38185. */
d8778560
AM
1017- if (flag & HA_STATUS_NO_LOCK
1018+ if (flag & HA_STATUS_NO_LOCK || !srv_stats_update_need_lock
1019 || !(flag & HA_STATUS_VARIABLE_EXTRA)) {
b4e1fa2c
AM
1020 /* We do not update delete_length if no
1021 locking is requested so the "old" value can
1bfc1981 1022@@ -11512,6 +11561,26 @@
b4e1fa2c
AM
1023 "The number of index pages to sample when calculating statistics (default 8)",
1024 NULL, NULL, 8, 1, ~0ULL, 0);
1025
b4e1fa2c
AM
1026+static MYSQL_SYSVAR_ULONG(stats_auto_update, srv_stats_auto_update,
1027+ PLUGIN_VAR_RQCMDARG,
1028+ "Enable/Disable InnoDB's auto update statistics of indexes. "
1029+ "(except for ANALYZE TABLE command) 0:disable 1:enable",
1030+ NULL, NULL, 1, 0, 1, 0);
1031+
1032+static MYSQL_SYSVAR_ULONG(stats_update_need_lock, srv_stats_update_need_lock,
1033+ PLUGIN_VAR_RQCMDARG,
1034+ "Enable/Disable InnoDB's update statistics which needs to lock dictionary. "
1035+ "e.g. Data_free.",
1036+ NULL, NULL, 1, 0, 1, 0);
1037+
1038+static MYSQL_SYSVAR_BOOL(use_sys_stats_table, innobase_use_sys_stats_table,
1039+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
1040+ "Enable to use SYS_STATS system table to store statistics statically, "
1041+ "And avoids to calculate statistics at every first open of the tables. "
1042+ "This option may make the opportunities of update statistics less. "
1043+ "So you should use ANALYZE TABLE command intentionally.",
1044+ NULL, NULL, FALSE);
1045+
1046 static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
1047 PLUGIN_VAR_OPCMDARG,
1048 "Enable InnoDB adaptive hash index (enabled by default). "
1bfc1981 1049@@ -11844,6 +11913,9 @@
a9ee80b9 1050 MYSQL_SYSVAR(recovery_update_relay_log),
b4e1fa2c
AM
1051 MYSQL_SYSVAR(rollback_on_timeout),
1052 MYSQL_SYSVAR(stats_on_metadata),
b4e1fa2c
AM
1053+ MYSQL_SYSVAR(stats_auto_update),
1054+ MYSQL_SYSVAR(stats_update_need_lock),
1055+ MYSQL_SYSVAR(use_sys_stats_table),
1056 MYSQL_SYSVAR(stats_sample_pages),
1057 MYSQL_SYSVAR(adaptive_hash_index),
df1b5770 1058 MYSQL_SYSVAR(stats_method),
1bfc1981 1059@@ -11915,7 +11987,10 @@
b4e1fa2c
AM
1060 i_s_innodb_sys_columns,
1061 i_s_innodb_sys_fields,
1062 i_s_innodb_sys_foreign,
1063-i_s_innodb_sys_foreign_cols
1064+i_s_innodb_sys_foreign_cols,
1065+i_s_innodb_sys_stats,
1066+i_s_innodb_table_stats,
1067+i_s_innodb_index_stats
1068 mysql_declare_plugin_end;
1069
1070 /** @brief Initialize the default value of innodb_commit_concurrency.
db82db79
AM
1071--- a/storage/innobase/handler/i_s.cc
1072+++ b/storage/innobase/handler/i_s.cc
b4e1fa2c
AM
1073@@ -49,6 +49,7 @@
1074 #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
1075 #include "trx0rseg.h" /* for trx_rseg_struct */
1076 #include "trx0sys.h" /* for trx_sys */
1077+#include "dict0dict.h" /* for dict_sys */
1078 }
1079
adf0fb13 1080 #define OK(expr) \
13ceb006
AM
1081@@ -3511,6 +3512,225 @@
1082 STRUCT_FLD(flags, 0UL)
b4e1fa2c
AM
1083 };
1084
1085+/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_stats */
1086+static ST_FIELD_INFO innodb_sys_stats_fields_info[] =
1087+{
1088+#define SYS_STATS_INDEX_ID 0
1089+ {STRUCT_FLD(field_name, "INDEX_ID"),
1090+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1091+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1092+ STRUCT_FLD(value, 0),
1093+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1094+ STRUCT_FLD(old_name, ""),
1095+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1096+
1097+#define SYS_STATS_KEY_COLS 1
1098+ {STRUCT_FLD(field_name, "KEY_COLS"),
1099+ STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS),
1100+ STRUCT_FLD(field_type, MYSQL_TYPE_LONG),
1101+ STRUCT_FLD(value, 0),
1102+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1103+ STRUCT_FLD(old_name, ""),
1104+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1105+
1106+#define SYS_STATS_DIFF_VALS 2
1107+ {STRUCT_FLD(field_name, "DIFF_VALS"),
1108+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1109+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1110+ STRUCT_FLD(value, 0),
1111+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1112+ STRUCT_FLD(old_name, ""),
1113+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1114+
11822e22
AM
1115+#define SYS_STATS_NON_NULL_VALS 3
1116+ {STRUCT_FLD(field_name, "NON_NULL_VALS"),
1117+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1118+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1119+ STRUCT_FLD(value, 0),
1120+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
1121+ STRUCT_FLD(old_name, ""),
1122+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1123+
b4e1fa2c
AM
1124+ END_OF_ST_FIELD_INFO
1125+};
1126+/**********************************************************************//**
1127+Function to fill information_schema.innodb_sys_stats
1128+@return 0 on success */
1129+static
1130+int
1131+i_s_dict_fill_sys_stats(
1132+/*====================*/
1133+ THD* thd, /*!< in: thread */
1134+ index_id_t index_id, /*!< in: INDEX_ID */
1135+ ulint key_cols, /*!< in: KEY_COLS */
1136+ ib_uint64_t diff_vals, /*!< in: DIFF_VALS */
11822e22 1137+ ib_uint64_t non_null_vals, /*!< in: NON_NULL_VALS */
b4e1fa2c
AM
1138+ TABLE* table_to_fill) /*!< in/out: fill this table */
1139+{
1140+ Field** fields;
1141+
1142+ DBUG_ENTER("i_s_dict_fill_sys_stats");
1143+
1144+ fields = table_to_fill->field;
1145+
1146+ OK(fields[SYS_STATS_INDEX_ID]->store(longlong(index_id), TRUE));
1147+
1148+ OK(fields[SYS_STATS_KEY_COLS]->store(key_cols));
1149+
1150+ OK(fields[SYS_STATS_DIFF_VALS]->store(longlong(diff_vals), TRUE));
1151+
11822e22
AM
1152+ if (non_null_vals == ((ib_uint64_t)(-1))) {
1153+ fields[SYS_STATS_NON_NULL_VALS]->set_null();
1154+ } else {
1155+ OK(fields[SYS_STATS_NON_NULL_VALS]->store(longlong(non_null_vals), TRUE));
1156+ fields[SYS_STATS_NON_NULL_VALS]->set_notnull();
1157+ }
1158+
b4e1fa2c
AM
1159+ OK(schema_table_store_record(thd, table_to_fill));
1160+
1161+ DBUG_RETURN(0);
1162+}
1163+/*******************************************************************//**
1164+Function to populate INFORMATION_SCHEMA.innodb_sys_stats table.
1165+@return 0 on success */
1166+static
1167+int
1168+i_s_sys_stats_fill_table(
1169+/*=====================*/
1170+ THD* thd, /*!< in: thread */
1171+ TABLE_LIST* tables, /*!< in/out: tables to fill */
1172+ COND* cond) /*!< in: condition (not used) */
1173+{
1174+ btr_pcur_t pcur;
1175+ const rec_t* rec;
1176+ mem_heap_t* heap;
1177+ mtr_t mtr;
1178+
1179+ DBUG_ENTER("i_s_sys_stats_fill_table");
1180+
1181+ /* deny access to non-superusers */
1182+ if (check_global_access(thd, PROCESS_ACL)) {
1183+ DBUG_RETURN(0);
1184+ }
1185+
1186+ heap = mem_heap_create(1000);
1187+ mutex_enter(&dict_sys->mutex);
1188+ mtr_start(&mtr);
1189+
1190+ rec = dict_startscan_system(&pcur, &mtr, SYS_STATS);
1191+
1192+ while (rec) {
1193+ const char* err_msg;
1194+ index_id_t index_id;
1195+ ulint key_cols;
1196+ ib_uint64_t diff_vals;
11822e22 1197+ ib_uint64_t non_null_vals;
b4e1fa2c
AM
1198+
1199+ /* Extract necessary information from a SYS_FOREIGN_COLS row */
1200+ err_msg = dict_process_sys_stats_rec(
11822e22 1201+ heap, rec, &index_id, &key_cols, &diff_vals, &non_null_vals);
b4e1fa2c
AM
1202+
1203+ mtr_commit(&mtr);
1204+ mutex_exit(&dict_sys->mutex);
1205+
1206+ if (!err_msg) {
1207+ i_s_dict_fill_sys_stats(
11822e22 1208+ thd, index_id, key_cols, diff_vals, non_null_vals,
b4e1fa2c
AM
1209+ tables->table);
1210+ } else {
1211+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
1212+ ER_CANT_FIND_SYSTEM_REC,
1213+ err_msg);
1214+ }
1215+
1216+ mem_heap_empty(heap);
1217+
1218+ /* Get the next record */
1219+ mutex_enter(&dict_sys->mutex);
1220+ mtr_start(&mtr);
1221+ rec = dict_getnext_system(&pcur, &mtr);
1222+ }
1223+
1224+ mtr_commit(&mtr);
1225+ mutex_exit(&dict_sys->mutex);
1226+ mem_heap_free(heap);
1227+
1228+ DBUG_RETURN(0);
1229+}
1230+/*******************************************************************//**
1231+Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_stats
1232+@return 0 on success */
1233+static
1234+int
1235+innodb_sys_stats_init(
1236+/*========================*/
1237+ void* p) /*!< in/out: table schema object */
1238+{
1239+ ST_SCHEMA_TABLE* schema;
1240+
1241+ DBUG_ENTER("innodb_sys_stats_init");
1242+
1243+ schema = (ST_SCHEMA_TABLE*) p;
1244+
1245+ schema->fields_info = innodb_sys_stats_fields_info;
1246+ schema->fill_table = i_s_sys_stats_fill_table;
1247+
1248+ DBUG_RETURN(0);
1249+}
1250+
1251+UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_stats =
1252+{
1253+ /* the plugin type (a MYSQL_XXX_PLUGIN value) */
1254+ /* int */
1255+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1256+
1257+ /* pointer to type-specific plugin descriptor */
1258+ /* void* */
1259+ STRUCT_FLD(info, &i_s_info),
1260+
1261+ /* plugin name */
1262+ /* const char* */
1263+ STRUCT_FLD(name, "INNODB_SYS_STATS"),
1264+
1265+ /* plugin author (for SHOW PLUGINS) */
1266+ /* const char* */
adf0fb13 1267+ STRUCT_FLD(author, "Percona"),
b4e1fa2c
AM
1268+
1269+ /* general descriptive text (for SHOW PLUGINS) */
1270+ /* const char* */
1271+ STRUCT_FLD(descr, "XtraDB SYS_STATS table"),
1272+
1273+ /* the plugin license (PLUGIN_LICENSE_XXX) */
1274+ /* int */
1275+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1276+
1277+ /* the function to invoke when plugin is loaded */
1278+ /* int (*)(void*); */
1279+ STRUCT_FLD(init, innodb_sys_stats_init),
1280+
1281+ /* the function to invoke when plugin is unloaded */
1282+ /* int (*)(void*); */
1283+ STRUCT_FLD(deinit, i_s_common_deinit),
1284+
1285+ /* plugin version (for SHOW PLUGINS) */
1286+ /* unsigned int */
1287+ STRUCT_FLD(version, INNODB_VERSION_SHORT),
1288+
1289+ /* struct st_mysql_show_var* */
1290+ STRUCT_FLD(status_vars, NULL),
1291+
1292+ /* struct st_mysql_sys_var** */
1293+ STRUCT_FLD(system_vars, NULL),
1294+
1295+ /* reserved for dependency checking */
1296+ /* void* */
13ceb006
AM
1297+ STRUCT_FLD(__reserved1, NULL),
1298+
1299+ /* flags for plugin */
1300+ /* unsigned long */
1301+ STRUCT_FLD(flags, 0UL)
b4e1fa2c
AM
1302+};
1303+
1304 /***********************************************************************
1305 */
1306 static ST_FIELD_INFO i_s_innodb_rseg_fields_info[] =
13ceb006
AM
1307@@ -3677,3 +3897,349 @@
1308 /* unsigned long */
1bfc1981 1309 STRUCT_FLD(flags, 0UL),
b4e1fa2c
AM
1310 };
1311+
1312+/***********************************************************************
1313+*/
1314+static ST_FIELD_INFO i_s_innodb_table_stats_info[] =
1315+{
1316+ {STRUCT_FLD(field_name, "table_schema"),
1317+ STRUCT_FLD(field_length, NAME_LEN),
1318+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1319+ STRUCT_FLD(value, 0),
1320+ STRUCT_FLD(field_flags, 0),
1321+ STRUCT_FLD(old_name, ""),
1322+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1323+
1324+ {STRUCT_FLD(field_name, "table_name"),
1325+ STRUCT_FLD(field_length, NAME_LEN),
1326+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1327+ STRUCT_FLD(value, 0),
1328+ STRUCT_FLD(field_flags, 0),
1329+ STRUCT_FLD(old_name, ""),
1330+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1331+
1332+ {STRUCT_FLD(field_name, "rows"),
1333+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1334+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1335+ STRUCT_FLD(value, 0),
1336+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1337+ STRUCT_FLD(old_name, ""),
1338+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1339+
1340+ {STRUCT_FLD(field_name, "clust_size"),
1341+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1342+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1343+ STRUCT_FLD(value, 0),
1344+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1345+ STRUCT_FLD(old_name, ""),
1346+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1347+
1348+ {STRUCT_FLD(field_name, "other_size"),
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+ {STRUCT_FLD(field_name, "modified"),
1357+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1358+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1359+ STRUCT_FLD(value, 0),
1360+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1361+ STRUCT_FLD(old_name, ""),
1362+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1363+
1364+ END_OF_ST_FIELD_INFO
1365+};
1366+
1367+static ST_FIELD_INFO i_s_innodb_index_stats_info[] =
1368+{
1369+ {STRUCT_FLD(field_name, "table_schema"),
1370+ STRUCT_FLD(field_length, NAME_LEN),
1371+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1372+ STRUCT_FLD(value, 0),
1373+ STRUCT_FLD(field_flags, 0),
1374+ STRUCT_FLD(old_name, ""),
1375+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1376+
1377+ {STRUCT_FLD(field_name, "table_name"),
1378+ STRUCT_FLD(field_length, NAME_LEN),
1379+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1380+ STRUCT_FLD(value, 0),
1381+ STRUCT_FLD(field_flags, 0),
1382+ STRUCT_FLD(old_name, ""),
1383+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1384+
1385+ {STRUCT_FLD(field_name, "index_name"),
1386+ STRUCT_FLD(field_length, NAME_LEN),
1387+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1388+ STRUCT_FLD(value, 0),
1389+ STRUCT_FLD(field_flags, 0),
1390+ STRUCT_FLD(old_name, ""),
1391+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1392+
1393+ {STRUCT_FLD(field_name, "fields"),
1394+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1395+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1396+ STRUCT_FLD(value, 0),
1397+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1398+ STRUCT_FLD(old_name, ""),
1399+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1400+
1401+ {STRUCT_FLD(field_name, "rows_per_key"),
1402+ STRUCT_FLD(field_length, 256),
1403+ STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
1404+ STRUCT_FLD(value, 0),
1405+ STRUCT_FLD(field_flags, 0),
1406+ STRUCT_FLD(old_name, ""),
1407+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1408+
1409+ {STRUCT_FLD(field_name, "index_total_pages"),
1410+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1411+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1412+ STRUCT_FLD(value, 0),
1413+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1414+ STRUCT_FLD(old_name, ""),
1415+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1416+
1417+ {STRUCT_FLD(field_name, "index_leaf_pages"),
1418+ STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
1419+ STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
1420+ STRUCT_FLD(value, 0),
1421+ STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
1422+ STRUCT_FLD(old_name, ""),
1423+ STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
1424+
1425+ END_OF_ST_FIELD_INFO
1426+};
1427+
1428+static
1429+int
1430+i_s_innodb_table_stats_fill(
1431+/*========================*/
1432+ THD* thd,
1433+ TABLE_LIST* tables,
1434+ COND* cond)
1435+{
1436+ TABLE* i_s_table = (TABLE *) tables->table;
1437+ int status = 0;
1438+ dict_table_t* table;
1439+
1440+ DBUG_ENTER("i_s_innodb_table_stats_fill");
1441+
1442+ /* deny access to non-superusers */
1443+ if (check_global_access(thd, PROCESS_ACL)) {
1444+ DBUG_RETURN(0);
1445+ }
1446+
1447+ mutex_enter(&(dict_sys->mutex));
1448+
1449+ table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1450+
1451+ while (table) {
1452+ char buf[NAME_LEN * 2 + 2];
1453+ char* ptr;
1454+
1455+ if (table->stat_clustered_index_size == 0) {
1456+ table = UT_LIST_GET_NEXT(table_LRU, table);
1457+ continue;
1458+ }
1459+
1460+ buf[NAME_LEN * 2 + 1] = 0;
1461+ strncpy(buf, table->name, NAME_LEN * 2 + 1);
1462+ ptr = strchr(buf, '/');
1463+ if (ptr) {
1464+ *ptr = '\0';
1465+ ++ptr;
1466+ } else {
1467+ ptr = buf;
1468+ }
1469+
1470+ field_store_string(i_s_table->field[0], buf);
1471+ field_store_string(i_s_table->field[1], ptr);
1472+ i_s_table->field[2]->store(table->stat_n_rows);
1473+ i_s_table->field[3]->store(table->stat_clustered_index_size);
1474+ i_s_table->field[4]->store(table->stat_sum_of_other_index_sizes);
1475+ i_s_table->field[5]->store(table->stat_modified_counter);
1476+
1477+ if (schema_table_store_record(thd, i_s_table)) {
1478+ status = 1;
1479+ break;
1480+ }
1481+
1482+ table = UT_LIST_GET_NEXT(table_LRU, table);
1483+ }
1484+
1485+ mutex_exit(&(dict_sys->mutex));
1486+
1487+ DBUG_RETURN(status);
1488+}
1489+
1490+static
1491+int
1492+i_s_innodb_index_stats_fill(
1493+/*========================*/
1494+ THD* thd,
1495+ TABLE_LIST* tables,
1496+ COND* cond)
1497+{
1498+ TABLE* i_s_table = (TABLE *) tables->table;
1499+ int status = 0;
1500+ dict_table_t* table;
1501+ dict_index_t* index;
1502+
1503+ DBUG_ENTER("i_s_innodb_index_stats_fill");
1504+
1505+ /* deny access to non-superusers */
1506+ if (check_global_access(thd, PROCESS_ACL)) {
1507+ DBUG_RETURN(0);
1508+ }
1509+
1510+ mutex_enter(&(dict_sys->mutex));
1511+
1512+ table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1513+
1514+ while (table) {
1515+ if (table->stat_clustered_index_size == 0) {
1516+ table = UT_LIST_GET_NEXT(table_LRU, table);
1517+ continue;
1518+ }
1519+
1520+ ib_int64_t n_rows = table->stat_n_rows;
1521+
1522+ if (n_rows < 0) {
1523+ n_rows = 0;
1524+ }
1525+
1526+ index = dict_table_get_first_index(table);
1527+
1528+ while (index) {
1529+ char buff[256+1];
1530+ char row_per_keys[256+1];
1531+ char buf[NAME_LEN * 2 + 2];
1532+ char* ptr;
1533+ ulint i;
1534+
1535+ buf[NAME_LEN * 2 + 1] = 0;
1536+ strncpy(buf, table->name, NAME_LEN * 2 + 1);
1537+ ptr = strchr(buf, '/');
1538+ if (ptr) {
1539+ *ptr = '\0';
1540+ ++ptr;
1541+ } else {
1542+ ptr = buf;
1543+ }
1544+
1545+ field_store_string(i_s_table->field[0], buf);
1546+ field_store_string(i_s_table->field[1], ptr);
1547+ field_store_string(i_s_table->field[2], index->name);
1548+ i_s_table->field[3]->store(index->n_uniq);
1549+
1550+ row_per_keys[0] = '\0';
1551+
1552+ /* It is remained optimistic operation still for now */
1553+ //dict_index_stat_mutex_enter(index);
1554+ if (index->stat_n_diff_key_vals) {
1555+ for (i = 1; i <= index->n_uniq; i++) {
1556+ ib_int64_t rec_per_key;
1557+ if (index->stat_n_diff_key_vals[i]) {
1558+ rec_per_key = n_rows / index->stat_n_diff_key_vals[i];
1559+ } else {
1560+ rec_per_key = n_rows;
1561+ }
1562+ ut_snprintf(buff, 256, (i == index->n_uniq)?"%llu":"%llu, ",
1563+ rec_per_key);
1564+ strncat(row_per_keys, buff, 256 - strlen(row_per_keys));
1565+ }
1566+ }
1567+ //dict_index_stat_mutex_exit(index);
1568+
1569+ field_store_string(i_s_table->field[4], row_per_keys);
1570+
1571+ i_s_table->field[5]->store(index->stat_index_size);
1572+ i_s_table->field[6]->store(index->stat_n_leaf_pages);
1573+
1574+ if (schema_table_store_record(thd, i_s_table)) {
1575+ status = 1;
1576+ break;
1577+ }
1578+
1579+ index = dict_table_get_next_index(index);
1580+ }
1581+
1582+ if (status == 1) {
1583+ break;
1584+ }
1585+
1586+ table = UT_LIST_GET_NEXT(table_LRU, table);
1587+ }
1588+
1589+ mutex_exit(&(dict_sys->mutex));
1590+
1591+ DBUG_RETURN(status);
1592+}
1593+
1594+static
1595+int
1596+i_s_innodb_table_stats_init(
1597+/*========================*/
1598+ void* p)
1599+{
1600+ DBUG_ENTER("i_s_innodb_table_stats_init");
1601+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1602+
1603+ schema->fields_info = i_s_innodb_table_stats_info;
1604+ schema->fill_table = i_s_innodb_table_stats_fill;
1605+
1606+ DBUG_RETURN(0);
1607+}
1608+
1609+static
1610+int
1611+i_s_innodb_index_stats_init(
1612+/*========================*/
1613+ void* p)
1614+{
1615+ DBUG_ENTER("i_s_innodb_index_stats_init");
1616+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1617+
1618+ schema->fields_info = i_s_innodb_index_stats_info;
1619+ schema->fill_table = i_s_innodb_index_stats_fill;
1620+
1621+ DBUG_RETURN(0);
1622+}
1623+
1624+UNIV_INTERN struct st_mysql_plugin i_s_innodb_table_stats =
1625+{
1626+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1627+ STRUCT_FLD(info, &i_s_info),
1628+ STRUCT_FLD(name, "INNODB_TABLE_STATS"),
adf0fb13 1629+ STRUCT_FLD(author, "Percona"),
b4e1fa2c
AM
1630+ STRUCT_FLD(descr, "InnoDB table statistics in memory"),
1631+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1632+ STRUCT_FLD(init, i_s_innodb_table_stats_init),
1633+ STRUCT_FLD(deinit, i_s_common_deinit),
1634+ STRUCT_FLD(version, 0x0100 /* 1.0 */),
1635+ STRUCT_FLD(status_vars, NULL),
1636+ STRUCT_FLD(system_vars, NULL),
13ceb006
AM
1637+ STRUCT_FLD(__reserved1, NULL),
1638+ STRUCT_FLD(flags, 0UL)
b4e1fa2c
AM
1639+};
1640+
1641+UNIV_INTERN struct st_mysql_plugin i_s_innodb_index_stats =
1642+{
1643+ STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1644+ STRUCT_FLD(info, &i_s_info),
1645+ STRUCT_FLD(name, "INNODB_INDEX_STATS"),
adf0fb13 1646+ STRUCT_FLD(author, "Percona"),
b4e1fa2c
AM
1647+ STRUCT_FLD(descr, "InnoDB index statistics in memory"),
1648+ STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1649+ STRUCT_FLD(init, i_s_innodb_index_stats_init),
1650+ STRUCT_FLD(deinit, i_s_common_deinit),
1651+ STRUCT_FLD(version, 0x0100 /* 1.0 */),
1652+ STRUCT_FLD(status_vars, NULL),
1653+ STRUCT_FLD(system_vars, NULL),
13ceb006
AM
1654+ STRUCT_FLD(__reserved1, NULL),
1655+ STRUCT_FLD(flags, 0UL)
b4e1fa2c 1656+};
db82db79
AM
1657--- a/storage/innobase/handler/i_s.h
1658+++ b/storage/innobase/handler/i_s.h
adf0fb13 1659@@ -43,5 +43,8 @@
b4e1fa2c
AM
1660 extern struct st_mysql_plugin i_s_innodb_sys_foreign;
1661 extern struct st_mysql_plugin i_s_innodb_sys_foreign_cols;
1662 extern struct st_mysql_plugin i_s_innodb_rseg;
1663+extern struct st_mysql_plugin i_s_innodb_sys_stats;
1664+extern struct st_mysql_plugin i_s_innodb_table_stats;
1665+extern struct st_mysql_plugin i_s_innodb_index_stats;
1666
1667 #endif /* i_s_h */
db82db79
AM
1668--- a/storage/innobase/include/dict0boot.h
1669+++ b/storage/innobase/include/dict0boot.h
b4e1fa2c
AM
1670@@ -104,6 +104,7 @@
1671 #define DICT_COLUMNS_ID 2
1672 #define DICT_INDEXES_ID 3
1673 #define DICT_FIELDS_ID 4
1674+#define DICT_STATS_ID 6
1675 /* The following is a secondary index on SYS_TABLES */
1676 #define DICT_TABLE_IDS_ID 5
1677
1678@@ -131,10 +132,13 @@
1679 #define DICT_HDR_INDEXES 44 /* Root of the index index tree */
1680 #define DICT_HDR_FIELDS 48 /* Root of the index field
1681 index tree */
1682+#define DICT_HDR_STATS 52 /* Root of the stats tree */
1683
1684 #define DICT_HDR_FSEG_HEADER 56 /* Segment header for the tablespace
1685 segment into which the dictionary
1686 header is created */
1687+
1688+#define DICT_HDR_XTRADB_MARK 256 /* Flag to distinguish expansion of XtraDB */
1689 /*-------------------------------------------------------------*/
1690
734d6226
AM
1691 /* The field numbers in the SYS_TABLES clustered index */
1692@@ -146,11 +150,16 @@
b4e1fa2c
AM
1693 #define DICT_SYS_INDEXES_TYPE_FIELD 6
1694 #define DICT_SYS_INDEXES_NAME_FIELD 4
1695
1696+#define DICT_SYS_STATS_DIFF_VALS_FIELD 4
11822e22 1697+#define DICT_SYS_STATS_NON_NULL_VALS_FIELD 5
b4e1fa2c
AM
1698+
1699 /* When a row id which is zero modulo this number (which must be a power of
1700 two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is
1701 updated */
1702 #define DICT_HDR_ROW_ID_WRITE_MARGIN 256
1703
1704+#define DICT_HDR_XTRADB_FLAG 0x5854524144425F31ULL /* "XTRADB_1" */
1705+
1706 #ifndef UNIV_NONINL
1707 #include "dict0boot.ic"
1708 #endif
db82db79
AM
1709--- a/storage/innobase/include/dict0crea.h
1710+++ b/storage/innobase/include/dict0crea.h
b4e1fa2c
AM
1711@@ -53,6 +53,14 @@
1712 dict_index_t* index, /*!< in: index to create, built as a memory data
1713 structure */
1714 mem_heap_t* heap); /*!< in: heap where created */
1715+/*********************************************************************//**
1716+*/
1717+UNIV_INTERN
1718+ind_node_t*
1719+ind_insert_stats_graph_create(
1720+/*==========================*/
1721+ dict_index_t* index,
1722+ mem_heap_t* heap);
1723 /***********************************************************//**
1724 Creates a table. This is a high-level function used in SQL execution graphs.
1725 @return query thread to run next or NULL */
1726@@ -62,6 +70,13 @@
1727 /*===================*/
1728 que_thr_t* thr); /*!< in: query thread */
1729 /***********************************************************//**
1730+*/
1731+UNIV_INTERN
1732+que_thr_t*
1733+dict_insert_stats_step(
1734+/*===================*/
1735+ que_thr_t* thr);
1736+/***********************************************************//**
1737 Creates an index. This is a high-level function used in SQL execution
1738 graphs.
1739 @return query thread to run next or NULL */
1740@@ -170,6 +185,7 @@
1741 ins_node_t* field_def; /* child node which does the inserts of
1742 the field definitions; the row to be inserted
1743 is built by the parent node */
1744+ ins_node_t* stats_def;
1745 commit_node_t* commit_node;
1746 /* child node which performs a commit after
1747 a successful index creation */
1748@@ -180,6 +196,7 @@
1749 dict_table_t* table; /*!< table which owns the index */
1750 dtuple_t* ind_row;/* index definition row built */
1751 ulint field_no;/* next field definition to insert */
1752+ ulint stats_no;
1753 mem_heap_t* heap; /*!< memory heap used as auxiliary storage */
1754 };
1755
1756@@ -189,6 +206,7 @@
1757 #define INDEX_CREATE_INDEX_TREE 3
1758 #define INDEX_COMMIT_WORK 4
1759 #define INDEX_ADD_TO_CACHE 5
1760+#define INDEX_BUILD_STATS_COLS 6
1761
1762 #ifndef UNIV_NONINL
1763 #include "dict0crea.ic"
db82db79
AM
1764--- a/storage/innobase/include/dict0dict.h
1765+++ b/storage/innobase/include/dict0dict.h
734d6226 1766@@ -1126,10 +1126,18 @@
b4e1fa2c
AM
1767 dict_update_statistics(
1768 /*===================*/
1769 dict_table_t* table, /*!< in/out: table */
1770- ibool only_calc_if_missing_stats);/*!< in: only
1771+ ibool only_calc_if_missing_stats, /*!< in: only
1772 update/recalc the stats if they have
1773 not been initialized yet, otherwise
1774 do nothing */
1775+ ibool sync);
11822e22
AM
1776+/*********************************************************************//**
1777+*/
1778+UNIV_INTERN
1779+ibool
1780+dict_is_older_statistics(
1781+/*=====================*/
1782+ dict_index_t* index);
b4e1fa2c
AM
1783 /********************************************************************//**
1784 Reserves the dictionary system mutex for MySQL. */
1785 UNIV_INTERN
734d6226 1786@@ -1244,6 +1252,7 @@
b4e1fa2c
AM
1787 dict_table_t* sys_columns; /*!< SYS_COLUMNS table */
1788 dict_table_t* sys_indexes; /*!< SYS_INDEXES table */
1789 dict_table_t* sys_fields; /*!< SYS_FIELDS table */
1790+ dict_table_t* sys_stats; /*!< SYS_STATS table */
1791 };
1792 #endif /* !UNIV_HOTBACKUP */
1793
db82db79
AM
1794--- a/storage/innobase/include/dict0load.h
1795+++ b/storage/innobase/include/dict0load.h
b4e1fa2c
AM
1796@@ -41,6 +41,7 @@
1797 SYS_FIELDS,
1798 SYS_FOREIGN,
1799 SYS_FOREIGN_COLS,
1800+ SYS_STATS,
1801
1802 /* This must be last item. Defines the number of system tables. */
1803 SYS_NUM_SYSTEM_TABLES
db82db79 1804@@ -327,6 +328,20 @@
b4e1fa2c
AM
1805 const char** ref_col_name, /*!< out: referenced column name
1806 in referenced table */
1807 ulint* pos); /*!< out: column position */
1808+/********************************************************************//**
1809+This function parses a SYS_STATS record and extract necessary
1810+information from the record and return to caller.
1811+@return error message, or NULL on success */
1812+UNIV_INTERN
1813+const char*
1814+dict_process_sys_stats_rec(
1815+/*=============================*/
1816+ mem_heap_t* heap, /*!< in/out: heap memory */
1817+ const rec_t* rec, /*!< in: current SYS_STATS rec */
1818+ index_id_t* index_id, /*!< out: INDEX_ID */
1819+ ulint* key_cols, /*!< out: KEY_COLS */
11822e22
AM
1820+ ib_uint64_t* diff_vals, /*!< out: DIFF_VALS */
1821+ ib_uint64_t* non_null_vals); /*!< out: NON_NULL_VALS */
b4e1fa2c
AM
1822 #ifndef UNIV_NONINL
1823 #include "dict0load.ic"
1824 #endif
db82db79
AM
1825--- a/storage/innobase/include/que0que.h
1826+++ b/storage/innobase/include/que0que.h
b4e1fa2c
AM
1827@@ -492,6 +492,8 @@
1828 #define QUE_NODE_CALL 31
1829 #define QUE_NODE_EXIT 32
1830
1831+#define QUE_NODE_INSERT_STATS 34
1832+
1833 /* Query thread states */
1834 #define QUE_THR_RUNNING 1
1835 #define QUE_THR_PROCEDURE_WAIT 2
db82db79
AM
1836--- a/storage/innobase/include/row0mysql.h
1837+++ b/storage/innobase/include/row0mysql.h
11822e22 1838@@ -387,6 +387,22 @@
b4e1fa2c
AM
1839 then checked for not being too
1840 large. */
1841 /*********************************************************************//**
1842+*/
1843+UNIV_INTERN
1844+int
1845+row_insert_stats_for_mysql(
1846+/*=======================*/
1847+ dict_index_t* index,
1848+ trx_t* trx);
11822e22
AM
1849+/*********************************************************************//**
1850+*/
1851+UNIV_INTERN
1852+int
1853+row_delete_stats_for_mysql(
1854+/*=======================*/
1855+ dict_index_t* index,
1856+ trx_t* trx);
b4e1fa2c
AM
1857+/*********************************************************************//**
1858 Scans a table create SQL string and adds to the data dictionary
1859 the foreign key constraints declared in the string. This function
1860 should be called after the indexes for a table have been created.
db82db79
AM
1861--- a/storage/innobase/include/srv0srv.h
1862+++ b/storage/innobase/include/srv0srv.h
734d6226 1863@@ -216,6 +216,9 @@
b4e1fa2c
AM
1864 extern ibool srv_innodb_status;
1865
1866 extern unsigned long long srv_stats_sample_pages;
b4e1fa2c
AM
1867+extern ulint srv_stats_auto_update;
1868+extern ulint srv_stats_update_need_lock;
1869+extern ibool srv_use_sys_stats_table;
1870
1871 extern ibool srv_use_doublewrite_buf;
1872 extern ibool srv_use_checksums;
db82db79
AM
1873--- a/storage/innobase/que/que0que.c
1874+++ b/storage/innobase/que/que0que.c
b4e1fa2c
AM
1875@@ -621,11 +621,21 @@
1876
1877 que_graph_free_recursive(cre_ind->ind_def);
1878 que_graph_free_recursive(cre_ind->field_def);
1879+ if (srv_use_sys_stats_table)
1880+ que_graph_free_recursive(cre_ind->stats_def);
1881 que_graph_free_recursive(cre_ind->commit_node);
1882
1883 mem_heap_free(cre_ind->heap);
1884
1885 break;
1886+ case QUE_NODE_INSERT_STATS:
1887+ cre_ind = node;
1888+
1889+ que_graph_free_recursive(cre_ind->stats_def);
1890+ que_graph_free_recursive(cre_ind->commit_node);
1891+
1892+ mem_heap_free(cre_ind->heap);
1893+ break;
1894 case QUE_NODE_PROC:
1895 que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
1896
1897@@ -1138,6 +1148,8 @@
1898 str = "CREATE TABLE";
1899 } else if (type == QUE_NODE_CREATE_INDEX) {
1900 str = "CREATE INDEX";
1901+ } else if (type == QUE_NODE_INSERT_STATS) {
1902+ str = "INSERT TO SYS_STATS";
1903 } else if (type == QUE_NODE_FOR) {
1904 str = "FOR LOOP";
1905 } else if (type == QUE_NODE_RETURN) {
1906@@ -1255,6 +1267,8 @@
1907 thr = dict_create_table_step(thr);
1908 } else if (type == QUE_NODE_CREATE_INDEX) {
1909 thr = dict_create_index_step(thr);
1910+ } else if (type == QUE_NODE_INSERT_STATS) {
1911+ thr = dict_insert_stats_step(thr);
1912 } else if (type == QUE_NODE_ROW_PRINTF) {
1913 thr = row_printf_step(thr);
1914 } else {
db82db79
AM
1915--- a/storage/innobase/row/row0ins.c
1916+++ b/storage/innobase/row/row0ins.c
13ceb006 1917@@ -2018,6 +2018,8 @@
11822e22
AM
1918 }
1919
1920 #ifdef UNIV_DEBUG
1921+ if (!srv_use_sys_stats_table
1922+ || index != UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes))
1923 {
1924 page_t* page = btr_cur_get_page(&cursor);
1925 rec_t* first_rec = page_rec_get_next(
db82db79
AM
1926--- a/storage/innobase/row/row0merge.c
1927+++ b/storage/innobase/row/row0merge.c
adf0fb13 1928@@ -2019,6 +2019,8 @@
b4e1fa2c
AM
1929 "UPDATE SYS_INDEXES SET NAME=CONCAT('"
1930 TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n"
1931 "COMMIT WORK;\n"
1932+ /* Drop the statistics of the index. */
1933+ "DELETE FROM SYS_STATS WHERE INDEX_ID = :indexid;\n"
1934 /* Drop the field definitions of the index. */
1935 "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
1936 /* Drop the index definition and the B-tree. */
db82db79
AM
1937--- a/storage/innobase/row/row0mysql.c
1938+++ b/storage/innobase/row/row0mysql.c
734d6226 1939@@ -922,6 +922,9 @@
b4e1fa2c
AM
1940
1941 table->stat_modified_counter = counter + 1;
1942
1943+ if (!srv_stats_auto_update)
1944+ return;
1945+
1946 /* Calculate new statistics if 1 / 16 of table has been modified
1947 since the last time a statistics batch was run, or if
1948 stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
734d6226 1949@@ -932,7 +935,7 @@
b4e1fa2c
AM
1950 || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
1951
1952 dict_update_statistics(table, FALSE /* update even if stats
1953- are initialized */);
1954+ are initialized */, TRUE);
1955 }
1956 }
1957
734d6226 1958@@ -2077,6 +2080,71 @@
b4e1fa2c
AM
1959 }
1960
1961 /*********************************************************************//**
1962+*/
1963+UNIV_INTERN
1964+int
1965+row_insert_stats_for_mysql(
1966+/*=======================*/
1967+ dict_index_t* index,
1968+ trx_t* trx)
1969+{
1970+ ind_node_t* node;
1971+ mem_heap_t* heap;
1972+ que_thr_t* thr;
1973+ ulint err;
1974+
adf0fb13 1975+ //ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
b4e1fa2c
AM
1976+
1977+ trx->op_info = "try to insert rows to SYS_STATS";
1978+
1979+ trx_start_if_not_started(trx);
1980+ trx->error_state = DB_SUCCESS;
1981+
1982+ heap = mem_heap_create(512);
1983+
1984+ node = ind_insert_stats_graph_create(index, heap);
1985+
1986+ thr = pars_complete_graph_for_exec(node, trx, heap);
1987+
1988+ ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
1989+ que_run_threads(thr);
1990+
1991+ err = trx->error_state;
1992+
1993+ que_graph_free((que_t*) que_node_get_parent(thr));
1994+
1995+ trx->op_info = "";
1996+
1997+ return((int) err);
1998+}
1999+
11822e22
AM
2000+/*********************************************************************//**
2001+*/
2002+UNIV_INTERN
2003+int
2004+row_delete_stats_for_mysql(
2005+/*=============================*/
2006+ dict_index_t* index,
2007+ trx_t* trx)
2008+{
2009+ pars_info_t* info = pars_info_create();
2010+
2011+ trx->op_info = "delete rows from SYS_STATS";
2012+
2013+ trx_start_if_not_started(trx);
2014+ trx->error_state = DB_SUCCESS;
2015+
2016+ pars_info_add_ull_literal(info, "indexid", index->id);
2017+
2018+ return((int) que_eval_sql(info,
2019+ "PROCEDURE DELETE_STATISTICS_PROC () IS\n"
2020+ "BEGIN\n"
2021+ "DELETE FROM SYS_STATS WHERE INDEX_ID = :indexid;\n"
2022+ "END;\n"
2023+ , TRUE, trx));
2024+}
2025+
b4e1fa2c
AM
2026+/*********************************************************************//**
2027 Scans a table create SQL string and adds to the data dictionary
2028 the foreign key constraints declared in the string. This function
2029 should be called after the indexes for a table have been created.
734d6226 2030@@ -3001,7 +3069,7 @@
b4e1fa2c
AM
2031 dict_table_autoinc_initialize(table, 1);
2032 dict_table_autoinc_unlock(table);
2033 dict_update_statistics(table, FALSE /* update even if stats are
2034- initialized */);
2035+ initialized */, TRUE);
2036
2037 trx_commit_for_mysql(trx);
2038
734d6226 2039@@ -3312,6 +3380,8 @@
b4e1fa2c
AM
2040 " IF (SQL % NOTFOUND) THEN\n"
2041 " found := 0;\n"
2042 " ELSE\n"
2043+ " DELETE FROM SYS_STATS\n"
2044+ " WHERE INDEX_ID = index_id;\n"
2045 " DELETE FROM SYS_FIELDS\n"
2046 " WHERE INDEX_ID = index_id;\n"
2047 " DELETE FROM SYS_INDEXES\n"
db82db79
AM
2048--- a/storage/innobase/row/row0row.c
2049+++ b/storage/innobase/row/row0row.c
734d6226 2050@@ -364,6 +364,14 @@
11822e22
AM
2051
2052 rec_len = rec_offs_n_fields(offsets);
2053
2054+ if (srv_use_sys_stats_table
2055+ && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)) {
2056+ if (rec_len < dict_index_get_n_fields(index)) {
2057+ /* the new record should be extended */
2058+ rec_len = dict_index_get_n_fields(index);
2059+ }
2060+ }
2061+
2062 entry = dtuple_create(heap, rec_len);
2063
2064 dtuple_set_n_fields_cmp(entry,
734d6226 2065@@ -375,6 +383,14 @@
11822e22
AM
2066 for (i = 0; i < rec_len; i++) {
2067
2068 dfield = dtuple_get_nth_field(entry, i);
2069+
2070+ if (srv_use_sys_stats_table
2071+ && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
2072+ && i >= rec_offs_n_fields(offsets)) {
2073+ dfield_set_null(dfield);
2074+ continue;
2075+ }
2076+
2077 field = rec_get_nth_field(rec, offsets, i, &len);
2078
2079 dfield_set_data(dfield, field, len);
db82db79
AM
2080--- a/storage/innobase/row/row0upd.c
2081+++ b/storage/innobase/row/row0upd.c
11822e22
AM
2082@@ -439,6 +439,12 @@
2083 0);
2084 }
2085
2086+ if (srv_use_sys_stats_table
2087+ && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
2088+ && upd_field->field_no >= rec_offs_n_fields(offsets)) {
2089+ return(TRUE);
2090+ }
2091+
2092 old_len = rec_offs_nth_size(offsets, upd_field->field_no);
2093
2094 if (rec_offs_comp(offsets)
2095@@ -879,6 +885,18 @@
2096
2097 for (i = 0; i < dtuple_get_n_fields(entry); i++) {
2098
2099+ if (srv_use_sys_stats_table
2100+ && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
2101+ && i >= rec_offs_n_fields(offsets)) {
2102+ dfield = dtuple_get_nth_field(entry, i);
2103+
2104+ upd_field = upd_get_nth_field(update, n_diff);
2105+ dfield_copy(&(upd_field->new_val), dfield);
2106+ upd_field_set_field_no(upd_field, i, index, trx);
2107+ n_diff++;
2108+ goto skip_compare;
2109+ }
2110+
2111 data = rec_get_nth_field(rec, offsets, i, &len);
2112
2113 dfield = dtuple_get_nth_field(entry, i);
db82db79
AM
2114--- a/storage/innobase/srv/srv0srv.c
2115+++ b/storage/innobase/srv/srv0srv.c
734d6226 2116@@ -400,6 +400,9 @@
b4e1fa2c
AM
2117 /* When estimating number of different key values in an index, sample
2118 this many index pages */
2119 UNIV_INTERN unsigned long long srv_stats_sample_pages = 8;
b4e1fa2c
AM
2120+UNIV_INTERN ulint srv_stats_auto_update = 1;
2121+UNIV_INTERN ulint srv_stats_update_need_lock = 1;
2122+UNIV_INTERN ibool srv_use_sys_stats_table = FALSE;
2123
2124 UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE;
2125 UNIV_INTERN ibool srv_use_checksums = TRUE;
db82db79
AM
2126--- a/storage/innobase/trx/trx0rec.c
2127+++ b/storage/innobase/trx/trx0rec.c
734d6226 2128@@ -669,14 +669,27 @@
11822e22
AM
2129 /* Save to the undo log the old values of the columns to be updated. */
2130
2131 if (update) {
2132+ ulint extended = 0;
734d6226 2133+
11822e22
AM
2134 if (trx_undo_left(undo_page, ptr) < 5) {
2135
2136 return(0);
2137 }
2138
2139- ptr += mach_write_compressed(ptr, upd_get_n_fields(update));
2140+ if (srv_use_sys_stats_table
2141+ && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)) {
2142+ for (i = 0; i < upd_get_n_fields(update); i++) {
2143+ ulint pos = upd_get_nth_field(update, i)->field_no;
734d6226 2144+
11822e22
AM
2145+ if (pos >= rec_offs_n_fields(offsets)) {
2146+ extended++;
2147+ }
2148+ }
2149+ }
2150+
2151+ ptr += mach_write_compressed(ptr, upd_get_n_fields(update) - extended);
734d6226
AM
2152
2153- for (i = 0; i < upd_get_n_fields(update); i++) {
11822e22
AM
2154+ for (i = 0; i < upd_get_n_fields(update) - extended; i++) {
2155
2156 ulint pos = upd_get_nth_field(update, i)->field_no;
2157
13ceb006
AM
2158--- /dev/null
2159+++ b/mysql-test/r/percona_innodb_use_sys_stats_table.result
2160@@ -0,0 +1,3 @@
2161+show variables like 'innodb_use_sys_stats%';
2162+Variable_name Value
2163+innodb_use_sys_stats_table ON
2164--- /dev/null
2165+++ b/mysql-test/t/percona_innodb_use_sys_stats_table-master.opt
2166@@ -0,0 +1 @@
2167+--innodb_use_sys_stats_table
2168--- /dev/null
2169+++ b/mysql-test/t/percona_innodb_use_sys_stats_table.test
2170@@ -0,0 +1,2 @@
2171+--source include/have_innodb.inc
2172+show variables like 'innodb_use_sys_stats%';
This page took 0.323606 seconds and 4 git commands to generate.