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