WL#6599: New Data Dictionary and I_S integration
Affects: Server-8.0
—
Status: Complete
Introduction:
-------------
The INFORMATION_SCHEMA tables on 5.7 are temporary tables that
are created and filled during execution of the query. The
meta-data is read from .FRM files, storage engines and server in
memory data structures. Reading data from .FRM files involves
preparation of TABLE_SHARE object for each and every table and
this is time consuming.
With the introduction of data dictionary in 8.0, most of
INFORMATION_SCHEMA tables meta-data can be read from data
dictionary tables. The goal of this WL is,
1. To re-implement the possible INFORMATION_SCHEMA tables to pick
meta-data from data-dictionary tables and avoid creation of
temporary tables and preparation of TABLE_SHARE object upon every
query execution that contains INFORMATION_SCHEMA table.
2. The implementation would also provide following modes,
2.1 Support retrieval of dynamic table or index statistics from a
new DD table where the statistics are already stored. The DD table
would be updated using ANALYZE TABLE command. This allows a
INFORMATION_SCHEMA system view to present the dynamic statistics to
the users faster. It is understood that the statistics presented
this way would be from the time when user ran ANALYZE TABLE and are
not latest statistics.
2.2 Support retrieval of dynamic table or index statistics from
storage engine. This allows a INFORMATION_SCHEMA system view to
present latest dynamic statistics to the users. The design would
also involve developing customer storage engine API's that would
help get the latest table statistics without running open_table()
on a given table.
2.3 Provide support for user to switch between behaviour 2.1 and
2.2 based on a session variable.
3. With the re-implementation of several INFORMATION_SCHEMA
tables, there will be compatibility issues. We must try to
support the current behaviour as much of possible. However few
specific cases are,
- The current behavior is that the order of row's returned from
I_S query is fixed as of now. After this WL implementation the
rows returned from every execution of INFORMATION_SCHEMA system
view might depend on optimizer decisions and hence the order might
change.
- On 5.7, I_S tables are temporary tables and then the 'CREATE
TABLE LIKE' and 'HANDLER COLUMNS OPEN' command would work on I_S
tables. On 8.0, few I_S tables are system views and these two
command expect the input to be a BASE table and not a view. This
brings in a limitation.
- The --ignore-db-dir option was mostly added to avoid SQL server
to read physical directories like lost+found. Now that 8.0 server
do not depend of file-system folder to find databases, this option
is removed.
- Upon execution of I_S system views, the resulting column names
are show in capital. This seems to be result of how views are
merged.
There could be other compatibility issues, that should be
investigated by the WL.
4. Discuss possible solution and outline a plan for implementation.
1) Definitions and Abbreviation:
--------------------------------
DD : Data Dictionary
I_S : INFORMATION_SCHEMA
System View : A MySQL view that represent a I_S table.
TS : Dynamic table statistics, like,
TABLE_ROWS
AVG_ROW_LENGTH
DATA_LENGTH
MAX_DATA_LENGTH
INDEX_LENGTH
DATA_FREE
AUTO_INCREMENT
CREATE_TIME
UPDATE_TIME
CHECK_TIME
IS : Dynamic Index statistics i.e., index CARDINALITY.
TS_DD : DD table mysql.table_stat to store table statistics
IS_DD : DD table mysql.index_stat to store index statistics
FDS : Fast Dynamic Table/Index Statistics, but not
latest. Statistics will be based on last
execution of ANALYZE TABLE command.
LDS : Latest Dynamic Table/Index Statistics read from
storage engine. This would be slower compare to
read LDS compared to FDS.
INTERNAL_UDF: User defined functions implemented to enable
reading SE statistics dynamically in LDS
configuration.
2) Functional requirements:
---------------------------
FR-01 Implement possible I_S tables as a System View over the DD
tables.
a) I_S tables that mostly fetch static meta-data.
I.e., it does not read TS/IS details.
CHARACTER_SETS
COLLATIONS
SCHEMATA
COLLATION_CHARACTER_SET_APPLICABILITY
COLUMNS
COLUMN_PRIVILEGES
KEY_COLUMN_USAGE
PARAMETERS
PARTITIONS
REFERENTIAL_CONSTRAINTS
EVENTS
ROUTINES
TABLESPACES
TABLE_CONSTRAINTS
TRIGGERS
VIEWS
KEY_COLUMN_USAGE
b) I_S tables that mostly read both static meta-data
and dynamic table statistics.
TABLES
STATISTICS
FILES
Note that the SHOW CREATE command on system view would now show
the system view definition.
FR-02 Implement possible SHOW commands to use new I_S system view
introduced by FR-01.
SHOW CHARSET
SHOW COLLATION
SHOW DATABASES
SHOW TABLES
SHOW TABLE STATUS
SHOW COLUMNS
SHOW KEYS/INDEXES
SHOW STATISTICS
DESCRIBE
FR-03 Introduce new TS_DD table to store dynamic table
statistics, to enable FDS retrieval from I_S system view.
FR-04 Introduce new IS_DD table to store dynamic index
statistics, to enable FDS retrieval from I_S system view.
FR-05 It must be possible for I_S system view to read dynamic
table statistics from storage engine enabling to read LDS.
FR-06 It must be possible for I_S system views to pick dynamic
table statistics from TS_DD and IS_DD tables providing
FDS.
FR-07 Enable MySQL users to pick either FDS or LDS based on a
session variable.
FR-08 Implement new INTERNAL_UDF's which would retrieve LDS
from storage engine. This would be used in new I_S system
view definition.
FR-09 Implement INTERNAL_UDF's to do quick retrieval of
TS/IS from storage engine by giving the table name. The mean
of 'quick' here is to read statistics quicker compared to
opening the underlying table using open_table() and then
reading the statistics. Designing a new UDF will help avoid
building complete TABLE_SHARE for a table.
Any new SE API's required to read quick TS/IS values would
be implemented as separate work.
FR-10 Store meta-data of I_S tables into DD during bootstrapping
itself. As this information never changes, we can stored
them once. This include I_S tables that are not system views too.
FR-11 Create I_S system views as part of bootstrapping
procedure.
FR-12 Introduce new DD columns enhancing DD table definitions
to store required information by I_S, Like
COLUMN_TYPE, DEFAULT_VALUE_UTF8, INDEX_ORDER, ROW_FORMAT.
FR-13 Implement SHOW command on temporary table to skip using
I_S system views and use the current approach of creating
temporary table and filling it during execution of query
itself. There are temporary tables created by CREATE
TEMPORARY TABLE command, whose metadata is not stored in DD
tables.
FR-14 Introduce new MySQL extension I_S.TABLES.LAST_ALTERED
column projecting the new information that is now
available in DD i.e, mysql.tables.last_altered. Possibly
we can enhance other I_S.* tables where data dictionary
tables now contain the last_altered information.
FR-15 Allow I_S system views to be executed without waiting for
concurrent writes to DD tables.
FR-16 Store mandatory plugin schema tables meta-data into DD
tables upon bootstrap.
FR-17 Store dynamic plugin schema tables meta-data into DD table
upon plugin install. And remove the same during plugin
uninstall.
FR-18 Enable use of I_S system view under locked table modes.
FR-19 Make SHOW commands to read view column meta-data.
FR-20 Enable users to provide information schema and system view
names in mix case letters and do not treat them as case
sensitive, this is required to match the old behavior.
The reason we need to handle this case is that the
TABLES.TABLE_NAME maps to DD table column mysql.tables.name with
the new implementation. Whose collation would make it
depend on l_c_t_n. However, in 5.7 this was fixed to utf8_general_ci
which enabled users to automatically do case insensitive
comparison. Requirement is to try and match the old behavior.
When user provide a I_S schema and table name, convert them
to lowercase when possible. For e.g., we could do this when table
name is added to open_table list by add_table_to_list(). This
enables use to support part of old behavior but not complete.
The restriction would be that I_S schema and table name
provide in WHERE clauses of SHOW and I_S query would be treated
with same collation requirements as that of mysql.tables.name.
FR-21 The 'System View' here is mostly treated by the MySQL server in
the same way as that of user tables, except that we handle them
in lock table mode a bit differently. See 2.1.11 for more info.
1. Architecture of I_S without DD:
==================================
I_S tables are implemented in MySQL as temporary tables which are created on
the fly during query execution. The existing architecture is that, this
temporary table is filled with required details read from,
1) FRM files.
2) Retrieved from SE, OR
3) SQL server global data structures.
1.1 The low level details of current implementation is as below:
----------------------------------------------------------------
ST_SCHEMA_TABLE structure represents I_S table and ST_FIELD_INFO
represents fields of I_S table. These two data structures are use
to create the temporary table for I_S. A array of ST_SCHEMA_TABLE
object is used to represent 31 information schema tables related
to SQL engine.
struct ST_SCHEMA_TABLE
{
const char* table_name;
ST_FIELD_INFO *fields_info;
// 1st level callback function
int (*fill_table) (THD *thd, TABLE_LIST *tables, Item *cond);
// 2nd level callback function
int (*process_table) (THD *thd, TABLE_LIST *tables,
TABLE *table,
bool res, LEX_STRING *db_name,
LEX_STRING *table_name);
...
}
struct ST_FIELD_INFO
{
const char* field_name;
uint field_length;
enum_field_types field_type;
int value;
uint field_flags;
...
}
1.1.1 )
'ST_SCHEMA_TABLE.fill_table' function pointer points to
callback function which fills records into the I_S temporary
table.
Below are some of the I_S tables and its corresponding callback
functions. There are mostly I_S tables that read the required
information from MySQL data structures.
-----------------------------------------------------
I_S TABLE | (*fill_table)()
------------------------------------------------------
CHARACTER_SETS | fill_schema_charsets
COLLATIONS | fill_schema_collation
ENGINES | fill_schema_engines
GLOBAL_STATUS | fill_status
GLOBAL_VARIABLES | fill_variables
OPEN_TABLES | fill_open_tables
OPTIMIZER_TRACE | fill_optimizer_trace_info
FILES | hton_fill_schema_table
COLUMN_PRIVILEGES | fill_schema_column_privileges
EVENTS | Events::fill_schema_events
-------------------------------------------------------
1.1.2 )
I_S tables which reads meta-data of database objects like
TABLES, TRIGGER, COLUMNS, VIEW uses callback function pointed to
by 'ST_SCHEMA_TABLE.process_table' to read meta-data from given
table.. As these I_S tables require list of all databases and
their tables list from which the details are extracted, the
function get_all_tables() is invoked at first.
Below are list of callback function which are responsible to
fill data into respective I_S tables.
------------------------------------------------------------------------
I_S TABLE |(*fill_table)()|(*process_table)()
------------------------------------------------------------------------
COLUMNS |get_all_tables |get_schema_column_record
KEY_COLUMN_USAGE |get_all_tables |get_schema_key_column_usage_record
PARTITIONS |get_all_tables |get_schema_partitions_record
REFERENTIAL_CONSTRAINTS|get_all_tables |get_referential_constraints_record
STATISTICS |get_all_tables |get_schema_stat_record
TABLES |get_all_tables |get_schema_tables_record
TABLE_CONSTRAINTS |get_all_tables |get_schema_constraints_record
TRIGGERS |get_all_tables |get_schema_triggers_record
VIEWS |get_all_tables |get_schema_views_record
------------------------------------------------------------------------
1.1.3 )
Pseudo code for get_all_tables() function
-----------------------------------------
// 2nd argument TABLE_LIST *tables represents temporary table 'T' created to
store resultset
for ('database' in databases_list) (directory scan on DATA_DIR + I_S)
{
for ('table' in tables_list of 'database') (directory scan on DATA_DIR/)
{
if ('table' is a I_S table)
- create temporary table 'TT' (creates .frm file for I_S)
- open table 'TT'
- Access meta-data using TABLE_SHARE,handler,handlerton,etc.
- call (*process_table)() to store meta-data into 'T'
- Present resulting rows to mysql client.
- close table 'TT'
- remove table 'TT' (removes .frm file)
else
- open table (open .frm file first time and then read from TABLE_CACHE)
- access meta info using TABLE_SHARE, handler, handlerton,etc of table
- call (*process_table)() to store meta-data into 'T'
- close table
endif
}
}
2. Architecture of I_S with DD:
===============================
2.1 Design Overview
-------------------
The approach of implementing new I_S table is to define I_S
system view over DD tables, representing a I_S table. This will
completely eliminate the need of preparing a temporary table for
each I_S table during execution and other costs that are
described in section 1) above. I_S query execution would work
same as executing a query on a view.
Following are the changes involved:
2.1.1 ) I_S tables that can be implemented as a System View (FR-01).
The names of new system views that are implemented are listed in FR-01.
Definition of each system view is listed in LLD.
2.1.2 ) I_S tables whose implementation remains the same.
ENGINES
GLOBAL_STATUS
GLOBAL_VARIABLES
OPTIMIZER_TRACE
PLUGINS
PROCESSLIST
PROFILING
OPEN_TABLES
SESSION_STATUS
SESSION_VARIABLES
SCHEMA_PRIVILEGES
TABLE_PRIVILEGES
COLUMN_PRIVILEGES
USER_PRIVILEGES
STATUS
2.1.3 ) List of commands that would be re-implemented to use new
I_S system views defined in 2.1.1. FR-02.
- We prepare a SELECT_LEX representing a SELECT query over I_S system view
by 'build_show_*()' function in sql/dd/show.cc. The approach is to prepare
a
Parse Tree node and let the executor execute it.
2.1.4 ) Implementation of FDS and LDS. (FR-03..09)
Following are the details of implementation to support
FDS and LDS configuration over I_S system views.
a) SQL server bootstrap will creates TS_DD and IS_DD
tables during DD initialization.
b) ANALYZE TABLE command updates TS_DD and IS_DD tables with
TS/IS meta-data read from SE. This will be picked by I_S tables
in FDS configuration.
c) There are two version of each I_S system view which read
TDS/IDS. This applies to I_S tables listed under 2.1.1 b)
c1) I_S system view definition that joins with TS_DD and
IS_DD to read FDS.
c2) I_S system view definition that invokes new
INTERNAL_UDF's to read LDS. These system view
definitions are suffixed with text '_dynamic' in there
view name.
d) SQL server would switch between c1) and c2) configuration
based on session variable 'information_schema_stats'.
This is implemented such that the 'add_table_to_list()' function
would rename the I_S system view name picking the one
required based on 'information_schema_stats' setting.
SQL server will use c1) behavior by default which
chooses the FDS configuration, that means that the
'information_schema_stats' is set to 'cached' by default.
E.g.,
We have I_S.TABLES system view representing c1) and
I_S.TABLES_DYNAMIC system view that represents c2) version.
Where a user executes a statement with I_S table name
e.g., 'SELECT * FROM INFORMATION_SCHEMA.TABLES', the parser
invokes 'add_table_to_list()' function. This function intern
checks if the 'information_schema_stats=latest', then replace
the I_S table name from INFORMATION_SCHEMA.TABLES to
INFORMATION_SCHEMA.TABLES_DYNAMIC. This same concept would be
applied to other I_S tables in 2.1.1 b)
Note that this behavior applies for SHOW commands implementation
which uses I_S tables.
2.1.5) I_S and concurrency (FR-15)
2.1.6) Allow view creation under bootstrapping (FR-11)
The new I_S system views should be created during
bootstrapping similar to the way DD tables are created. This
avoid possibility of SQL server picking wrong I_S system view
definition, accidentally modified by user OR due to user
using a old DB patch.
TODO: The upgrade needs to handle drop and re-create
the system views, mainly when upgrading from 8.0 to higher
versions.
2.1.7) Store meta-data of plugin schema tables. (FR-10,FR-16,FR-17)
FR-10
As described by Praba in 1.1.3 above, the 5.7 server would
end-up creating a temporary table to retrieve I_S table metad-data
and present that in output of I_S.TABLES. With FR-01
implemented we cannot do the same.
As the I_S tables schema does not change, we will store the
meta-data of I_S tables during server bootstrapping procedure.
FR-16:
The 5.7 server would request meta-data of I_S system tables
owned by storage engines upon execution of every I_S table listed
in 2.1.1 a) & b). With FR-01 implemented the I_S system views
cannot retrieve this meta-data from SE. I.e., 2.1.4 c1 and c2 would
be modeled to read rows from SE during execution, which is
not possible.
As the SE schema tables meta-data is pretty much fixed and
does not change, we would store such mandatory plugins schema
table meta-data into DD tables during bootstrapping. This would
save lot of time spent to read data from SE during execution.
FR-17 - TBD
Dynamic plugins can own schema tables. On 5.7 these tables
are requested by SQL server through SE API and the values are
filled in by SE engine itself.
With FR-01 implemented, a system view cannot read this
information from SE. Hence the plan is to store the Plugin's
schema table meta-data into DD table when the plugin is
installed. And we remove the same when plugin is un-installed.
2.1.8) Introducing new DD columns (FR-12)
On 5.7 server we read meta-data of table from TABLE_SHARE
prepared after opening the table. This TABLE_SHARE contains
information like below, which are mostly not persistent as is in
.FRM by are computed when the TABLE_SHARE is prepared. This
information was not available in DD tables readily.
So we added following new DD columns which are required by
I_S tables.
COLUMNS.COLUMN_KEY
COLUMNS.COLUMN_TYPE
COLUMNS.DEFAULT_VALUE_UTF8
TABLES.ROW_FORMAT
2.1.9) SHOW COLUMNS for temporary tables (FR-13)
SHOW COLUMNS command would pick data from I_S system view
after FR-01. This bring data from DD tables. However, the
meta-data of temporary tables is not stored/persistent in the DD
tables. So the meta-data of temporary table would not be seen by
I_S system view.
SHOW COLUMNS command on a temporary tables would skip using
the I_S system view and fall-back to the old model of creating a
temporary table and filling it with the data temporary table
meta-data from the SQL server memory data structures.
2.1.10) Introducing new I_S.TABLES.LAST_ALTERED field (FR-14)
There is a plan to introduce this new I_S column as a MySQL
extension.
2.1.11) I_S query execution under locked table mode: (FR-18)
I_S tables are temporary tables on 5.7. This make them
possible to access under LOCK TABLE command with explicitly
locking I_S tables. Now with FR-01 is implemented, the query
execution procedure fails to process I_S system view as the under
laying DD table are not locked.
The SQL server is made to open the DD tables used by a I_S
system view without requiring them to be locked explicitly.
2.1.12) Quick retrieval [Avoid open_table()] of latest statistics
using INTERNAL_UDF's (FR-08, FR-09)
When 'information_schema_stats=latest' the TS/IS
statistics are read from SE. The way we read these values on 5.7
is by opening the underlying table and reading handler->info()
values. If the UDF's in 8.0 does the same, the performance of I_S
query on 8.0 will not improvement and would remain same.
In effort to improve performance of I_S query with TS/IS
data, new SE API's are designed (see LLD section 2) to request
the TS/IS statistics based on the table name, without doing a
full blown table open.
These new SE API's are implemented by 'InnoDB' SE alone for
now. So, the INTERNAL_UDF's would use these new SE API's only for
'InnoDB' tables. For non-InnoDB tables, the INTERNAL_UDF's would
following the same procedure as that of 5.7 to open the table and
invoke handler->info() to read the TS/IS values.
3 Compatibility issues:
-----------------------
Please refer main.dd_is_compatibility for test cases for each of
below change in behavior.
a) Requires execution of ANALYZE TABLE in FDS mode. I.e.,
when 'information_schema_stats=cached'.
Steps:
1) start server.
2) create a table.
3) insert few rows.
4) read I_S.TABLES dynamic statistics.
If we carry on following steps on 5.7 server then we do get
TS/IS read from SE.
However on 8.0 server, step 4) would get NULL for all the
dynamic statistics. The reason is that the default configuration
of I_S system view is to pick the TS/IS values from TS_DD and
IS_DD tables, which is based on
'information_schema_stats=cached'. TS_DD/IS_DD tables
needs to be updated by a explicit ANALYZE TABLE command. Without
which the step 4) would result in NULL due to LEFT JOIN done
in system view definition with TS_DD/IS_DD.
The correct steps to get TS/IS on 8.0 would be:
Steps:
1) start server.
2) create a table.
3) insert few rows.
4) run ANALYZE TABLE of the table.
5) read I_S.TABLES dynamic statistics.
b) The DD tables are listed in I_S query output.
We will hide the DD table meta-data to be exposed by I_S queries.
c) Capital cased I_S table column names.
Upon execution of a I_S query, the resulting column names
were in lower case on 5.7. However, on 8.0 with I_S system views,
SQL server present the I_S table column name in capital letters.
This is because optimizer does view merging instead of temp table
algorithm, due to which the column names are changed to uppercase.
One workaround to get column name with desired (lower/upper) case,
is to use a alias for the projections from the query, e.g.,
SELECT table_name as 'table_name' FROM INFORMATION_SCHEMA.TABLES;
table_name
----------
t1
Whereas without the alias we get,
SELECT table_name FROM INFORMATION_SCHEMA.TABLES;
TABLE_NAME
----------
t1
d) The order of row returned I_S query.
On 5.7, the order of row returned by I_S query was predictable
upon multiple execution of same query. With FR-01 being
implemented, the problem is that the optimizer do not guaranty
the order of rows returned from the SELECT.
On 8.0, it is recommended to use ORDER BY clause on I_S query
to order the rows based on users desire.
e) CREATE_TIME stored in DD table.
On 5.7, the CREATE_TIME of a table is not preserved by SQL
server and it is requested to SE. Moreover, not all SE's do
return CREATE_TIME.
On 8.0, SQL server store the CREATE_TIME of table in
mysql.tables.create_time.
f) Removal of --ignore-db-dir option from server.
This option was mostly added to avoid SQL server to read
physical directories like lost+found. Now that 8.0 server do not
depend of file-system folder to find databases, this option is
removed.
g) 'CREATE TABLE LIKE ' and
'HANDLER COLUMNS OPEN on '
On 5.7, I_S tables are temporary tables and then the 'CREATE
TABLE LIKE' and 'HANDLER COLUMNS OPEN' command would work on I_S
tables.
On 8.0, few I_S tables are system views and these two
command expect the input to be a BASE table and not a view. This
brings in a limitation.
h) I_S schema name and the table name are treated as
case-sensitive based on l_c_t_n setting, especially when these
names are used in WHERE clause of SHOW commands. This is because
the TABLES.TABLE_NAME maps to mysql.tables.name, which works based
on l_c_t_n.
i) Refering the behavior in FR-20, the restriction would
be that I_S schema and table name provide in WHERE clauses
of SHOW and I_S query would be treated with same collation
requirements as that of mysql.tables.name.
j) Prepared statements of SHOW commands fail differently for e.g.
ER_BAD_DB_ERROR unknown schema, instead of ER_TOO_BIG_SELECT for
big SELECT's. This is consequence of we checking for existing
database first and then JOIN::optimize(). In 5.7 this was done in
the other way.
k) ANALYZE TABLE under innodb read only mode fails with
error/warning. This would be a restrictions with wl6599. It is
recommended to use 'information_schema_stats=latest' to get latest
statistics from IS queries in read only mode.
l) Most of the INFORMATION_SCHEMA table are re-implemented as view.
Current method of dumping INFORMATION_SCHEMA does not work
for views.
OTOH, INFORMATION_SCHEMA DB content dump is only used to reload the
data into another tables for analysis purpose. This feature is not the
core responsibility of mysqlpump tool. INFORMATION_SCHEMA DB
content can be dumped using other methods like SELECT INTO OUTFILE ...
for such purpose. Hence ignoring INFORMATION_SCHEMA DB dump from
mysqldump and mysqlpump tool.
m) MySQL 'DISABLE KEYS' functionality is only applicable to MyISAM
tables, but looks like its marked for InnoDB table too in trunk.
This problem is fixed now. It has been discussed with Martin Hansson
who worked on WL8697 which introduced invisible index. He agreed that
the behavior on trunk is bad and needed to be fixed. We have fixed
that now.
n) In the 5.7 code, value for IS_UPDATABLE column of view is evaluated based
on view is mergable or not and view has at least one fields which
can be updated. This value is stored in the schema table.
But there are many other factors to decide view is updatable or not.
In 5.7 code too, these factors are checked while creating or
altering view but this value is not used while filling schema table.
Due to which we were getting wrong IS_UDPATABLE for some views.
Now we get correct is_updatable value for views as we
read the value stored in dicationary tables while creating or altering
view.
o) Most of the INFORMATION_SCHEMA table are re-implemented as view as
this WL. Current method of dumping INFORMATION_SCHEMA does not work
for views.
OTOH, INFORMATION_SCHEMA DB content dump is only used to reload the data
into another tables for analysis purpose. This feature is not the
core responsibility of mysqlpump tool. INFORMATION_SCHEMA DB
content can be dumped using other methods like SELECT INTO OUTFILE ...
for such purpose. Hence ignoring INFORMATION_SCHEMA DB dump from
mysqldump and mysqlpump tool.
p) ANLYZE TABLE operation on non-transactional table was incompatible
with FLUSH TABLES WITH READ LOCK. ANLYZE TABLE operation
used to wait for GLOBAL READ LOCK before.
Now ANLYZE TABLE operations for transactional and non-transactional
tables, ignores GLOBAL READ LOCK. So analyze table operation
is compatible with FLUSH TABLES WITH READ LOCK now.
q) In the 5.7 code, operation on INFORMATION_SCHEMA tables
acquires MDL lock on the tables to open definitions from the
data dictionary while filling schema table. With system view
implementation, as the rows are fetched from the new data dictionary
tables, MDL lock on the database objects are not acquired.
This is true in most of the cases except when
"information_schema_stats=latest" and operation on INFORMATION_SCHMEA
table requires latest statstics values.
Only in this case MDL lock of type MDL_SHARED_HIGH_PRIO is acquired on
the database object for the explicit(operation) duration.
1 System view definitions implementing FR-01: (Mar 10 2016)
-----------------------------------------------------------
--
-- INFORMATION_SCHEMA.COLLATIONS
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW information_schema.collations
AS
SELECT col.name AS COLLATION_NAME,
cs.name AS CHARACTER_SET_NAME,
col.id AS ID,
IF(EXISTS(SELECT * FROM mysql.character_sets
WHERE mysql.character_sets.default_collation_id=
col.id),
'Yes','') AS IS_DEFAULT,
IF(col.is_compiled,'Yes','') AS IS_COMPILED,
col.sort_length AS SORTLEN
FROM mysql.collations col JOIN mysql.character_sets cs ON
col.character_set_id=cs.id;
--
-- INFORMATION_SCHEMA.CHARACTER_SETS
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW
information_schema.character_sets as
SELECT cs.name AS CHARACTER_SET_NAME,
col.name AS DEFAULT_COLLATE_NAME,
cs.comment AS DESCRIPTION,
cs.mb_max_length AS MAXLEN
FROM mysql.character_sets cs JOIN mysql.collations col ON
cs.default_collation_id = col.id;
--
-- INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITY
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW
information_schema.collation_character_set_applicability AS
SELECT col.name AS COLLATION_NAME,
cs.name AS CHARACTER_SET_NAME
FROM mysql.character_sets cs JOIN mysql.collations col ON cs.id =
col.character_set_id;
--
-- INFORMATION_SCHEMA.SCHEMATA
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW information_schema.schemata AS
SELECT cat.name AS CATALOG_NAME,
sch.name AS SCHEMA_NAME,
cs.name AS DEFAULT_CHARACTER_SET_NAME,
col.name AS DEFAULT_COLLATION_NAME,
NULL AS SQL_PATH
FROM mysql.schemata sch JOIN mysql.catalogs cat ON cat.id=sch.catalog_id
JOIN mysql.collations col ON sch.default_collation_id = col.id
JOIN mysql.character_sets cs ON col.character_set_id= cs.id
WHERE CAN_ACCESS_DATABASE(sch.name);
--
-- INFORMATION_SCHEMA.TABLES
--
-- There are two definitions of information_schema.tables.
-- 1. INFORMATION_SCHEMA.TABLES view which picks dynamic column
-- statistics from mysql.table_stats which gets populated when
-- we execute 'anaylze table' command.
--
-- 2. INFORMATION_SCHEMA.TABLES_DYNAMIC view which retrieves dynamic
-- column statistics using a internal UDF which opens the user
-- table and reads dynamic table statistics.
--
-- MySQL server uses definition 1) by default. The session variable
-- dynamic_information_schema_stats=true would enable use of definition 2).
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW information_schema.tables AS
SELECT cat.name AS TABLE_CATALOG,
sch.name AS TABLE_SCHEMA,
tbl.name AS TABLE_NAME,
tbl.type AS TABLE_TYPE,
IF(tbl.type = 'VIEW', NULL, tbl.engine) AS ENGINE,
IF(tbl.type = 'VIEW', NULL, 10 /* FRM_VER_TRUE_VARCHAR */) AS VERSION,
tbl.row_format AS ROW_FORMAT,
stat.table_rows AS TABLE_ROWS,
stat.avg_row_length AS AVG_ROW_LENGTH,
stat.data_length AS DATA_LENGTH,
stat.max_data_length AS MAX_DATA_LENGTH,
stat.index_length AS INDEX_LENGTH,
stat.data_free AS DATA_FREE,
stat.auto_increment AS AUTO_INCREMENT,
tbl.created AS CREATE_TIME,
stat.update_time AS UPDATE_TIME,
stat.check_time AS CHECK_TIME,
col.name AS TABLE_COLLATION,
stat.checksum AS CHECKSUM,
IF (tbl.type = 'VIEW', NULL,
GET_DD_CREATE_OPTIONS(tbl.options,
IF(IFNULL(tbl.partition_expression,'NOT_PART_TBL')='NOT_PART_TBL', 0,
1)))
AS CREATE_OPTIONS,
IF (tbl.type = 'VIEW', 'VIEW', tbl.comment) AS TABLE_COMMENT
FROM mysql.tables tbl JOIN mysql.schemata sch ON tbl.schema_id=sch.id
JOIN mysql.catalogs cat ON cat.id=sch.catalog_id
LEFT JOIN mysql.collations col ON tbl.collation_id=col.id
LEFT JOIN mysql.table_stats stat ON tbl.name=stat.table_name
AND sch.name=stat.schema_name
WHERE CAN_ACCESS_TABLE(sch.name, tbl.name) AND NOT tbl.hidden;
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW
information_schema.tables_dynamic AS
SELECT cat.name AS TABLE_CATALOG,
sch.name AS TABLE_SCHEMA,
tbl.name AS TABLE_NAME,
tbl.type AS TABLE_TYPE,
IF(tbl.type = 'VIEW', NULL, tbl.engine) AS ENGINE,
IF(tbl.type = 'VIEW', NULL, 10 /* FRM_VER_TRUE_VARCHAR */) AS VERSION,
tbl.row_format AS ROW_FORMAT,
INTERNAL_TABLE_ROWS(sch.name, tbl.name,
IF(IFNULL(tbl.partition_type,'')='',tbl.engine,''),
tbl.se_private_id) AS TABLE_ROWS,
INTERNAL_AVG_ROW_LENGTH(sch.name, tbl.name,
IF(IFNULL(tbl.partition_type,'')='',tbl.engine,''),
tbl.se_private_id) AS AVG_ROW_LENGTH,
INTERNAL_DATA_LENGTH(sch.name, tbl.name,
IF(IFNULL(tbl.partition_type,'')='',tbl.engine,''),
tbl.se_private_id) AS DATA_LENGTH,
INTERNAL_MAX_DATA_LENGTH(sch.name, tbl.name,
IF(IFNULL(tbl.partition_type,'')='',tbl.engine,''),
tbl.se_private_id) AS MAX_DATA_LENGTH,
INTERNAL_INDEX_LENGTH(sch.name, tbl.name,
IF(IFNULL(tbl.partition_type,'')='',tbl.engine,''),
tbl.se_private_id) AS INDEX_LENGTH,
INTERNAL_DATA_FREE(sch.name, tbl.name,
IF(IFNULL(tbl.partition_type,'')='',tbl.engine,''),
tbl.se_private_id) AS DATA_FREE,
INTERNAL_AUTO_INCREMENT(sch.name, tbl.name,
IF(IFNULL(tbl.partition_type,'')='',tbl.engine,''),
tbl.se_private_id) AS AUTO_INCREMENT,
tbl.created AS CREATE_TIME,
INTERNAL_UPDATE_TIME(sch.name, tbl.name,
IF(IFNULL(tbl.partition_type,'')='',tbl.engine,''),
tbl.se_private_id) AS UPDATE_TIME,
INTERNAL_CHECK_TIME(sch.name, tbl.name,
IF(IFNULL(tbl.partition_type,'')='',tbl.engine,''),
tbl.se_private_id) AS CHECK_TIME,
col.name AS TABLE_COLLATION,
INTERNAL_CHECKSUM(sch.name, tbl.name,
IF(IFNULL(tbl.partition_type,'')='',tbl.engine,''),
tbl.se_private_id) AS CHECKSUM,
IF (tbl.type = 'VIEW', NULL,
GET_DD_CREATE_OPTIONS(tbl.options,
IF(IFNULL(tbl.partition_expression,'NOT_PART_TBL')='NOT_PART_TBL', 0,
1)))
AS CREATE_OPTIONS,
IF (tbl.type = 'VIEW', 'VIEW',
INTERNAL_GET_COMMENT_OR_ERROR(tbl.comment)) AS TABLE_COMMENT
FROM mysql.tables tbl JOIN mysql.schemata sch ON tbl.schema_id=sch.id
JOIN mysql.catalogs cat ON cat.id=sch.catalog_id
LEFT JOIN mysql.collations col ON tbl.collation_id=col.id
WHERE CAN_ACCESS_TABLE(sch.name, tbl.name) AND NOT tbl.hidden;
--
-- INFORMATION_SCHEMA.COLUMNS
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW information_schema.columns AS
SELECT
cat.name AS TABLE_CATALOG,
sch.name AS TABLE_SCHEMA,
tbl.name AS TABLE_NAME,
col.name AS COLUMN_NAME,
col.ordinal_position AS ORDINAL_POSITION,
IFNULL (col.default_value_utf8, '') AS COLUMN_DEFAULT,
IF (col.is_nullable = 1, 'YES','NO') AS IS_NULLABLE,
SUBSTRING_INDEX(SUBSTRING_INDEX(col.column_type_utf8, '(', 1), ' ', 1) AS
DATA_TYPE,
INTERNAL_DD_CHAR_LENGTH(col.type, col.char_length, coll.name, 0) AS
CHARACTER_MAXIMUM_LENGTH,
INTERNAL_DD_CHAR_LENGTH(col.type, col.char_length, coll.name, 1) AS
CHARACTER_OCTET_LENGTH,
IF (col.numeric_precision = 0, NULL, col.numeric_precision) AS
NUMERIC_PRECISION,
IF (col.numeric_scale = 0 && col.numeric_precision = 0, NULL,
col.numeric_scale) AS NUMERIC_SCALE,
col.datetime_precision AS DATETIME_PRECISION,
CASE col.type
WHEN 'MYSQL_TYPE_STRING' THEN (IF (cs.name='binary',NULL, cs.name))
WHEN 'MYSQL_TYPE_VAR_STRING' THEN (IF (cs.name='binary',NULL, cs.name))
WHEN 'MYSQL_TYPE_VARCHAR' THEN (IF (cs.name='binary',NULL, cs.name))
WHEN 'MYSQL_TYPE_TINY_BLOB' THEN (IF (cs.name='binary',NULL, cs.name))
WHEN 'MYSQL_TYPE_MEDIUM_BLOB' THEN (IF (cs.name='binary',NULL, cs.name))
WHEN 'MYSQL_TYPE_BLOB' THEN (IF (cs.name='binary',NULL, cs.name))
WHEN 'MYSQL_TYPE_LONG_BLOB' THEN (IF (cs.name='binary',NULL, cs.name))
WHEN 'MYSQL_TYPE_ENUM' THEN (IF (cs.name='binary',NULL, cs.name))
WHEN 'MYSQL_TYPE_SET' THEN (IF (cs.name='binary',NULL, cs.name))
ELSE NULL
END AS CHARACTER_SET_NAME,
CASE col.type
WHEN 'MYSQL_TYPE_STRING' THEN (IF (cs.name='binary',NULL, coll.name))
WHEN 'MYSQL_TYPE_VAR_STRING' THEN (IF (cs.name='binary',NULL, coll.name))
WHEN 'MYSQL_TYPE_VARCHAR' THEN (IF (cs.name='binary',NULL, coll.name))
WHEN 'MYSQL_TYPE_TINY_BLOB' THEN (IF (cs.name='binary',NULL, coll.name))
WHEN 'MYSQL_TYPE_MEDIUM_BLOB' THEN (IF (cs.name='binary',NULL, coll.name))
WHEN 'MYSQL_TYPE_BLOB' THEN (IF (cs.name='binary',NULL, coll.name))
WHEN 'MYSQL_TYPE_LONG_BLOB' THEN (IF (cs.name='binary',NULL, coll.name))
WHEN 'MYSQL_TYPE_ENUM' THEN (IF (cs.name='binary',NULL, coll.name))
WHEN 'MYSQL_TYPE_SET' THEN (IF (cs.name='binary',NULL, coll.name))
ELSE NULL
END AS COLLATION_NAME,
col.column_type_utf8 AS COLUMN_TYPE,
col.column_key AS COLUMN_KEY,
IF(IFNULL(col.generation_expression_utf8,'IS_NOT_GC')='IS_NOT_GC',
IF (col.is_auto_increment=TRUE,
CONCAT(IFNULL(CONCAT("on update ", col.update_option, " "),''),
"auto_increment"),
IFNULL(CONCAT("on update ", col.update_option),'')),
IF(col.is_virtual, "VIRTUAL GENERATED", "STORED GENERATED")) AS EXTRA,
GET_DD_COLUMN_PRIVILEGES(sch.name, tbl.name, col.name) AS `PRIVILEGES`,
IFNULL(col.comment, "") AS COLUMN_COMMENT,
IFNULL(col.generation_expression_utf8, "") AS GENERATION_EXPRESSION
FROM mysql.columns col JOIN mysql.tables tbl ON col.table_id=tbl.id
JOIN mysql.schemata sch ON tbl.schema_id=sch.id
JOIN mysql.catalogs cat ON cat.id=sch.catalog_id
JOIN mysql.collations coll ON col.collation_id=coll.id
JOIN mysql.character_sets cs ON coll.character_set_id= cs.id
WHERE CAN_ACCESS_COLUMN(sch.name, tbl.name, col.name) AND NOT tbl.hidden;
--
-- INFORMATION_SCHEMA.STATISTICS
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW
information_schema.statistics_base AS
(SELECT cat.name AS TABLE_CATALOG,
sch.name AS TABLE_SCHEMA,
tbl.name AS TABLE_NAME,
IF (idx.type = 'PRIMARY' OR idx.type = 'UNIQUE','0','1') AS NON_UNIQUE,
sch.name AS INDEX_SCHEMA,
idx.name AS INDEX_NAME,
icu.ordinal_position AS SEQ_IN_INDEX,
col.name AS COLUMN_NAME,
CASE WHEN icu.order = 'DESC' THEN 'D'
WHEN icu.order = 'ASC' THEN 'A'
ELSE NULL END AS COLLATION,
GET_DD_INDEX_SUB_PART_LENGTH(icu.length, col.type, col.char_length,
col.collation_id, idx.options) AS SUB_PART,
NULL AS PACKED,
if (col.is_nullable = 1, 'YES','') AS NULLABLE,
CASE WHEN idx.type = 'SPATIAL' THEN 'SPATIAL'
WHEN idx.algorithm = 'SE_PRIVATE' THEN ''
ELSE idx.algorithm END AS INDEX_TYPE,
IF (idx.type = 'PRIMARY' OR idx.type = 'UNIQUE',
'',IF(INTERNAL_KEYS_DISABLED(sch.name, tbl.name,
tbl.options),'disabled', ''))
AS COMMENT,
idx.comment AS INDEX_COMMENT,
IF (idx.is_visible, 'YES', 'NO') AS IS_VISIBLE,
idx.ordinal_position AS INDEX_ORDINAL_POSITION,
icu.ordinal_position AS COLUMN_ORDINAL_POSITION,
tbl.engine AS ENGINE,
tbl.se_private_id AS SE_PRIVATE_ID
FROM mysql.index_column_usage icu JOIN mysql.indexes idx ON
idx.id=icu.index_id
JOIN mysql.tables tbl ON idx.table_id=tbl.id
JOIN mysql.columns col ON icu.column_id=col.id
JOIN mysql.schemata sch ON tbl.schema_id=sch.id
JOIN mysql.catalogs cat ON cat.id=sch.catalog_id
JOIN mysql.collations coll ON tbl.collation_id=coll.id
WHERE CAN_ACCESS_TABLE(sch.name, tbl.name) AND NOT tbl.hidden);
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW information_schema.statistics
AS
(SELECT TABLE_CATALOG,
TABLE_SCHEMA,
sb.TABLE_NAME AS `TABLE_NAME`,
NON_UNIQUE,
INDEX_SCHEMA,
sb.INDEX_NAME AS `INDEX_NAME`,
SEQ_IN_INDEX,
sb.COLUMN_NAME AS `COLUMN_NAME`,
COLLATION,
stat.cardinality AS CARDINALITY,
SUB_PART,
PACKED,
NULLABLE,
INDEX_TYPE,
COMMENT,
INDEX_COMMENT,
IS_VISIBLE
FROM information_schema.statistics_base sb
LEFT JOIN mysql.index_stats stat
ON sb.table_name=stat.table_name
and sb.table_schema=stat.schema_name
and sb.index_name=stat.index_name
and sb.column_name=stat.column_name);
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW
information_schema.statistics_dynamic AS
(SELECT TABLE_CATALOG,
TABLE_SCHEMA,
TABLE_NAME,
NON_UNIQUE,
INDEX_SCHEMA,
INDEX_NAME,
SEQ_IN_INDEX,
COLUMN_NAME,
COLLATION,
INTERNAL_INDEX_COLUMN_CARDINALITY(TABLE_SCHEMA,TABLE_NAME, INDEX_NAME,
INDEX_ORDINAL_POSITION,
COLUMN_ORDINAL_POSITION,
ENGINE,
SE_PRIVATE_ID)
AS CARDINALITY,
SUB_PART,
PACKED,
NULLABLE,
INDEX_TYPE,
COMMENT,
INDEX_COMMENT,
IS_VISIBLE
FROM information_schema.statistics_base);
--
-- INFORMATION_SCHEMA.TABLE_CONSTRAINTS
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW
information_schema.table_constraints AS
(SELECT cat.name AS CONSTRAINT_CATALOG,
sch.name AS CONSTRAINT_SCHEMA,
CONVERT(idx.name USING utf8) AS CONSTRAINT_NAME,
sch.name AS TABLE_SCHEMA,
tbl.name AS TABLE_NAME,
IF (idx.type='PRIMARY', 'PRIMARY KEY', idx.type) AS CONSTRAINT_TYPE
FROM mysql.indexes idx JOIN mysql.tables tbl ON idx.table_id = tbl.id
JOIN mysql.schemata sch ON tbl.schema_id= sch.id
JOIN mysql.catalogs cat ON cat.id=sch.catalog_id
AND idx.type IN ('PRIMARY', 'UNIQUE')
WHERE CAN_ACCESS_TABLE(sch.name, tbl.name) AND NOT tbl.hidden)
UNION
(SELECT cat.name AS CONSTRAINT_CATALOG,
sch.name AS CONSTRAINT_SCHEMA,
CONVERT(fk.name USING utf8) AS CONSTRAINT_NAME,
sch.name AS TABLE_SCHEMA,
tbl.name AS TABLE_NAME,
'Foreign Key' AS CONSTRAINT_TYPE
FROM mysql.foreign_keys fk JOIN mysql.tables tbl ON fk.table_id = tbl.id
JOIN mysql.schemata sch ON fk.schema_id= sch.id
JOIN mysql.catalogs cat ON cat.id=sch.catalog_id
WHERE CAN_ACCESS_TABLE(sch.name, tbl.name) AND NOT tbl.hidden);
--
-- INFORMATION_SCHEMA.KEY_COLUMN_USAGE
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW
information_schema.key_column_usage AS
(SELECT cat.name AS CONSTRAINT_CATALOG,
sch.name AS CONSTRAINT_SCHEMA,
CONVERT(idx.name USING utf8) AS CONSTRAINT_NAME,
cat.name AS TABLE_CATALOG,
sch.name AS TABLE_SCHEMA,
tbl.name AS TABLE_NAME,
col.name AS COLUMN_NAME,
icu.ordinal_position AS ORDINAL_POSITION,
NULL AS POSITION_IN_UNIQUE_CONSTRAINT,
NULL AS REFERENCED_TABLE_SCHEMA,
NULL AS REFERENCED_TABLE_NAME,
NULL AS REFERENCED_COLUMN_NAME
FROM mysql.indexes idx JOIN mysql.tables tbl ON idx.table_id = tbl.id
JOIN mysql.schemata sch ON tbl.schema_id= sch.id
JOIN mysql.catalogs cat ON cat.id=sch.catalog_id
JOIN mysql.index_column_usage icu ON icu.index_id=idx.id
JOIN mysql.columns col ON icu.column_id=col.id
WHERE CAN_ACCESS_TABLE(sch.name, tbl.name) AND NOT tbl.hidden)
UNION
(SELECT cat.name AS CONSTRAINT_CATALOG,
sch.name AS CONSTRAINT_SCHEMA,
CONVERT(fk.name USING utf8) AS CONSTRAINT_NAME,
cat.name AS TABLE_CATALOG,
sch.name AS TABLE_SCHEMA,
tbl.name AS TABLE_NAME,
col.name AS COLUMN_NAME,
fkcu.ordinal_position AS ORDINAL_POSITION,
icu.ordinal_position AS POSITION_IN_UNIQUE_CONSTRAINT,
fk.referenced_table_schema AS REFERENCED_TABLE_SCHEMA,
fk.referenced_table_name AS REFERENCED_TABLE_NAME,
fkcu.referenced_column_name AS REFERENCED_COLUMN_NAME
FROM mysql.foreign_keys fk JOIN mysql.tables tbl ON fk.table_id = tbl.id
JOIN mysql.foreign_key_column_usage fkcu ON fkcu.foreign_key_id=fk.id
JOIN mysql.schemata sch ON fk.schema_id= sch.id
JOIN mysql.catalogs cat ON cat.id=sch.catalog_id
JOIN mysql.columns col ON fkcu.column_id=col.id
JOIN mysql.indexes idx ON fk.unique_constraint_id=idx.id
JOIN mysql.index_column_usage icu ON idx.id=icu.index_id
WHERE CAN_ACCESS_TABLE(sch.name, tbl.name) AND NOT tbl.hidden);
--
-- INFORMATION_SCHEMA.VIEWS
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW information_schema.views AS
SELECT cat.name AS TABLE_CATALOG,
sch.name AS TABLE_SCHEMA,
vw.name AS TABLE_NAME,
vw.view_definition_utf8 AS VIEW_DEFINITION,
vw.view_check_option AS CHECK_OPTION,
vw.view_is_updatable AS IS_UPDATABLE,
vw.view_definer AS DEFINER,
IF (vw.view_security_type = 'DEFAULT', 'DEFINER', vw.view_security_type)
AS SECURITY_TYPE,
(SELECT cs.name
FROM mysql.collations coll JOIN mysql.character_sets cs
ON coll.character_set_id= cs.id
WHERE coll.id=vw.view_client_collation_id) AS CHARACTER_SET_CLIENT,
(SELECT coll.name
FROM mysql.collations coll
WHERE coll.id=vw.view_connection_collation_id) AS COLLATION_CONNECTION
FROM mysql.tables vw JOIN mysql.schemata sch ON vw.schema_id=sch.id
JOIN mysql.catalogs cat ON cat.id=sch.catalog_id
WHERE vw.type = 'VIEW' AND CAN_ACCESS_TABLE(sch.name, vw.name);
--
-- INFORMATION SCHEMA VIEWS implementing SHOW statements
--
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW
information_schema.show_statistics AS
(SELECT
TABLE_SCHEMA as `Database`,
sb.TABLE_NAME AS `Table`,
NON_UNIQUE AS `Non_unique`,
sb.INDEX_NAME AS `Key_name`,
SEQ_IN_INDEX AS `Seq_in_index`,
sb.COLUMN_NAME AS `Column_name`,
COLLATION AS `Collation`,
stat.cardinality AS `Cardinality`,
SUB_PART AS `Sub_part`,
PACKED AS `Packed`,
NULLABLE AS `Null`,
INDEX_TYPE AS `Index_type`,
COMMENT AS `Comment`,
INDEX_COMMENT AS `Index_comment`,
IS_VISIBLE AS `Visible`,
INDEX_ORDINAL_POSITION,
COLUMN_ORDINAL_POSITION
FROM information_schema.statistics_base sb
LEFT JOIN mysql.index_stats stat
ON sb.table_name=stat.table_name
and sb.table_schema=stat.schema_name
and sb.index_name=stat.index_name
and sb.column_name=stat.column_name);
CREATE OR REPLACE DEFINER=`root`@`localhost` VIEW
information_schema.show_statistics_dynamic AS
(SELECT
TABLE_SCHEMA as `Database`,
TABLE_NAME AS `Table`,
NON_UNIQUE AS `Non_unique`,
INDEX_NAME AS `Key_name`,
SEQ_IN_INDEX AS `Seq_in_index`,
COLUMN_NAME AS `Column_name`,
COLLATION AS `Collation`,
INTERNAL_INDEX_COLUMN_CARDINALITY(TABLE_SCHEMA, TABLE_NAME, INDEX_NAME,
INDEX_ORDINAL_POSITION,
COLUMN_ORDINAL_POSITION,
ENGINE,
SE_PRIVATE_ID)
AS `Cardinality`,
SUB_PART AS `Sub_part`,
PACKED AS `Packed`,
NULLABLE AS `Null`,
INDEX_TYPE AS `Index_type`,
COMMENT AS `Comment`,
INDEX_COMMENT AS `Index_comment`,
IS_VISIBLE AS `Visible`,
INDEX_ORDINAL_POSITION,
COLUMN_ORDINAL_POSITION
FROM information_schema.statistics_base);
2. Definitions of new data dictionary tables added by this WL :
---------------------------------------------------------------
CREATE TABLE `table_stats` (
`schema_name` varchar(64) COLLATE utf8_bin NOT NULL,
`table_name` varchar(64) COLLATE utf8_bin NOT NULL,
`table_rows` bigint(20) unsigned DEFAULT NULL,
`avg_row_length` bigint(20) unsigned DEFAULT NULL,
`data_length` bigint(20) unsigned DEFAULT NULL,
`max_data_length` bigint(20) unsigned DEFAULT NULL,
`index_length` bigint(20) unsigned DEFAULT NULL,
`data_free` bigint(20) unsigned DEFAULT NULL,
`auto_increment` bigint(20) unsigned DEFAULT NULL,
`checksum` bigint(20) unsigned DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL,
`check_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`schema_name`,`table_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0;
CREATE TABLE `index_stats` (
`schema_name` varchar(64) COLLATE utf8_bin NOT NULL,
`table_name` varchar(64) COLLATE utf8_bin NOT NULL,
`index_name` varchar(64) COLLATE utf8_bin NOT NULL,
`column_name` varchar(64) COLLATE utf8_bin NOT NULL,
`cardinality` bigint(20) unsigned DEFAULT NULL,
UNIQUE KEY `schema_name`
(`schema_name`,`table_name`,`index_name`,`column_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0;
3. New SE API's introduced:
--------------------------
The following new handlerton API's are introduced to read the
table statistics from storage engine. This is currently implemented
only for 'InnoDB' engine.
/**
@brief
Retrieve ha_statistics from SE.
@param1 db_name Name of schema
@param2 table_name Name of table
@param3 se_private_id SE private id of the table.
@param4 flags Type of statistics to retrieve.
@param5 stats (OUT) Contains statistics read from SE.
@returns false on success,
true on failure
*/
bool (*get_table_statistics)(const char *db_name,
const char *table_name,
dd::Object_id se_private_id,
uint flags,
ha_statistics &stats);
/**
@brief
Retrieve index column cardinality from SE.
@param1 db_name Name of schema
@param2 table_name Name of table
@param3 index_name Name of index
@param4 index_ordinal_position Position of index.
@param5 column_ordinal_position Position of column in index.
@param6 se_private_id SE private id of the table.
@param7 cardinality (OUT) cardinality being returned by SE.
@returns false on success,
true on failure
*/
bool (*get_index_column_cardinality)(const char *db_name,
const char *table_name,
const char *index_name,
uint index_ordinal_position,
uint column_ordinal_position,
dd::Object_id se_private_id,
ulonglong *cardinality);
4. Change made in mysqlpump tool:
With the introduction of new information schema views on top
of new data dictionary, the way the SHOW command works is
changed. We now have two ways of SHOW command picking table
statistics.
One is to read it from DD table mysql.table_stats and
mysql.index_stats. For this to happen, we need to execute
ANALYZE TABLE prior to execution of mysqlpump tool. As the
tool can run on whole database, we would end-up running
ANALYZE TABLE for all tables in the database irrespective of
whether statistics are already present in the statictics
tables. This could be a time consuming additional step to
carry.
Second option is to read statistics from SE itself. This
options looks safe and execution of mysqlpump tool need not
care if ANALYZE TABLE command was run on every table. We
always get the statistics, which match the behavior without
data dictionary.
The first option would be faster as we do not opening the
underlying tables during execution of SHOW command. However
the first option might read old statistics, so we feel second
option is preferred here to get statistics dynamically from
SE by setting information_schema_stats=latest for this
session, which would match the old behavior in 5.7.
Copyright (c) 2000, 2025, Oracle Corporation and/or its affiliates. All rights reserved.