1 /*****************************************************************************
2 
3 Copyright (c) 2009, 2018, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License, version 2.0, as published by the
7 Free Software Foundation.
8 
9 This program is also distributed with certain software (including but not
10 limited to OpenSSL) that is licensed under separate terms, as designated in a
11 particular file or component or in included license documentation. The authors
12 of MySQL hereby grant you an additional permission to link the program and
13 your derivative works with the separately licensed software that they have
14 included with MySQL.
15 
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19 for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
24 
25 *****************************************************************************/
26 
27 /** @file include/dict0stats.h
28  Code used for calculating and manipulating table statistics.
29 
30  Created Jan 06, 2010 Vasil Dimov
31  *******************************************************/
32 
33 #ifndef dict0stats_h
34 #define dict0stats_h
35 
36 #include "univ.i"
37 
38 #include "dict0types.h"
39 #include "mem0mem.h"
40 #include "trx0types.h"
41 
42 enum dict_stats_upd_option_t {
43   DICT_STATS_RECALC_PERSISTENT, /* (re) calculate the
44                            statistics using a precise and slow
45                            algo and save them to the persistent
46                            storage, if the persistent storage is
47                            not present then emit a warning and
48                            fall back to transient stats */
49   DICT_STATS_RECALC_TRANSIENT,  /* (re) calculate the statistics
50                             using an imprecise quick algo
51                             without saving the results
52                             persistently */
53   DICT_STATS_EMPTY_TABLE,       /* Write all zeros (or 1 where it makes sense)
54                                 into a table and its indexes' statistics
55                                 members. The resulting stats correspond to an
56                                 empty table. If the table is using persistent
57                                 statistics, then they are saved on disk. */
58   DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY /* fetch the stats
59                           from the persistent storage if the in-memory
60                           structures have not been initialized yet,
61                           otherwise do nothing */
62 };
63 
64 /** Set the persistent statistics flag for a given table. This is set only in
65 the in-memory table object and is not saved on disk. It will be read from the
66 .frm file upon first open from MySQL after a server restart.
67 @param[in,out]	table	table
68 @param[in]	ps_on	persistent stats explicitly enabled
69 @param[in]	ps_off	persistent stats explicitly disabled */
70 UNIV_INLINE
71 void dict_stats_set_persistent(dict_table_t *table, ibool ps_on, ibool ps_off);
72 
73 /** Check whether persistent statistics is enabled for a given table.
74  @return true if enabled, false otherwise */
75 UNIV_INLINE
76 ibool dict_stats_is_persistent_enabled(
77     const dict_table_t *table) /*!< in: table */
78     MY_ATTRIBUTE((warn_unused_result));
79 
80 /** Set the auto recalc flag for a given table (only honored for a persistent
81 stats enabled table). The flag is set only in the in-memory table object and is
82 not saved in InnoDB files. It will be read from the .frm file upon first open
83 from MySQL after a server restart.
84 @param[in,out]	table		table
85 @param[in]	auto_recalc_on	explicitly enabled
86 @param[in]	auto_recalc_off	explicitly disabled */
87 UNIV_INLINE
88 void dict_stats_auto_recalc_set(dict_table_t *table, ibool auto_recalc_on,
89                                 ibool auto_recalc_off);
90 
91 /** Check whether auto recalc is enabled for a given table.
92  @return true if enabled, false otherwise */
93 UNIV_INLINE
94 ibool dict_stats_auto_recalc_is_enabled(
95     const dict_table_t *table); /*!< in: table */
96 
97 /** Initialize table's stats for the first time when opening a table. */
98 UNIV_INLINE
99 void dict_stats_init(dict_table_t *table); /*!< in/out: table */
100 
101 /** Deinitialize table's stats after the last close of the table. This is
102  used to detect "FLUSH TABLE" and refresh the stats upon next open. */
103 UNIV_INLINE
104 void dict_stats_deinit(dict_table_t *table); /*!< in/out: table */
105 
106 /** Calculates new estimates for table and index statistics. The statistics
107  are used in query optimization.
108  @return DB_* error code or DB_SUCCESS */
109 dberr_t dict_stats_update(dict_table_t *table, /*!< in/out: table */
110                           dict_stats_upd_option_t stats_upd_option);
111 /*!< in: whether to (re) calc
112 the stats or to fetch them from
113 the persistent storage */
114 
115 /** Removes the information for a particular index's stats from the persistent
116  storage if it exists and if there is data stored for this index.
117  This function creates its own trx and commits it.
118  @return DB_SUCCESS or error code */
119 dberr_t dict_stats_drop_index(
120     const char *tname, /*!< in: table name */
121     const char *iname, /*!< in: index name */
122     char *errstr,      /*!< out: error message if != DB_SUCCESS
123                        is returned */
124     ulint errstr_sz);  /*!< in: size of the errstr buffer */
125 
126 /** Removes the statistics for a table and all of its indexes from the
127  persistent storage if it exists and if there is data stored for the table.
128  This function creates its own transaction and commits it.
129  @return DB_SUCCESS or error code */
130 dberr_t dict_stats_drop_table(
131     const char *table_name, /*!< in: table name */
132     char *errstr,           /*!< out: error message
133                             if != DB_SUCCESS is returned */
134     ulint errstr_sz);       /*!< in: size of errstr buffer */
135 
136 /** Fetches or calculates new estimates for index statistics. */
137 void dict_stats_update_for_index(dict_index_t *index); /*!< in/out: index */
138 
139 /** Renames a table in InnoDB persistent stats storage.
140  This function creates its own transaction and commits it.
141  @return DB_SUCCESS or error code */
142 dberr_t dict_stats_rename_table(const char *old_name, /*!< in: old table name */
143                                 const char *new_name, /*!< in: new table name */
144                                 char *errstr,      /*!< out: error string if !=
145                                                    DB_SUCCESS      is returned */
146                                 size_t errstr_sz); /*!< in: errstr size */
147 
148 /** Renames an index in InnoDB persistent stats storage.
149  This function creates its own transaction and commits it.
150  @return DB_SUCCESS or error code. DB_STATS_DO_NOT_EXIST will be returned
151  if the persistent stats do not exist. */
152 dberr_t dict_stats_rename_index(
153     const dict_table_t *table,  /*!< in: table whose index
154                                 is renamed */
155     const char *old_index_name, /*!< in: old index name */
156     const char *new_index_name) /*!< in: new index name */
157     MY_ATTRIBUTE((warn_unused_result));
158 
159 /** Evict the stats tables if they loaded in tablespace cache and also
160 close the stats .ibd files. We have to close stats tables because
161 8.0 stats tables will use the same name. We load the stats from 5.7
162 with a suffix "_backup57" and migrate the statistics. */
163 void dict_stats_evict_tablespaces();
164 
165 /** Represent the record of innodb_table_stats table. */
166 class TableStatsRecord {
167  public:
168   /** Constructor. */
169   TableStatsRecord();
170 
171   /** Destructor. */
172   ~TableStatsRecord();
173 
174   /** Set the data for the innodb_table_stats record.
175   @param[in]	data		data to be set in the record
176   @param[in]	col_offset	column offset
177   @param[in]	len		length of the data. */
178   void set_data(const byte *data, ulint col_offset, ulint len);
179 
180   /** Get the table name from innodb_table_stats record.
181   @retval table name of the table_stats record. */
182   char *get_tbl_name() const;
183 
184   /** Set the table name for the innodb_table_stats record.
185   @param[in]	data	data to be set in the record
186   @param[in]	len	length of the data. */
187   void set_tbl_name(const byte *data, ulint len);
188 
189   /** Get the db name from the innodb_table_stats record.
190   @retval db name of the table stats record. */
191   char *get_db_name() const;
192 
193   /** Set the db name for the innodb_table_stats record.
194   @param[in]	data	data to be set
195   @param[in]	len	length of the data. */
196   void set_db_name(const byte *data, ulint len);
197 
198   /** Get the n_rows from the innodb_table_stats record.
199   @retval n_rows from the record. */
200   ib_uint64_t get_n_rows() const;
201 
202   /** Set the n_rows for the innodb_table_stats record.
203   @param[in]	no_of_rows	number of rows. */
204   void set_n_rows(ib_uint64_t no_of_rows);
205 
206   /** Get the clustered index size from
207   innodb_table_stats record.
208   @retval size of the clustered index. */
209   ulint get_clustered_index_size() const;
210 
211   /** Set the clustered index size for the
212   innodb_table_stats record.
213   @param[in]	clust_size	clustered index size. */
214   void set_clustered_index_size(ulint clust_size);
215 
216   /** Get the sum of other index size.
217   @retval sum of secondary index size. */
218   ulint get_sum_of_other_index_size() const;
219 
220   /** Set the sum of sec index size.
221   @param[in]	sum_of_other_index_size	sum of secondary index size. */
222   void set_sum_of_other_index_size(ulint sum_of_other_index_size);
223 
224   /** Column number of innodb_table_stats.database_name. */
225   static constexpr unsigned DB_NAME_COL_NO = 0;
226   /** Column number of innodb_table_stats.table_name. */
227   static constexpr unsigned TABLE_NAME_COL_NO = 1;
228   /** Column number of innodb_table_stats.n_rows. */
229   static constexpr unsigned N_ROWS_COL_NO = 3;
230   /** Column number of innodb_table_stats.clustered_index_size. */
231   static constexpr unsigned CLUST_INDEX_SIZE_COL_NO = 4;
232   /** Column number of innodb_table_stats.sum_of_other_index_sizes. */
233   static constexpr unsigned SUM_OF_OTHER_INDEX_SIZE_COL_NO = 5;
234 
235  private:
236   /** Database name. */
237   char *m_db_name;
238   /** Table name. */
239   char *m_tbl_name;
240   /** Number of rows. */
241   ib_uint64_t m_n_rows;
242   /** Clustered index size. */
243   ulint m_clustered_index_size;
244   /** Sum of other index size. */
245   ulint m_sum_of_other_index_sizes;
246   /** Heap to store db_name, tbl_name for the record. */
247   mem_heap_t *m_heap;
248 };
249 
250 /** Calculates new estimates for table and index statistics. This function
251  is relatively quick and is used to calculate transient statistics that
252  are not saved on disk.
253  This was the only way to calculate statistics before the
254  Persistent Statistics feature was introduced. */
255 void dict_stats_update_transient(dict_table_t *table); /*!< in/out: table */
256 
257 #include "dict0stats.ic"
258 
259 #ifdef UNIV_ENABLE_UNIT_TEST_DICT_STATS
260 void test_dict_stats_all();
261 #endif /* UNIV_ENABLE_UNIT_TEST_DICT_STATS */
262 
263 #endif /* dict0stats_h */
264