]> git.pld-linux.org Git - packages/mysql.git/blame - innodb_stats.patch
- up to 5.5.31
[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) {
29ffd636
AM
281@@ -1177,6 +1316,66 @@
282 return(NULL);
283 }
b4e1fa2c 284
29ffd636
AM
285+ thr->run_node = que_node_get_parent(node);
286+
287+ return(thr);
288+}
289+
290+/****************************************************************//**
b4e1fa2c
AM
291+*/
292+UNIV_INTERN
293+que_thr_t*
294+dict_insert_stats_step(
295+/*===================*/
296+ que_thr_t* thr) /*!< in: query thread */
297+{
298+ ind_node_t* node;
299+ ulint err = DB_ERROR;
300+ trx_t* trx;
301+
302+ ut_ad(thr);
303+
304+ trx = thr_get_trx(thr);
305+
306+ node = thr->run_node;
307+
308+ if (thr->prev_node == que_node_get_parent(node)) {
309+ node->state = INDEX_BUILD_STATS_COLS;
310+ }
311+
312+ if (node->state == INDEX_BUILD_STATS_COLS) {
313+ if (node->stats_no <= dict_index_get_n_unique(node->index)) {
314+
315+ err = dict_build_stats_def_step(node);
316+
317+ if (err != DB_SUCCESS) {
318+
319+ goto function_exit;
320+ }
321+
322+ node->stats_no++;
323+
324+ thr->run_node = node->stats_def;
325+
326+ return(thr);
327+ } else {
328+ node->state = INDEX_COMMIT_WORK;
329+ }
330+ }
331+
332+ if (node->state == INDEX_COMMIT_WORK) {
333+
334+ /* do not commit transaction here for now */
335+ }
336+
337+function_exit:
338+ trx->error_state = err;
339+
340+ if (err == DB_SUCCESS) {
341+ } else {
342+ return(NULL);
343+ }
344+
29ffd636
AM
345 thr->run_node = que_node_get_parent(node);
346
347 return(thr);
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);
29ffd636 359@@ -4354,6 +4354,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
29ffd636 655@@ -4361,10 +4650,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;
29ffd636 668@@ -4381,6 +4671,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
29ffd636 696@@ -4445,6 +4756,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[
29ffd636 708@@ -4462,6 +4778,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
29ffd636 787@@ -4539,7 +4927,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;
29ffd636 964@@ -6196,6 +6216,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;
29ffd636 976@@ -8149,11 +8174,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 }
29ffd636 1013@@ -8238,7 +8287,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
29ffd636 1022@@ -11511,6 +11560,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). "
29ffd636 1049@@ -11883,6 +11952,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),
29ffd636 1059@@ -11957,7 +12029,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.362574 seconds and 4 git commands to generate.