summaryrefslogtreecommitdiffstats
path: root/scripts/sys_schema/procedures
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:00:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:00:34 +0000
commit3f619478f796eddbba6e39502fe941b285dd97b1 (patch)
treee2c7b5777f728320e5b5542b6213fd3591ba51e2 /scripts/sys_schema/procedures
parentInitial commit. (diff)
downloadmariadb-3f619478f796eddbba6e39502fe941b285dd97b1.tar.xz
mariadb-3f619478f796eddbba6e39502fe941b285dd97b1.zip
Adding upstream version 1:10.11.6.upstream/1%10.11.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'scripts/sys_schema/procedures')
-rw-r--r--scripts/sys_schema/procedures/create_synonym_db.sql187
-rw-r--r--scripts/sys_schema/procedures/diagnostics.sql1064
-rw-r--r--scripts/sys_schema/procedures/execute_prepared_stmt.sql89
-rw-r--r--scripts/sys_schema/procedures/ps_setup_disable_background_threads.sql54
-rw-r--r--scripts/sys_schema/procedures/ps_setup_disable_consumer.sql70
-rw-r--r--scripts/sys_schema/procedures/ps_setup_disable_instrument.sql80
-rw-r--r--scripts/sys_schema/procedures/ps_setup_disable_thread.sql68
-rw-r--r--scripts/sys_schema/procedures/ps_setup_enable_background_threads.sql54
-rw-r--r--scripts/sys_schema/procedures/ps_setup_enable_consumer.sql74
-rw-r--r--scripts/sys_schema/procedures/ps_setup_enable_instrument.sql86
-rw-r--r--scripts/sys_schema/procedures/ps_setup_enable_thread.sql68
-rw-r--r--scripts/sys_schema/procedures/ps_setup_reload_saved.sql146
-rw-r--r--scripts/sys_schema/procedures/ps_setup_reset_to_default.sql148
-rw-r--r--scripts/sys_schema/procedures/ps_setup_reset_to_default_57.sql165
-rw-r--r--scripts/sys_schema/procedures/ps_setup_reset_to_default_57_after.sql16
-rw-r--r--scripts/sys_schema/procedures/ps_setup_reset_to_default_57_before.sql17
-rw-r--r--scripts/sys_schema/procedures/ps_setup_save.sql97
-rw-r--r--scripts/sys_schema/procedures/ps_setup_show_disabled.sql163
-rw-r--r--scripts/sys_schema/procedures/ps_setup_show_disabled_consumers.sql57
-rw-r--r--scripts/sys_schema/procedures/ps_setup_show_disabled_instruments.sql47
-rw-r--r--scripts/sys_schema/procedures/ps_setup_show_enabled.sql166
-rw-r--r--scripts/sys_schema/procedures/ps_setup_show_enabled_consumers.sql57
-rw-r--r--scripts/sys_schema/procedures/ps_setup_show_enabled_instruments.sql47
-rw-r--r--scripts/sys_schema/procedures/ps_statement_avg_latency_histogram.sql230
-rw-r--r--scripts/sys_schema/procedures/ps_trace_statement_digest.sql324
-rw-r--r--scripts/sys_schema/procedures/ps_trace_thread.sql321
-rw-r--r--scripts/sys_schema/procedures/ps_trace_thread_57.sql340
-rw-r--r--scripts/sys_schema/procedures/ps_truncate_all_tables.sql90
-rw-r--r--scripts/sys_schema/procedures/statement_performance_analyzer.sql723
-rw-r--r--scripts/sys_schema/procedures/table_exists.sql201
30 files changed, 5249 insertions, 0 deletions
diff --git a/scripts/sys_schema/procedures/create_synonym_db.sql b/scripts/sys_schema/procedures/create_synonym_db.sql
new file mode 100644
index 00000000..e373a9b4
--- /dev/null
+++ b/scripts/sys_schema/procedures/create_synonym_db.sql
@@ -0,0 +1,187 @@
+-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS create_synonym_db;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE create_synonym_db (
+ IN in_db_name VARCHAR(64),
+ IN in_synonym VARCHAR(64)
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Takes a source database name and synonym name, and then creates the
+ synonym database with views that point to all of the tables within
+ the source database.
+
+ Useful for creating a "ps" synonym for "performance_schema",
+ or "is" instead of "information_schema", for example.
+
+ Parameters
+ -----------
+
+ in_db_name (VARCHAR(64)):
+ The database name that you would like to create a synonym for.
+ in_synonym (VARCHAR(64)):
+ The database synonym name.
+
+ Example
+ -----------
+
+ mysql> SHOW DATABASES;
+ +--------------------+
+ | Database |
+ +--------------------+
+ | information_schema |
+ | mysql |
+ | performance_schema |
+ | sys |
+ | test |
+ +--------------------+
+ 5 rows in set (0.00 sec)
+
+ mysql> CALL sys.create_synonym_db(\'performance_schema\', \'ps\');
+ +---------------------------------------+
+ | summary |
+ +---------------------------------------+
+ | Created 74 views in the `ps` database |
+ +---------------------------------------+
+ 1 row in set (8.57 sec)
+
+ Query OK, 0 rows affected (8.57 sec)
+
+ mysql> SHOW DATABASES;
+ +--------------------+
+ | Database |
+ +--------------------+
+ | information_schema |
+ | mysql |
+ | performance_schema |
+ | ps |
+ | sys |
+ | test |
+ +--------------------+
+ 6 rows in set (0.00 sec)
+
+ mysql> SHOW FULL TABLES FROM ps;
+ +------------------------------------------------------+------------+
+ | Tables_in_ps | Table_type |
+ +------------------------------------------------------+------------+
+ | accounts | VIEW |
+ | cond_instances | VIEW |
+ | events_stages_current | VIEW |
+ | events_stages_history | VIEW |
+ ...
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ DECLARE v_done bool DEFAULT FALSE;
+ DECLARE v_db_name_check VARCHAR(64);
+ DECLARE v_db_err_msg TEXT;
+ DECLARE v_table VARCHAR(64);
+ DECLARE v_views_created INT DEFAULT 0;
+ DECLARE v_table_exists ENUM('', 'BASE TABLE', 'VIEW', 'TEMPORARY') DEFAULT '';
+ DECLARE v_temp_table TEXT;
+
+ DECLARE c_table_names CURSOR FOR
+ SELECT TABLE_NAME
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = in_db_name;
+
+ DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
+
+ -- Check if the source database exists
+ SELECT SCHEMA_NAME INTO v_db_name_check
+ FROM INFORMATION_SCHEMA.SCHEMATA
+ WHERE SCHEMA_NAME = in_db_name;
+
+ IF v_db_name_check IS NULL THEN
+ SET v_db_err_msg = CONCAT('Unknown database ', in_db_name);
+ SIGNAL SQLSTATE 'HY000'
+ SET MESSAGE_TEXT = v_db_err_msg;
+ END IF;
+
+ -- Check if a database of the synonym name already exists
+ SELECT SCHEMA_NAME INTO v_db_name_check
+ FROM INFORMATION_SCHEMA.SCHEMATA
+ WHERE SCHEMA_NAME = in_synonym;
+
+ IF v_db_name_check = in_synonym THEN
+ SET v_db_err_msg = CONCAT('Can\'t create database ', in_synonym, '; database exists');
+ SIGNAL SQLSTATE 'HY000'
+ SET MESSAGE_TEXT = v_db_err_msg;
+ END IF;
+
+ -- All good, create the database and views
+ SET @create_db_stmt := CONCAT('CREATE DATABASE ', sys.quote_identifier(in_synonym));
+ PREPARE create_db_stmt FROM @create_db_stmt;
+ EXECUTE create_db_stmt;
+ DEALLOCATE PREPARE create_db_stmt;
+
+ SET v_done = FALSE;
+ OPEN c_table_names;
+ c_table_names: LOOP
+ FETCH c_table_names INTO v_table;
+ IF v_done THEN
+ LEAVE c_table_names;
+ END IF;
+
+ -- Check does temporary table shadows the base table. If it is so, terminate.
+ CALL sys.table_exists(in_db_name, v_table, v_table_exists);
+ IF (v_table_exists = 'TEMPORARY') THEN
+ SET v_temp_table =
+ CONCAT(
+ 'Table',
+ sys.quote_identifier(in_db_name),
+ '.',
+ sys.quote_identifier(v_table),
+ 'shadows base table. View cannot be created! Terminating!');
+ SIGNAL SQLSTATE 'HY000'
+ SET MESSAGE_TEXT = v_temp_table;
+ LEAVE c_table_names;
+ END IF;
+
+ SET @create_view_stmt = CONCAT(
+ 'CREATE SQL SECURITY INVOKER VIEW ',
+ sys.quote_identifier(in_synonym),
+ '.',
+ sys.quote_identifier(v_table),
+ ' AS SELECT * FROM ',
+ sys.quote_identifier(in_db_name),
+ '.',
+ sys.quote_identifier(v_table)
+ );
+ PREPARE create_view_stmt FROM @create_view_stmt;
+ EXECUTE create_view_stmt;
+ DEALLOCATE PREPARE create_view_stmt;
+
+ SET v_views_created = v_views_created + 1;
+ END LOOP;
+ CLOSE c_table_names;
+
+ SELECT CONCAT(
+ 'Created ', v_views_created, ' view',
+ IF(v_views_created != 1, 's', ''), ' in the ',
+ sys.quote_identifier(in_synonym), ' database'
+ ) AS summary;
+
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/diagnostics.sql b/scripts/sys_schema/procedures/diagnostics.sql
new file mode 100644
index 00000000..2e79c5c1
--- /dev/null
+++ b/scripts/sys_schema/procedures/diagnostics.sql
@@ -0,0 +1,1064 @@
+-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS diagnostics;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE diagnostics (
+ IN in_max_runtime int unsigned, IN in_interval int unsigned,
+ IN in_auto_config enum ('current', 'medium', 'full')
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Create a report of the current status of the server for diagnostics purposes. Data collected includes (some items depends on versions and settings):
+
+ * The GLOBAL VARIABLES
+ * Several sys schema views including metrics or equivalent (depending on version and settings)
+ * Queries in the 95th percentile
+ * Several ndbinfo views for MySQL Cluster
+ * Replication (both master and slave) information.
+
+ Some of the sys schema views are calculated as initial (optional), overall, delta:
+
+ * The initial view is the content of the view at the start of this procedure.
+ This output will be the same as the the start values used for the delta view.
+ The initial view is included if @sys.diagnostics.include_raw = ''ON''.
+ * The overall view is the content of the view at the end of this procedure.
+ This output is the same as the end values used for the delta view.
+ The overall view is always included.
+ * The delta view is the difference from the beginning to the end. Note that for min and max values
+ they are simply the min or max value from the end view respectively, so does not necessarily reflect
+ the minimum/maximum value in the monitored period.
+ Note: except for the metrics views the delta is only calculation between the first and last outputs.
+
+ Requires the SUPER privilege for "SET sql_log_bin = 0;".
+
+ Versions supported:
+ * MySQL 5.6: 5.6.10 and later
+ * MySQL 5.7: 5.7.9 and later
+
+ Parameters
+ -----------
+
+ in_max_runtime (INT UNSIGNED):
+ The maximum time to keep collecting data.
+ Use NULL to get the default which is 60 seconds, otherwise enter a value greater than 0.
+ in_interval (INT UNSIGNED):
+ How long to sleep between data collections.
+ Use NULL to get the default which is 30 seconds, otherwise enter a value greater than 0.
+ in_auto_config (ENUM(''current'', ''medium'', ''full''))
+ Automatically enable Performance Schema instruments and consumers.
+ NOTE: The more that are enabled, the more impact on the performance.
+ Supported values are:
+ * current - use the current settings.
+ * medium - enable some settings.
+ * full - enables all settings. This will have a big impact on the
+ performance - be careful using this option.
+ If another setting the ''current'' is chosen, the current settings
+ are restored at the end of the procedure.
+
+
+ Configuration Options
+ ----------------------
+
+ sys.diagnostics.allow_i_s_tables
+ Specifies whether it is allowed to do table scan queries on information_schema.TABLES. This can be expensive if there
+ are many tables. Set to ''ON'' to allow, ''OFF'' to not allow.
+ Default is ''OFF''.
+
+ sys.diagnostics.include_raw
+ Set to ''ON'' to include the raw data (e.g. the original output of "SELECT * FROM sys.metrics").
+ Use this to get the initial values of the various views.
+ Default is ''OFF''.
+
+ sys.statement_truncate_len
+ How much of queries in the process list output to include.
+ Default is 64.
+
+ sys.debug
+ Whether to provide debugging output.
+ Default is ''OFF''. Set to ''ON'' to include.
+
+
+ Example
+ --------
+
+ To create a report and append it to the file diag.out:
+
+ mysql> TEE diag.out;
+ mysql> CALL sys.diagnostics(120, 30, ''current'');
+ ...
+ mysql> NOTEE;
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ READS SQL DATA
+BEGIN
+ DECLARE v_start, v_runtime, v_iter_start, v_sleep DECIMAL(20,2) DEFAULT 0.0;
+ DECLARE v_has_innodb, v_has_ndb, v_has_ps, v_has_replication, v_has_ps_replication VARCHAR(8) CHARSET utf8 DEFAULT 'NO';
+ DECLARE v_this_thread_enabled, v_has_ps_vars, v_has_metrics ENUM('YES', 'NO');
+ DECLARE v_table_name, v_banner VARCHAR(64) CHARSET utf8;
+ DECLARE v_sql_status_summary_select, v_sql_status_summary_delta, v_sql_status_summary_from, v_no_delta_names TEXT;
+ DECLARE v_output_time, v_output_time_prev DECIMAL(20,3) UNSIGNED;
+ DECLARE v_output_count, v_count, v_old_group_concat_max_len INT UNSIGNED DEFAULT 0;
+ -- The width of each of the status outputs in the summery
+ DECLARE v_status_summary_width TINYINT UNSIGNED DEFAULT 50;
+ DECLARE v_done BOOLEAN DEFAULT FALSE;
+ -- Do not include the following ndbinfo views:
+ -- 'blocks' Static
+ -- 'config_params' Static
+ -- 'dict_obj_types' Static
+ -- 'disk_write_speed_base' Can generate lots of output - only include aggregate views here
+ -- 'memory_per_fragment' Can generate lots of output
+ -- 'memoryusage' Handled separately
+ -- 'operations_per_fragment' Can generate lots of output
+ -- 'threadblocks' Only needed once
+ DECLARE c_ndbinfo CURSOR FOR
+ SELECT TABLE_NAME
+ FROM information_schema.TABLES
+ WHERE TABLE_SCHEMA = 'ndbinfo'
+ AND TABLE_NAME NOT IN (
+ 'blocks',
+ 'config_params',
+ 'dict_obj_types',
+ 'disk_write_speed_base',
+ 'memory_per_fragment',
+ 'memoryusage',
+ 'operations_per_fragment',
+ 'threadblocks'
+ );
+ DECLARE c_sysviews_w_delta CURSOR FOR
+ SELECT table_name
+ FROM tmp_sys_views_delta
+ ORDER BY table_name;
+ DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
+
+ -- Do not track the current thread - no reason to clutter the output
+ SELECT INSTRUMENTED INTO v_this_thread_enabled FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID();
+ IF (v_this_thread_enabled = 'YES') THEN
+ CALL sys.ps_setup_disable_thread(CONNECTION_ID());
+ END IF;
+
+ -- Check options are sane
+ IF (in_max_runtime < in_interval) THEN
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = 'in_max_runtime must be greater than or equal to in_interval';
+ END IF;
+ IF (in_max_runtime = 0) THEN
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = 'in_max_runtime must be greater than 0';
+ END IF;
+ IF (in_interval = 0) THEN
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = 'in_interval must be greater than 0';
+ END IF;
+
+ -- Set configuration options
+ IF (@sys.diagnostics.allow_i_s_tables IS NULL) THEN
+ SET @sys.diagnostics.allow_i_s_tables = sys.sys_get_config('diagnostics.allow_i_s_tables', 'OFF');
+ END IF;
+ IF (@sys.diagnostics.include_raw IS NULL) THEN
+ SET @sys.diagnostics.include_raw = sys.sys_get_config('diagnostics.include_raw' , 'OFF');
+ END IF;
+ IF (@sys.debug IS NULL) THEN
+ SET @sys.debug = sys.sys_get_config('debug' , 'OFF');
+ END IF;
+ IF (@sys.statement_truncate_len IS NULL) THEN
+ SET @sys.statement_truncate_len = sys.sys_get_config('statement_truncate_len' , '64' );
+ END IF;
+
+ -- Temporary table are used - disable sql_log_bin if necessary to prevent them replicating
+ SET @log_bin := @@sql_log_bin;
+ IF (@log_bin = 1) THEN
+ SET sql_log_bin = 0;
+ END IF;
+
+ -- Some metrics variables doesn't make sense in delta and rate calculations even if they are numeric
+ -- as they really are more like settings or "current" status.
+ SET v_no_delta_names = CONCAT('s%{COUNT}.Variable_name NOT IN (',
+ '''innodb_buffer_pool_pages_total'', ',
+ '''innodb_page_size'', ',
+ '''last_query_cost'', ',
+ '''last_query_partial_plans'', ',
+ '''qcache_total_blocks'', ',
+ '''slave_last_heartbeat'', ',
+ '''ssl_ctx_verify_depth'', ',
+ '''ssl_ctx_verify_mode'', ',
+ '''ssl_session_cache_size'', ',
+ '''ssl_verify_depth'', ',
+ '''ssl_verify_mode'', ',
+ '''ssl_version'', ',
+ '''buffer_flush_lsn_avg_rate'', ',
+ '''buffer_flush_pct_for_dirty'', ',
+ '''buffer_flush_pct_for_lsn'', ',
+ '''buffer_pool_pages_total'', ',
+ '''lock_row_lock_time_avg'', ',
+ '''lock_row_lock_time_max'', ',
+ '''innodb_page_size''',
+ ')');
+
+ IF (in_auto_config <> 'current') THEN
+ IF (@sys.debug = 'ON') THEN
+ SELECT CONCAT('Updating Performance Schema configuration to ', in_auto_config) AS 'Debug';
+ END IF;
+ CALL sys.ps_setup_save(0);
+
+ IF (in_auto_config = 'medium') THEN
+ -- Enable all consumers except %history and %history_long
+ UPDATE performance_schema.setup_consumers
+ SET ENABLED = 'YES'
+ WHERE NAME NOT LIKE '%\_history%';
+
+ -- Enable all instruments except wait/synch/%
+ UPDATE performance_schema.setup_instruments
+ SET ENABLED = 'YES',
+ TIMED = 'YES'
+ WHERE NAME NOT LIKE 'wait/synch/%';
+ ELSEIF (in_auto_config = 'full') THEN
+ UPDATE performance_schema.setup_consumers
+ SET ENABLED = 'YES';
+
+ UPDATE performance_schema.setup_instruments
+ SET ENABLED = 'YES',
+ TIMED = 'YES';
+ END IF;
+
+ -- Enable all threads except this one
+ UPDATE performance_schema.threads
+ SET INSTRUMENTED = 'YES'
+ WHERE PROCESSLIST_ID <> CONNECTION_ID();
+ END IF;
+
+ SET v_start = UNIX_TIMESTAMP(NOW(2)),
+ in_interval = IFNULL(in_interval, 30),
+ in_max_runtime = IFNULL(in_max_runtime, 60);
+
+ -- Get a quick ref with hostname, server UUID, and the time for the report.
+ SET v_banner = REPEAT(
+ '-',
+ LEAST(
+ GREATEST(
+ 36,
+ CHAR_LENGTH(VERSION()),
+ CHAR_LENGTH(@@global.version_comment),
+ CHAR_LENGTH(@@global.version_compile_os),
+ CHAR_LENGTH(@@global.version_compile_machine),
+ CHAR_LENGTH(@@global.socket),
+ CHAR_LENGTH(@@global.datadir)
+ ),
+ 64
+ )
+ );
+ SELECT 'Hostname' AS 'Name', @@global.hostname AS 'Value'
+ UNION ALL
+ SELECT 'Port' AS 'Name', @@global.port AS 'Value'
+ UNION ALL
+ SELECT 'Socket' AS 'Name', @@global.socket AS 'Value'
+ UNION ALL
+ SELECT 'Datadir' AS 'Name', @@global.datadir AS 'Value'
+ UNION ALL
+ SELECT REPEAT('-', 23) AS 'Name', v_banner AS 'Value'
+ UNION ALL
+ SELECT 'MySQL Version' AS 'Name', VERSION() AS 'Value'
+ UNION ALL
+ SELECT 'Sys Schema Version' AS 'Name', (SELECT sys_version FROM sys.version) AS 'Value'
+ UNION ALL
+ SELECT 'Version Comment' AS 'Name', @@global.version_comment AS 'Value'
+ UNION ALL
+ SELECT 'Version Compile OS' AS 'Name', @@global.version_compile_os AS 'Value'
+ UNION ALL
+ SELECT 'Version Compile Machine' AS 'Name', @@global.version_compile_machine AS 'Value'
+ UNION ALL
+ SELECT REPEAT('-', 23) AS 'Name', v_banner AS 'Value'
+ UNION ALL
+ SELECT 'UTC Time' AS 'Name', UTC_TIMESTAMP() AS 'Value'
+ UNION ALL
+ SELECT 'Local Time' AS 'Name', NOW() AS 'Value'
+ UNION ALL
+ SELECT 'Time Zone' AS 'Name', @@global.time_zone AS 'Value'
+ UNION ALL
+ SELECT 'System Time Zone' AS 'Name', @@global.system_time_zone AS 'Value'
+ UNION ALL
+ SELECT 'Time Zone Offset' AS 'Name', TIMEDIFF(NOW(), UTC_TIMESTAMP()) AS 'Value';
+
+ -- Are the InnoDB, NDBCluster, and Performance Schema storage engines present?
+ SET v_has_innodb = IFNULL((SELECT SUPPORT FROM information_schema.ENGINES WHERE ENGINE = 'InnoDB'), 'NO'),
+ v_has_ndb = IFNULL((SELECT SUPPORT FROM information_schema.ENGINES WHERE ENGINE = 'NDBCluster'), 'NO'),
+ v_has_ps = IFNULL((SELECT SUPPORT FROM information_schema.ENGINES WHERE ENGINE = 'PERFORMANCE_SCHEMA'), 'NO'),
+ v_has_ps_replication = IF(v_has_ps = 'YES'
+ AND EXISTS(SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'performance_schema' AND TABLE_NAME = 'replication_applier_status'),
+ 'YES',
+ 'NO'
+ ),
+ v_has_replication = 'MAYBE',
+ v_has_metrics = IF(v_has_ps = 'YES' OR (sys.version_major() = 5 AND sys.version_minor() = 6), 'YES', 'NO'),
+ v_has_ps_vars = 'NO';
+
+ -- 5.7.7 introduced the possibility to get SHOW [GLOBAL|SESSION] VARIABLES and SHOW [GLOBAL|SESSION] STATUS
+ -- from the Performance Schema. But it's optional whether it's enabled.
+ -- 5.7.9 changes so the Performance Schema tables always work.
+ -- Note that @@global.show_compatibility_56 = OFF will only actually work if the Performance Schema is enabled in <=5.7.8,
+ -- however except overriding the global value there is nothing that can be done about it.
+ -- v_has_ps_vars defaults to NO
+ /*!50707 SET v_has_ps_vars = IF(@@global.show_compatibility_56, 'NO', 'YES');*/
+ /*!50709 SET v_has_ps_vars = 'YES';*/
+
+ IF (@sys.debug = 'ON') THEN
+ SELECT v_has_innodb AS 'Has_InnoDB', v_has_ndb AS 'Has_NDBCluster',
+ v_has_ps AS 'Has_Performance_Schema', v_has_ps_vars AS 'Has_P_S_SHOW_Variables',
+ v_has_metrics AS 'Has_metrics',
+ v_has_ps_replication 'AS Has_P_S_Replication', v_has_replication AS 'Has_Replication';
+ END IF;
+
+ IF (v_has_innodb IN ('DEFAULT', 'YES')) THEN
+ -- Need to use prepared statement as just having the query as a plain command
+ -- will generate an error if the InnoDB storage engine is not present
+ SET @sys.diagnostics.sql = 'SHOW ENGINE InnoDB STATUS';
+ PREPARE stmt_innodb_status FROM @sys.diagnostics.sql;
+ END IF;
+
+ IF (v_has_ps = 'YES') THEN
+ -- Need to use prepared statement as just having the query as a plain command
+ -- will generate an error if the InnoDB storage engine is not present
+ SET @sys.diagnostics.sql = 'SHOW ENGINE PERFORMANCE_SCHEMA STATUS';
+ PREPARE stmt_ps_status FROM @sys.diagnostics.sql;
+ END IF;
+
+ IF (v_has_ndb IN ('DEFAULT', 'YES')) THEN
+ -- Need to use prepared statement as just having the query as a plain command
+ -- will generate an error if the NDBCluster storage engine is not present
+ SET @sys.diagnostics.sql = 'SHOW ENGINE NDBCLUSTER STATUS';
+ PREPARE stmt_ndbcluster_status FROM @sys.diagnostics.sql;
+ END IF;
+
+ SET @sys.diagnostics.sql_gen_query_template = 'SELECT CONCAT(
+ ''SELECT '',
+ GROUP_CONCAT(
+ CASE WHEN (SUBSTRING(TABLE_NAME, 3), COLUMN_NAME) IN (
+ (''io_global_by_file_by_bytes'', ''total''),
+ (''io_global_by_wait_by_bytes'', ''total_requested'')
+ )
+ THEN CONCAT(''sys.format_bytes('', COLUMN_NAME, '') AS '', COLUMN_NAME)
+ WHEN SUBSTRING(COLUMN_NAME, -8) = ''_latency''
+ THEN CONCAT(''sys.format_time('', COLUMN_NAME, '') AS '', COLUMN_NAME)
+ WHEN SUBSTRING(COLUMN_NAME, -7) = ''_memory'' OR SUBSTRING(COLUMN_NAME, -17) = ''_memory_allocated''
+ OR ((SUBSTRING(COLUMN_NAME, -5) = ''_read'' OR SUBSTRING(COLUMN_NAME, -8) = ''_written'' OR SUBSTRING(COLUMN_NAME, -6) = ''_write'') AND SUBSTRING(COLUMN_NAME, 1, 6) <> ''COUNT_'')
+ THEN CONCAT(''sys.format_bytes('', COLUMN_NAME, '') AS '', COLUMN_NAME)
+ ELSE COLUMN_NAME
+ END
+ ORDER BY ORDINAL_POSITION
+ SEPARATOR '',\n ''
+ ),
+ ''\n FROM tmp_'', SUBSTRING(TABLE_NAME FROM 3), ''_%{OUTPUT}''
+ ) AS Query INTO @sys.diagnostics.sql_select
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = ''sys'' AND TABLE_NAME = ?
+ GROUP BY TABLE_NAME';
+
+ SET @sys.diagnostics.sql_gen_query_delta = 'SELECT CONCAT(
+ ''SELECT '',
+ GROUP_CONCAT(
+ CASE WHEN FIND_IN_SET(COLUMN_NAME, diag.pk)
+ THEN COLUMN_NAME
+ WHEN diag.TABLE_NAME = ''io_global_by_file_by_bytes'' AND COLUMN_NAME = ''write_pct''
+ THEN CONCAT(''IFNULL(ROUND(100-(((e.total_read-IFNULL(s.total_read, 0))'',
+ ''/NULLIF(((e.total_read-IFNULL(s.total_read, 0))+(e.total_written-IFNULL(s.total_written, 0))), 0))*100), 2), 0.00) AS '',
+ COLUMN_NAME)
+ WHEN (diag.TABLE_NAME, COLUMN_NAME) IN (
+ (''io_global_by_file_by_bytes'', ''total''),
+ (''io_global_by_wait_by_bytes'', ''total_requested'')
+ )
+ THEN CONCAT(''sys.format_bytes(e.'', COLUMN_NAME, ''-IFNULL(s.'', COLUMN_NAME, '', 0)) AS '', COLUMN_NAME)
+ WHEN SUBSTRING(COLUMN_NAME, 1, 4) IN (''max_'', ''min_'') AND SUBSTRING(COLUMN_NAME, -8) = ''_latency''
+ THEN CONCAT(''sys.format_time(e.'', COLUMN_NAME, '') AS '', COLUMN_NAME)
+ WHEN COLUMN_NAME = ''avg_latency''
+ THEN CONCAT(''sys.format_time((e.total_latency - IFNULL(s.total_latency, 0))'',
+ ''/NULLIF(e.total - IFNULL(s.total, 0), 0)) AS '', COLUMN_NAME)
+ WHEN SUBSTRING(COLUMN_NAME, -12) = ''_avg_latency''
+ THEN CONCAT(''sys.format_time((e.'', SUBSTRING(COLUMN_NAME FROM 1 FOR CHAR_LENGTH(COLUMN_NAME)-12), ''_latency - IFNULL(s.'', SUBSTRING(COLUMN_NAME FROM 1 FOR CHAR_LENGTH(COLUMN_NAME)-12), ''_latency, 0))'',
+ ''/NULLIF(e.'', SUBSTRING(COLUMN_NAME FROM 1 FOR CHAR_LENGTH(COLUMN_NAME)-12), ''s - IFNULL(s.'', SUBSTRING(COLUMN_NAME FROM 1 FOR CHAR_LENGTH(COLUMN_NAME)-12), ''s, 0), 0)) AS '', COLUMN_NAME)
+ WHEN SUBSTRING(COLUMN_NAME, -8) = ''_latency''
+ THEN CONCAT(''sys.format_time(e.'', COLUMN_NAME, '' - IFNULL(s.'', COLUMN_NAME, '', 0)) AS '', COLUMN_NAME)
+ WHEN COLUMN_NAME IN (''avg_read'', ''avg_write'', ''avg_written'')
+ THEN CONCAT(''sys.format_bytes(IFNULL((e.total_'', IF(COLUMN_NAME = ''avg_read'', ''read'', ''written''), ''-IFNULL(s.total_'', IF(COLUMN_NAME = ''avg_read'', ''read'', ''written''), '', 0))'',
+ ''/NULLIF(e.count_'', IF(COLUMN_NAME = ''avg_read'', ''read'', ''write''), ''-IFNULL(s.count_'', IF(COLUMN_NAME = ''avg_read'', ''read'', ''write''), '', 0), 0), 0)) AS '',
+ COLUMN_NAME)
+ WHEN SUBSTRING(COLUMN_NAME, -7) = ''_memory'' OR SUBSTRING(COLUMN_NAME, -17) = ''_memory_allocated''
+ OR ((SUBSTRING(COLUMN_NAME, -5) = ''_read'' OR SUBSTRING(COLUMN_NAME, -8) = ''_written'' OR SUBSTRING(COLUMN_NAME, -6) = ''_write'') AND SUBSTRING(COLUMN_NAME, 1, 6) <> ''COUNT_'')
+ THEN CONCAT(''sys.format_bytes(e.'', COLUMN_NAME, '' - IFNULL(s.'', COLUMN_NAME, '', 0)) AS '', COLUMN_NAME)
+ ELSE CONCAT(''(e.'', COLUMN_NAME, '' - IFNULL(s.'', COLUMN_NAME, '', 0)) AS '', COLUMN_NAME)
+ END
+ ORDER BY ORDINAL_POSITION
+ SEPARATOR '',\n ''
+ ),
+ ''\n FROM tmp_'', diag.TABLE_NAME, ''_end e
+ LEFT OUTER JOIN tmp_'', diag.TABLE_NAME, ''_start s USING ('', diag.pk, '')''
+ ) AS Query INTO @sys.diagnostics.sql_select
+ FROM tmp_sys_views_delta diag
+ INNER JOIN information_schema.COLUMNS c ON c.TABLE_NAME = CONCAT(''x$'', diag.TABLE_NAME)
+ WHERE c.TABLE_SCHEMA = ''sys'' AND diag.TABLE_NAME = ?
+ GROUP BY diag.TABLE_NAME';
+
+ IF (v_has_ps = 'YES') THEN
+ -- Create temporary table with the ORDER BY clauses. Will be required both for the initial (if included) and end queries
+ DROP TEMPORARY TABLE IF EXISTS tmp_sys_views_delta;
+ CREATE TEMPORARY TABLE tmp_sys_views_delta (
+ TABLE_NAME varchar(64) NOT NULL,
+ order_by text COMMENT 'ORDER BY clause for the initial and overall views',
+ order_by_delta text COMMENT 'ORDER BY clause for the delta views',
+ where_delta text COMMENT 'WHERE clause to use for delta views to only include rows with a "count" > 0',
+ limit_rows int unsigned COMMENT 'The maximum number of rows to include for the view',
+ pk varchar(128) COMMENT 'Used with the FIND_IN_SET() function so use comma separated list without whitespace',
+ PRIMARY KEY (TABLE_NAME)
+ );
+
+ -- %{OUTPUT} will be replace by the suffix used for the output.
+ IF (@sys.debug = 'ON') THEN
+ SELECT 'Populating tmp_sys_views_delta' AS 'Debug';
+ END IF;
+ INSERT INTO tmp_sys_views_delta
+ VALUES ('host_summary' , '%{TABLE}.statement_latency DESC',
+ '(e.statement_latency-IFNULL(s.statement_latency, 0)) DESC',
+ '(e.statements - IFNULL(s.statements, 0)) > 0', NULL, 'host'),
+ ('host_summary_by_file_io' , '%{TABLE}.io_latency DESC',
+ '(e.io_latency-IFNULL(s.io_latency, 0)) DESC',
+ '(e.ios - IFNULL(s.ios, 0)) > 0', NULL, 'host'),
+ ('host_summary_by_file_io_type' , '%{TABLE}.host, %{TABLE}.total_latency DESC',
+ 'e.host, (e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'host,event_name'),
+ ('host_summary_by_stages' , '%{TABLE}.host, %{TABLE}.total_latency DESC',
+ 'e.host, (e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'host,event_name'),
+ ('host_summary_by_statement_latency' , '%{TABLE}.total_latency DESC',
+ '(e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'host'),
+ ('host_summary_by_statement_type' , '%{TABLE}.host, %{TABLE}.total_latency DESC',
+ 'e.host, (e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'host,statement'),
+ ('io_by_thread_by_latency' , '%{TABLE}.total_latency DESC',
+ '(e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user,thread_id,processlist_id'),
+ ('io_global_by_file_by_bytes' , '%{TABLE}.total DESC',
+ '(e.total-IFNULL(s.total, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', 100, 'file'),
+ ('io_global_by_file_by_latency' , '%{TABLE}.total_latency DESC',
+ '(e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', 100, 'file'),
+ ('io_global_by_wait_by_bytes' , '%{TABLE}.total_requested DESC',
+ '(e.total_requested-IFNULL(s.total_requested, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'event_name'),
+ ('io_global_by_wait_by_latency' , '%{TABLE}.total_latency DESC',
+ '(e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'event_name'),
+ ('schema_index_statistics' , '(%{TABLE}.select_latency+%{TABLE}.insert_latency+%{TABLE}.update_latency+%{TABLE}.delete_latency) DESC',
+ '((e.select_latency+e.insert_latency+e.update_latency+e.delete_latency)-IFNULL(s.select_latency+s.insert_latency+s.update_latency+s.delete_latency, 0)) DESC',
+ '((e.rows_selected+e.insert_latency+e.rows_updated+e.rows_deleted)-IFNULL(s.rows_selected+s.rows_inserted+s.rows_updated+s.rows_deleted, 0)) > 0',
+ 100, 'table_schema,table_name,index_name'),
+ ('schema_table_statistics' , '%{TABLE}.total_latency DESC',
+ '(e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total_latency-IFNULL(s.total_latency, 0)) > 0', 100, 'table_schema,table_name'),
+ ('schema_tables_with_full_table_scans', '%{TABLE}.rows_full_scanned DESC',
+ '(e.rows_full_scanned-IFNULL(s.rows_full_scanned, 0)) DESC',
+ '(e.rows_full_scanned-IFNULL(s.rows_full_scanned, 0)) > 0', 100, 'object_schema,object_name'),
+ ('user_summary' , '%{TABLE}.statement_latency DESC',
+ '(e.statement_latency-IFNULL(s.statement_latency, 0)) DESC',
+ '(e.statements - IFNULL(s.statements, 0)) > 0', NULL, 'user'),
+ ('user_summary_by_file_io' , '%{TABLE}.io_latency DESC',
+ '(e.io_latency-IFNULL(s.io_latency, 0)) DESC',
+ '(e.ios - IFNULL(s.ios, 0)) > 0', NULL, 'user'),
+ ('user_summary_by_file_io_type' , '%{TABLE}.user, %{TABLE}.latency DESC',
+ 'e.user, (e.latency-IFNULL(s.latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user,event_name'),
+ ('user_summary_by_stages' , '%{TABLE}.user, %{TABLE}.total_latency DESC',
+ 'e.user, (e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user,event_name'),
+ ('user_summary_by_statement_latency' , '%{TABLE}.total_latency DESC',
+ '(e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user'),
+ ('user_summary_by_statement_type' , '%{TABLE}.user, %{TABLE}.total_latency DESC',
+ 'e.user, (e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user,statement'),
+ ('wait_classes_global_by_avg_latency' , 'IFNULL(%{TABLE}.total_latency / NULLIF(%{TABLE}.total, 0), 0) DESC',
+ 'IFNULL((e.total_latency-IFNULL(s.total_latency, 0)) / NULLIF((e.total - IFNULL(s.total, 0)), 0), 0) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'event_class'),
+ ('wait_classes_global_by_latency' , '%{TABLE}.total_latency DESC',
+ '(e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'event_class'),
+ ('waits_by_host_by_latency' , '%{TABLE}.host, %{TABLE}.total_latency DESC',
+ 'e.host, (e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'host,event'),
+ ('waits_by_user_by_latency' , '%{TABLE}.user, %{TABLE}.total_latency DESC',
+ 'e.user, (e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'user,event'),
+ ('waits_global_by_latency' , '%{TABLE}.total_latency DESC',
+ '(e.total_latency-IFNULL(s.total_latency, 0)) DESC',
+ '(e.total - IFNULL(s.total, 0)) > 0', NULL, 'events')
+ ;
+ END IF;
+
+
+ SELECT '
+
+=======================
+
+ Configuration
+
+=======================
+
+' AS '';
+ -- Get the configuration.
+ SELECT 'GLOBAL VARIABLES' AS 'The following output is:';
+ IF (v_has_ps_vars = 'YES') THEN
+ SELECT LOWER(VARIABLE_NAME) AS Variable_name, VARIABLE_VALUE AS Variable_value FROM performance_schema.global_variables ORDER BY VARIABLE_NAME;
+ ELSE
+ SELECT LOWER(VARIABLE_NAME) AS Variable_name, VARIABLE_VALUE AS Variable_value FROM information_schema.GLOBAL_VARIABLES ORDER BY VARIABLE_NAME;
+ END IF;
+
+ IF (v_has_ps = 'YES') THEN
+ -- Overview of the Performance Schema dynamic settings used for this report.
+ SELECT 'Performance Schema Setup - Actors' AS 'The following output is:';
+ SELECT * FROM performance_schema.setup_actors;
+
+ SELECT 'Performance Schema Setup - Consumers' AS 'The following output is:';
+ SELECT NAME AS Consumer, ENABLED, sys.ps_is_consumer_enabled(NAME) AS COLLECTS
+ FROM performance_schema.setup_consumers;
+
+ SELECT 'Performance Schema Setup - Instruments' AS 'The following output is:';
+ SELECT SUBSTRING_INDEX(NAME, '/', 2) AS 'InstrumentClass',
+ ROUND(100*SUM(IF(ENABLED = 'YES', 1, 0))/COUNT(*), 2) AS 'EnabledPct',
+ ROUND(100*SUM(IF(TIMED = 'YES', 1, 0))/COUNT(*), 2) AS 'TimedPct'
+ FROM performance_schema.setup_instruments
+ GROUP BY SUBSTRING_INDEX(NAME, '/', 2)
+ ORDER BY SUBSTRING_INDEX(NAME, '/', 2);
+
+ SELECT 'Performance Schema Setup - Objects' AS 'The following output is:';
+ SELECT * FROM performance_schema.setup_objects;
+
+ SELECT 'Performance Schema Setup - Threads' AS 'The following output is:';
+ SELECT `TYPE` AS ThreadType, COUNT(*) AS 'Total', ROUND(100*SUM(IF(INSTRUMENTED = 'YES', 1, 0))/COUNT(*), 2) AS 'InstrumentedPct'
+ FROM performance_schema.threads
+ GROUP BY TYPE;
+ END IF;
+
+
+ IF (v_has_replication = 'NO') THEN
+ SELECT 'No Replication Configured' AS 'Replication Status';
+ ELSE
+ -- No guarantee that replication is actually configured, but we can't really know
+ SELECT CONCAT('Replication Configured: ', v_has_replication, ' - Performance Schema Replication Tables: ', v_has_ps_replication) AS 'Replication Status';
+
+ IF (v_has_ps_replication = 'YES') THEN
+ SELECT 'Replication - Connection Configuration' AS 'The following output is:';
+ SELECT * FROM performance_schema.replication_connection_configuration/*!50706 ORDER BY CHANNEL_NAME*/;
+ END IF;
+
+ IF (v_has_ps_replication = 'YES') THEN
+ SELECT 'Replication - Applier Configuration' AS 'The following output is:';
+ SELECT * FROM performance_schema.replication_applier_configuration ORDER BY CHANNEL_NAME;
+ END IF;
+ END IF;
+
+
+ IF (v_has_ndb IN ('DEFAULT', 'YES')) THEN
+ SELECT 'Cluster Thread Blocks' AS 'The following output is:';
+ SELECT * FROM ndbinfo.threadblocks;
+ END IF;
+
+ -- For a number of sys views as well as events_statements_summary_by_digest,
+ -- just get the start data and then at the end output the overall and delta values
+ IF (v_has_ps = 'YES') THEN
+ IF (@sys.diagnostics.include_raw = 'ON') THEN
+ SELECT '
+
+========================
+
+ Initial Status
+
+========================
+
+' AS '';
+ END IF;
+
+ DROP TEMPORARY TABLE IF EXISTS tmp_digests_start;
+ CALL sys.statement_performance_analyzer('create_tmp', 'tmp_digests_start', NULL);
+ CALL sys.statement_performance_analyzer('snapshot', NULL, NULL);
+ CALL sys.statement_performance_analyzer('save', 'tmp_digests_start', NULL);
+
+ -- Loop over the sys views where deltas should be calculated.
+ IF (@sys.diagnostics.include_raw = 'ON') THEN
+ SET @sys.diagnostics.sql = REPLACE(@sys.diagnostics.sql_gen_query_template, '%{OUTPUT}', 'start');
+ IF (@sys.debug = 'ON') THEN
+ SELECT 'The following query will be used to generate the query for each sys view' AS 'Debug';
+ SELECT @sys.diagnostics.sql AS 'Debug';
+ END IF;
+ PREPARE stmt_gen_query FROM @sys.diagnostics.sql;
+ END IF;
+ SET v_done = FALSE;
+ OPEN c_sysviews_w_delta;
+ c_sysviews_w_delta_loop: LOOP
+ FETCH c_sysviews_w_delta INTO v_table_name;
+ IF v_done THEN
+ LEAVE c_sysviews_w_delta_loop;
+ END IF;
+
+ IF (@sys.debug = 'ON') THEN
+ SELECT CONCAT('The following queries are for storing the initial content of ', v_table_name) AS 'Debug';
+ END IF;
+
+ CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE IF EXISTS `tmp_', v_table_name, '_start`'));
+ CALL sys.execute_prepared_stmt(CONCAT('CREATE TEMPORARY TABLE `tmp_', v_table_name, '_start` SELECT * FROM `sys`.`x$', v_table_name, '`'));
+
+ IF (@sys.diagnostics.include_raw = 'ON') THEN
+ SET @sys.diagnostics.table_name = CONCAT('x$', v_table_name);
+ EXECUTE stmt_gen_query USING @sys.diagnostics.table_name;
+ -- If necessary add ORDER BY and LIMIT
+ SELECT CONCAT(@sys.diagnostics.sql_select,
+ IF(order_by IS NOT NULL, CONCAT('\n ORDER BY ', REPLACE(order_by, '%{TABLE}', CONCAT('tmp_', v_table_name, '_start'))), ''),
+ IF(limit_rows IS NOT NULL, CONCAT('\n LIMIT ', limit_rows), '')
+ )
+ INTO @sys.diagnostics.sql_select
+ FROM tmp_sys_views_delta
+ WHERE TABLE_NAME = v_table_name;
+ SELECT CONCAT('Initial ', v_table_name) AS 'The following output is:';
+ CALL sys.execute_prepared_stmt(@sys.diagnostics.sql_select);
+ END IF;
+ END LOOP;
+ CLOSE c_sysviews_w_delta;
+
+ IF (@sys.diagnostics.include_raw = 'ON') THEN
+ DEALLOCATE PREPARE stmt_gen_query;
+ END IF;
+ END IF;
+
+ -- If in_include_status_summary is TRUE then a temporary table is required to store the data
+ SET v_sql_status_summary_select = 'SELECT Variable_name',
+ v_sql_status_summary_delta = '',
+ v_sql_status_summary_from = '';
+
+ -- Start the loop
+ REPEAT
+ SET v_output_count = v_output_count + 1;
+ IF (v_output_count > 1) THEN
+ -- Don't sleep on the first execution
+ SET v_sleep = in_interval-(UNIX_TIMESTAMP(NOW(2))-v_iter_start);
+ SELECT NOW() AS 'Time', CONCAT('Going to sleep for ', v_sleep, ' seconds. Please do not interrupt') AS 'The following output is:';
+ DO SLEEP(in_interval);
+ END IF;
+ SET v_iter_start = UNIX_TIMESTAMP(NOW(2));
+
+ SELECT NOW(), CONCAT('Iteration Number ', IFNULL(v_output_count, 'NULL')) AS 'The following output is:';
+
+ -- Even in 5.7 there is no way to get all the info from SHOW MASTER|SLAVE STATUS using the Performance Schema or
+ -- other tables, so include them even though they are no longer optimal solutions and if present get the additional
+ -- information from the other tables available.
+ IF (@@log_bin = 1) THEN
+ SELECT 'SHOW MASTER STATUS' AS 'The following output is:';
+ SHOW MASTER STATUS;
+ END IF;
+
+ IF (v_has_replication <> 'NO') THEN
+ SELECT 'SHOW SLAVE STATUS' AS 'The following output is:';
+ SHOW SLAVE STATUS;
+ END IF;
+
+ -- We need one table per output as a temporary table cannot be opened twice in the same query, and we need to
+ -- join the outputs in the summary at the end.
+ SET v_table_name = CONCAT('tmp_metrics_', v_output_count);
+ CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE IF EXISTS ', v_table_name));
+
+ -- Currently information_schema.GLOBAL_STATUS has VARIABLE_VALUE as varchar(1024)
+ CALL sys.execute_prepared_stmt(CONCAT('CREATE TEMPORARY TABLE ', v_table_name, ' (
+ Variable_name VARCHAR(193) NOT NULL,
+ Variable_value VARCHAR(1024),
+ Type VARCHAR(100) NOT NULL,
+ Enabled ENUM(''YES'', ''NO'', ''PARTIAL'') NOT NULL,
+ PRIMARY KEY (Type, Variable_name)
+) ENGINE = InnoDB DEFAULT CHARSET=utf8'));
+
+ IF (v_has_metrics) THEN
+ SET @sys.diagnostics.sql = CONCAT(
+ 'INSERT INTO ', v_table_name,
+ ' SELECT Variable_name, REPLACE(Variable_value, ''\n'', ''\\\\n'') AS Variable_value, Type, Enabled FROM sys.metrics'
+ );
+ ELSE
+ -- 5.7+ and the Performance Schema disabled. Use information_schema.GLOBAL_STATUS instead like in 5.6.
+ SET @sys.diagnostics.sql = CONCAT(
+ 'INSERT INTO ', v_table_name,
+ '(SELECT LOWER(VARIABLE_NAME) AS Variable_name, REPLACE(VARIABLE_VALUE, ''\n'', ''\\\\n'') AS Variable_value,
+ ''Global Status'' AS Type, ''YES'' AS Enabled
+ FROM performance_schema.global_status
+) UNION ALL (
+SELECT NAME AS Variable_name, COUNT AS Variable_value,
+ CONCAT(''InnoDB Metrics - '', SUBSYSTEM) AS Type,
+ IF(STATUS = ''enabled'', ''YES'', ''NO'') AS Enabled
+ FROM information_schema.INNODB_METRICS
+ -- Deduplication - some variables exists both in GLOBAL_STATUS and INNODB_METRICS
+ -- Keep the one from GLOBAL_STATUS as it is always enabled and it''s more likely to be used for existing tools.
+ WHERE NAME NOT IN (
+ ''lock_row_lock_time'', ''lock_row_lock_time_avg'', ''lock_row_lock_time_max'', ''lock_row_lock_waits'',
+ ''buffer_pool_reads'', ''buffer_pool_read_requests'', ''buffer_pool_write_requests'', ''buffer_pool_wait_free'',
+ ''buffer_pool_read_ahead'', ''buffer_pool_read_ahead_evicted'', ''buffer_pool_pages_total'', ''buffer_pool_pages_misc'',
+ ''buffer_pool_pages_data'', ''buffer_pool_bytes_data'', ''buffer_pool_pages_dirty'', ''buffer_pool_bytes_dirty'',
+ ''buffer_pool_pages_free'', ''buffer_pages_created'', ''buffer_pages_written'', ''buffer_pages_read'',
+ ''buffer_data_reads'', ''buffer_data_written'', ''file_num_open_files'',
+ ''os_log_bytes_written'', ''os_log_fsyncs'', ''os_log_pending_fsyncs'', ''os_log_pending_writes'',
+ ''log_waits'', ''log_write_requests'', ''log_writes'', ''innodb_dblwr_writes'', ''innodb_dblwr_pages_written'', ''innodb_page_size'')
+) UNION ALL (
+SELECT ''NOW()'' AS Variable_name, NOW(3) AS Variable_value, ''System Time'' AS Type, ''YES'' AS Enabled
+) UNION ALL (
+SELECT ''UNIX_TIMESTAMP()'' AS Variable_name, ROUND(UNIX_TIMESTAMP(NOW(3)), 3) AS Variable_value, ''System Time'' AS Type, ''YES'' AS Enabled
+)
+ ORDER BY Type, Variable_name;'
+ );
+ END IF;
+ CALL sys.execute_prepared_stmt(@sys.diagnostics.sql);
+
+ -- Prepare the query to retrieve the summary
+ CALL sys.execute_prepared_stmt(
+ CONCAT('SELECT Variable_value INTO @sys.diagnostics.output_time FROM ', v_table_name, ' WHERE Type = ''System Time'' AND Variable_name = ''UNIX_TIMESTAMP()''')
+ );
+ SET v_output_time = @sys.diagnostics.output_time;
+
+ -- Limit each value to v_status_summary_width chars (when v_has_ndb = TRUE the values can be very wide - refer to the output here for the full values)
+ -- v_sql_status_summary_select, v_sql_status_summary_delta, v_sql_status_summary_from
+ SET v_sql_status_summary_select = CONCAT(v_sql_status_summary_select, ',
+ CONCAT(
+ LEFT(s', v_output_count, '.Variable_value, ', v_status_summary_width, '),
+ IF(', REPLACE(v_no_delta_names, '%{COUNT}', v_output_count), ' AND s', v_output_count, '.Variable_value REGEXP ''^[0-9]+(\\\\.[0-9]+)?$'', CONCAT('' ('', ROUND(s', v_output_count, '.Variable_value/', v_output_time, ', 2), ''/sec)''), '''')
+ ) AS ''Output ', v_output_count, ''''),
+ v_sql_status_summary_from = CONCAT(v_sql_status_summary_from, '
+',
+ IF(v_output_count = 1, ' FROM ', ' INNER JOIN '),
+ v_table_name, ' s', v_output_count,
+ IF (v_output_count = 1, '', ' USING (Type, Variable_name)'));
+ IF (v_output_count > 1) THEN
+ SET v_sql_status_summary_delta = CONCAT(v_sql_status_summary_delta, ',
+ IF(', REPLACE(v_no_delta_names, '%{COUNT}', v_output_count), ' AND s', (v_output_count-1), '.Variable_value REGEXP ''^[0-9]+(\\\\.[0-9]+)?$'' AND s', v_output_count, '.Variable_value REGEXP ''^[0-9]+(\\\\.[0-9]+)?$'',
+ CONCAT(IF(s', (v_output_count-1), '.Variable_value REGEXP ''^[0-9]+\\\\.[0-9]+$'' OR s', v_output_count, '.Variable_value REGEXP ''^[0-9]+\\\\.[0-9]+$'',
+ ROUND((s', v_output_count, '.Variable_value-s', (v_output_count-1), '.Variable_value), 2),
+ (s', v_output_count, '.Variable_value-s', (v_output_count-1), '.Variable_value)
+ ),
+ '' ('', ROUND((s', v_output_count, '.Variable_value-s', (v_output_count-1), '.Variable_value)/(', v_output_time, '-', v_output_time_prev, '), 2), ''/sec)''
+ ),
+ ''''
+ ) AS ''Delta (', (v_output_count-1), ' -> ', v_output_count, ')''');
+ END IF;
+
+ SET v_output_time_prev = v_output_time;
+
+ IF (@sys.diagnostics.include_raw = 'ON') THEN
+ IF (v_has_metrics) THEN
+ SELECT 'SELECT * FROM sys.metrics' AS 'The following output is:';
+ ELSE
+ SELECT 'sys.metrics equivalent' AS 'The following output is:';
+ END IF;
+ -- Ensures that the output here is the same as the one used in the status summary at the end
+ CALL sys.execute_prepared_stmt(CONCAT('SELECT Type, Variable_name, Enabled, Variable_value FROM ', v_table_name, ' ORDER BY Type, Variable_name'));
+ END IF;
+
+ -- InnoDB
+ IF (v_has_innodb IN ('DEFAULT', 'YES')) THEN
+ SELECT 'SHOW ENGINE INNODB STATUS' AS 'The following output is:';
+ EXECUTE stmt_innodb_status;
+ SELECT 'InnoDB - Transactions' AS 'The following output is:';
+ SELECT * FROM information_schema.INNODB_TRX;
+ END IF;
+
+ -- NDBCluster
+ IF (v_has_ndb IN ('DEFAULT', 'YES')) THEN
+ SELECT 'SHOW ENGINE NDBCLUSTER STATUS' AS 'The following output is:';
+ EXECUTE stmt_ndbcluster_status;
+
+ SELECT 'ndbinfo.memoryusage' AS 'The following output is:';
+ SELECT node_id, memory_type, sys.format_bytes(used) AS used, used_pages, sys.format_bytes(total) AS total, total_pages,
+ ROUND(100*(used/total), 2) AS 'Used %'
+ FROM ndbinfo.memoryusage;
+
+ -- Loop over the ndbinfo tables (except memoryusage which was handled separately above).
+ -- The exact tables available are version dependent, so get the list from the Information Schema.
+ SET v_done = FALSE;
+ OPEN c_ndbinfo;
+ c_ndbinfo_loop: LOOP
+ FETCH c_ndbinfo INTO v_table_name;
+ IF v_done THEN
+ LEAVE c_ndbinfo_loop;
+ END IF;
+
+ SELECT CONCAT('SELECT * FROM ndbinfo.', v_table_name) AS 'The following output is:';
+ CALL sys.execute_prepared_stmt(CONCAT('SELECT * FROM `ndbinfo`.`', v_table_name, '`'));
+ END LOOP;
+ CLOSE c_ndbinfo;
+
+ SELECT * FROM information_schema.FILES;
+ END IF;
+
+ SELECT 'SELECT * FROM sys.processlist' AS 'The following output is:';
+ SELECT processlist.* FROM sys.processlist;
+
+ IF (v_has_ps = 'YES') THEN
+ -- latest_file_io
+ IF (sys.ps_is_consumer_enabled('events_waits_history_long') = 'YES') THEN
+ SELECT 'SELECT * FROM sys.latest_file_io' AS 'The following output is:';
+ SELECT * FROM sys.latest_file_io;
+ END IF;
+
+ -- current memory usage
+ IF (EXISTS(SELECT 1 FROM performance_schema.setup_instruments WHERE NAME LIKE 'memory/%' AND ENABLED = 'YES')) THEN
+ SELECT 'SELECT * FROM sys.memory_by_host_by_current_bytes' AS 'The following output is:';
+ SELECT * FROM sys.memory_by_host_by_current_bytes;
+
+ SELECT 'SELECT * FROM sys.memory_by_thread_by_current_bytes' AS 'The following output is:';
+ SELECT * FROM sys.memory_by_thread_by_current_bytes;
+
+ SELECT 'SELECT * FROM sys.memory_by_user_by_current_bytes' AS 'The following output is:';
+ SELECT * FROM sys.memory_by_user_by_current_bytes;
+
+ SELECT 'SELECT * FROM sys.memory_global_by_current_bytes' AS 'The following output is:';
+ SELECT * FROM sys.memory_global_by_current_bytes;
+ END IF;
+ END IF;
+
+ SET v_runtime = (UNIX_TIMESTAMP(NOW(2)) - v_start);
+ UNTIL (v_runtime + in_interval >= in_max_runtime) END REPEAT;
+
+ -- Get Performance Schema status
+ IF (v_has_ps = 'YES') THEN
+ SELECT 'SHOW ENGINE PERFORMANCE_SCHEMA STATUS' AS 'The following output is:';
+ EXECUTE stmt_ps_status;
+ END IF;
+
+ -- Deallocate prepared statements
+ IF (v_has_innodb IN ('DEFAULT', 'YES')) THEN
+ DEALLOCATE PREPARE stmt_innodb_status;
+ END IF;
+ IF (v_has_ps = 'YES') THEN
+ DEALLOCATE PREPARE stmt_ps_status;
+ END IF;
+ IF (v_has_ndb IN ('DEFAULT', 'YES')) THEN
+ DEALLOCATE PREPARE stmt_ndbcluster_status;
+ END IF;
+
+
+ SELECT '
+
+============================
+
+ Schema Information
+
+============================
+
+' AS '';
+
+ SELECT COUNT(*) AS 'Total Number of Tables' FROM information_schema.TABLES;
+
+ -- The cost of information_schema.TABLES.DATA_LENGTH depends mostly on the number of tables
+ IF (@sys.diagnostics.allow_i_s_tables = 'ON') THEN
+ SELECT 'Storage Engine Usage' AS 'The following output is:';
+ SELECT ENGINE, COUNT(*) AS NUM_TABLES,
+ sys.format_bytes(SUM(DATA_LENGTH)) AS DATA_LENGTH,
+ sys.format_bytes(SUM(INDEX_LENGTH)) AS INDEX_LENGTH,
+ sys.format_bytes(SUM(DATA_LENGTH+INDEX_LENGTH)) AS TOTAL
+ FROM information_schema.TABLES
+ GROUP BY ENGINE;
+
+ SELECT 'Schema Object Overview' AS 'The following output is:';
+ SELECT * FROM sys.schema_object_overview;
+
+ SELECT 'Tables without a PRIMARY KEY' AS 'The following output is:';
+ SELECT TABLES.TABLE_SCHEMA, ENGINE, COUNT(*) AS NumTables
+ FROM information_schema.TABLES
+ LEFT OUTER JOIN information_schema.STATISTICS ON STATISTICS.TABLE_SCHEMA = TABLES.TABLE_SCHEMA
+ AND STATISTICS.TABLE_NAME = TABLES.TABLE_NAME
+ AND STATISTICS.INDEX_NAME = 'PRIMARY'
+ WHERE STATISTICS.TABLE_NAME IS NULL
+ AND TABLES.TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
+ AND TABLES.TABLE_TYPE = 'BASE TABLE'
+ GROUP BY TABLES.TABLE_SCHEMA, ENGINE;
+ END IF;
+
+ IF (v_has_ps = 'YES') THEN
+ SELECT 'Unused Indexes' AS 'The following output is:';
+ SELECT object_schema, COUNT(*) AS NumUnusedIndexes
+ FROM performance_schema.table_io_waits_summary_by_index_usage
+ WHERE index_name IS NOT NULL
+ AND count_star = 0
+ AND object_schema NOT IN ('mysql', 'sys')
+ AND index_name != 'PRIMARY'
+ GROUP BY object_schema;
+ END IF;
+
+ IF (v_has_ps = 'YES') THEN
+ SELECT '
+
+=========================
+
+ Overall Status
+
+=========================
+
+' AS '';
+
+ SELECT 'CALL sys.ps_statement_avg_latency_histogram()' AS 'The following output is:';
+ CALL sys.ps_statement_avg_latency_histogram();
+
+ CALL sys.statement_performance_analyzer('snapshot', NULL, NULL);
+ CALL sys.statement_performance_analyzer('overall', NULL, 'with_runtimes_in_95th_percentile');
+
+ SET @sys.diagnostics.sql = REPLACE(@sys.diagnostics.sql_gen_query_template, '%{OUTPUT}', 'end');
+ IF (@sys.debug = 'ON') THEN
+ SELECT 'The following query will be used to generate the query for each sys view' AS 'Debug';
+ SELECT @sys.diagnostics.sql AS 'Debug';
+ END IF;
+ PREPARE stmt_gen_query FROM @sys.diagnostics.sql;
+
+ SET v_done = FALSE;
+ OPEN c_sysviews_w_delta;
+ c_sysviews_w_delta_loop: LOOP
+ FETCH c_sysviews_w_delta INTO v_table_name;
+ IF v_done THEN
+ LEAVE c_sysviews_w_delta_loop;
+ END IF;
+
+ IF (@sys.debug = 'ON') THEN
+ SELECT CONCAT('The following queries are for storing the final content of ', v_table_name) AS 'Debug';
+ END IF;
+
+ CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE IF EXISTS `tmp_', v_table_name, '_end`'));
+ CALL sys.execute_prepared_stmt(CONCAT('CREATE TEMPORARY TABLE `tmp_', v_table_name, '_end` SELECT * FROM `sys`.`x$', v_table_name, '`'));
+
+ IF (@sys.diagnostics.include_raw = 'ON') THEN
+ SET @sys.diagnostics.table_name = CONCAT('x$', v_table_name);
+ EXECUTE stmt_gen_query USING @sys.diagnostics.table_name;
+ -- If necessary add ORDER BY and LIMIT
+ SELECT CONCAT(@sys.diagnostics.sql_select,
+ IF(order_by IS NOT NULL, CONCAT('\n ORDER BY ', REPLACE(order_by, '%{TABLE}', CONCAT('tmp_', v_table_name, '_end'))), ''),
+ IF(limit_rows IS NOT NULL, CONCAT('\n LIMIT ', limit_rows), '')
+ )
+ INTO @sys.diagnostics.sql_select
+ FROM tmp_sys_views_delta
+ WHERE TABLE_NAME = v_table_name;
+ SELECT CONCAT('Overall ', v_table_name) AS 'The following output is:';
+ CALL sys.execute_prepared_stmt(@sys.diagnostics.sql_select);
+ END IF;
+ END LOOP;
+ CLOSE c_sysviews_w_delta;
+
+ DEALLOCATE PREPARE stmt_gen_query;
+
+
+ SELECT '
+
+======================
+
+ Delta Status
+
+======================
+
+' AS '';
+
+ CALL sys.statement_performance_analyzer('delta', 'tmp_digests_start', 'with_runtimes_in_95th_percentile');
+ CALL sys.statement_performance_analyzer('cleanup', NULL, NULL);
+
+ DROP TEMPORARY TABLE tmp_digests_start;
+
+ -- @sys.diagnostics.sql_gen_query_delta is defined near the to together with @sys.diagnostics.sql_gen_query_template
+ IF (@sys.debug = 'ON') THEN
+ SELECT 'The following query will be used to generate the query for each sys view delta' AS 'Debug';
+ SELECT @sys.diagnostics.sql_gen_query_delta AS 'Debug';
+ END IF;
+ PREPARE stmt_gen_query_delta FROM @sys.diagnostics.sql_gen_query_delta;
+
+ SET v_old_group_concat_max_len = @@session.group_concat_max_len;
+ SET @@session.group_concat_max_len = 2048;
+ SET v_done = FALSE;
+ OPEN c_sysviews_w_delta;
+ c_sysviews_w_delta_loop: LOOP
+ FETCH c_sysviews_w_delta INTO v_table_name;
+ IF v_done THEN
+ LEAVE c_sysviews_w_delta_loop;
+ END IF;
+
+ SET @sys.diagnostics.table_name = v_table_name;
+ EXECUTE stmt_gen_query_delta USING @sys.diagnostics.table_name;
+ -- If necessary add WHERE, ORDER BY, and LIMIT
+ SELECT CONCAT(@sys.diagnostics.sql_select,
+ IF(where_delta IS NOT NULL, CONCAT('\n WHERE ', where_delta), ''),
+ IF(order_by_delta IS NOT NULL, CONCAT('\n ORDER BY ', order_by_delta), ''),
+ IF(limit_rows IS NOT NULL, CONCAT('\n LIMIT ', limit_rows), '')
+ )
+ INTO @sys.diagnostics.sql_select
+ FROM tmp_sys_views_delta
+ WHERE TABLE_NAME = v_table_name;
+
+ SELECT CONCAT('Delta ', v_table_name) AS 'The following output is:';
+ CALL sys.execute_prepared_stmt(@sys.diagnostics.sql_select);
+
+ CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE `tmp_', v_table_name, '_end`'));
+ CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE `tmp_', v_table_name, '_start`'));
+ END LOOP;
+ CLOSE c_sysviews_w_delta;
+ SET @@session.group_concat_max_len = v_old_group_concat_max_len;
+
+ DEALLOCATE PREPARE stmt_gen_query_delta;
+ DROP TEMPORARY TABLE tmp_sys_views_delta;
+ END IF;
+
+ IF (v_has_metrics) THEN
+ SELECT 'SELECT * FROM sys.metrics' AS 'The following output is:';
+ ELSE
+ SELECT 'sys.metrics equivalent' AS 'The following output is:';
+ END IF;
+ CALL sys.execute_prepared_stmt(
+ CONCAT(v_sql_status_summary_select, v_sql_status_summary_delta, ', Type, s1.Enabled', v_sql_status_summary_from,
+ '
+ ORDER BY Type, Variable_name'
+ )
+ );
+
+ -- Remove all the metrics temporary tables again
+ SET v_count = 0;
+ WHILE (v_count < v_output_count) DO
+ SET v_count = v_count + 1;
+ SET v_table_name = CONCAT('tmp_metrics_', v_count);
+ CALL sys.execute_prepared_stmt(CONCAT('DROP TEMPORARY TABLE IF EXISTS ', v_table_name));
+ END WHILE;
+
+ IF (in_auto_config <> 'current') THEN
+ CALL sys.ps_setup_reload_saved();
+ SET sql_log_bin = @log_bin;
+ END IF;
+
+ -- Reset the @sys.diagnostics.% user variables internal to this procedure
+ SET @sys.diagnostics.output_time = NULL,
+ @sys.diagnostics.sql = NULL,
+ @sys.diagnostics.sql_gen_query_delta = NULL,
+ @sys.diagnostics.sql_gen_query_template = NULL,
+ @sys.diagnostics.sql_select = NULL,
+ @sys.diagnostics.table_name = NULL;
+
+ -- Restore INSTRUMENTED for this thread
+ IF (v_this_thread_enabled = 'YES') THEN
+ CALL sys.ps_setup_enable_thread(CONNECTION_ID());
+ END IF;
+
+ IF (@log_bin = 1) THEN
+ SET sql_log_bin = @log_bin;
+ END IF;
+END$$
+
+DELIMITER ; \ No newline at end of file
diff --git a/scripts/sys_schema/procedures/execute_prepared_stmt.sql b/scripts/sys_schema/procedures/execute_prepared_stmt.sql
new file mode 100644
index 00000000..8e975b90
--- /dev/null
+++ b/scripts/sys_schema/procedures/execute_prepared_stmt.sql
@@ -0,0 +1,89 @@
+-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS execute_prepared_stmt;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE execute_prepared_stmt (
+ IN in_query longtext CHARACTER SET UTF8
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Takes the query in the argument and executes it using a prepared statement. The prepared statement is deallocated,
+ so the procedure is mainly useful for executing one off dynamically created queries.
+
+ The sys_execute_prepared_stmt prepared statement name is used for the query and is required not to exist.
+
+
+ Parameters
+ -----------
+
+ in_query (longtext CHARACTER SET UTF8):
+ The query to execute.
+
+
+ Configuration Options
+ ----------------------
+
+ sys.debug
+ Whether to provide debugging output.
+ Default is ''OFF''. Set to ''ON'' to include.
+
+
+ Example
+ --------
+
+ mysql> CALL sys.execute_prepared_stmt(''SELECT * FROM sys.sys_config'');
+ +------------------------+-------+---------------------+--------+
+ | variable | value | set_time | set_by |
+ +------------------------+-------+---------------------+--------+
+ | statement_truncate_len | 64 | 2015-06-30 13:06:00 | NULL |
+ +------------------------+-------+---------------------+--------+
+ 1 row in set (0.00 sec)
+
+ Query OK, 0 rows affected (0.00 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ READS SQL DATA
+BEGIN
+ -- Set configuration options
+ IF (@sys.debug IS NULL) THEN
+ SET @sys.debug = sys.sys_get_config('debug', 'OFF');
+ END IF;
+
+ -- Verify the query exists
+ -- The shortest possible query is "DO 1"
+ IF (in_query IS NULL OR LENGTH(in_query) < 4) THEN
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = "The @sys.execute_prepared_stmt.sql must contain a query";
+ END IF;
+
+ SET @sys.execute_prepared_stmt.sql = in_query;
+
+ IF (@sys.debug = 'ON') THEN
+ SELECT @sys.execute_prepared_stmt.sql AS 'Debug';
+ END IF;
+ PREPARE sys_execute_prepared_stmt FROM @sys.execute_prepared_stmt.sql;
+ EXECUTE sys_execute_prepared_stmt;
+ DEALLOCATE PREPARE sys_execute_prepared_stmt;
+
+ SET @sys.execute_prepared_stmt.sql = NULL;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_disable_background_threads.sql b/scripts/sys_schema/procedures/ps_setup_disable_background_threads.sql
new file mode 100644
index 00000000..0c316bc7
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_disable_background_threads.sql
@@ -0,0 +1,54 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_disable_background_threads;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_disable_background_threads ()
+ COMMENT '
+ Description
+ -----------
+
+ Disable all background thread instrumentation within Performance Schema.
+
+ Parameters
+ -----------
+
+ None.
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_disable_background_threads();
+ +--------------------------------+
+ | summary |
+ +--------------------------------+
+ | Disabled 18 background threads |
+ +--------------------------------+
+ 1 row in set (0.00 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ UPDATE performance_schema.threads
+ SET instrumented = 'NO'
+ WHERE type = 'BACKGROUND';
+
+ SELECT CONCAT('Disabled ', @rows := ROW_COUNT(), ' background thread', IF(@rows != 1, 's', '')) AS summary;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_disable_consumer.sql b/scripts/sys_schema/procedures/ps_setup_disable_consumer.sql
new file mode 100644
index 00000000..bdebd62e
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_disable_consumer.sql
@@ -0,0 +1,70 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_disable_consumer;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_disable_consumer (
+ IN consumer VARCHAR(128)
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Disables consumers within Performance Schema
+ matching the input pattern.
+
+ Parameters
+ -----------
+
+ consumer (VARCHAR(128)):
+ A LIKE pattern match (using "%consumer%") of consumers to disable
+
+ Example
+ -----------
+
+ To disable all consumers:
+
+ mysql> CALL sys.ps_setup_disable_consumer(\'\');
+ +--------------------------+
+ | summary |
+ +--------------------------+
+ | Disabled 15 consumers |
+ +--------------------------+
+ 1 row in set (0.02 sec)
+
+ To disable just the event_stage consumers:
+
+ mysql> CALL sys.ps_setup_disable_comsumers(\'stage\');
+ +------------------------+
+ | summary |
+ +------------------------+
+ | Disabled 3 consumers |
+ +------------------------+
+ 1 row in set (0.00 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ UPDATE performance_schema.setup_consumers
+ SET enabled = 'NO'
+ WHERE name LIKE CONCAT('%', consumer, '%');
+
+ SELECT CONCAT('Disabled ', @rows := ROW_COUNT(), ' consumer', IF(@rows != 1, 's', '')) AS summary;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_disable_instrument.sql b/scripts/sys_schema/procedures/ps_setup_disable_instrument.sql
new file mode 100644
index 00000000..14fe4d86
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_disable_instrument.sql
@@ -0,0 +1,80 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_disable_instrument;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_disable_instrument (
+ IN in_pattern VARCHAR(128)
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Disables instruments within Performance Schema
+ matching the input pattern.
+
+ Parameters
+ -----------
+
+ in_pattern (VARCHAR(128)):
+ A LIKE pattern match (using "%in_pattern%") of events to disable
+
+ Example
+ -----------
+
+ To disable all mutex instruments:
+
+ mysql> CALL sys.ps_setup_disable_instrument(\'wait/synch/mutex\');
+ +--------------------------+
+ | summary |
+ +--------------------------+
+ | Disabled 155 instruments |
+ +--------------------------+
+ 1 row in set (0.02 sec)
+
+ To disable just a specific TCP/IP based network IO instrument:
+
+ mysql> CALL sys.ps_setup_disable_instrument(\'wait/io/socket/sql/server_tcpip_socket\');
+ +------------------------+
+ | summary |
+ +------------------------+
+ | Disabled 1 instruments |
+ +------------------------+
+ 1 row in set (0.00 sec)
+
+ To disable all instruments:
+
+ mysql> CALL sys.ps_setup_disable_instrument(\'\');
+ +--------------------------+
+ | summary |
+ +--------------------------+
+ | Disabled 547 instruments |
+ +--------------------------+
+ 1 row in set (0.01 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ UPDATE performance_schema.setup_instruments
+ SET enabled = 'NO', timed = 'NO'
+ WHERE name LIKE CONCAT('%', in_pattern, '%');
+
+ SELECT CONCAT('Disabled ', @rows := ROW_COUNT(), ' instrument', IF(@rows != 1, 's', '')) AS summary;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_disable_thread.sql b/scripts/sys_schema/procedures/ps_setup_disable_thread.sql
new file mode 100644
index 00000000..fe0bb862
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_disable_thread.sql
@@ -0,0 +1,68 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_disable_thread;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_disable_thread (
+ IN in_connection_id BIGINT
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Disable the given connection/thread in Performance Schema.
+
+ Parameters
+ -----------
+
+ in_connection_id (BIGINT):
+ The connection ID (PROCESSLIST_ID from performance_schema.threads
+ or the ID shown within SHOW PROCESSLIST)
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_disable_thread(3);
+ +-------------------+
+ | summary |
+ +-------------------+
+ | Disabled 1 thread |
+ +-------------------+
+ 1 row in set (0.01 sec)
+
+ To disable the current connection:
+
+ mysql> CALL sys.ps_setup_disable_thread(CONNECTION_ID());
+ +-------------------+
+ | summary |
+ +-------------------+
+ | Disabled 1 thread |
+ +-------------------+
+ 1 row in set (0.00 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ UPDATE performance_schema.threads
+ SET instrumented = 'NO'
+ WHERE processlist_id = in_connection_id;
+
+ SELECT CONCAT('Disabled ', @rows := ROW_COUNT(), ' thread', IF(@rows != 1, 's', '')) AS summary;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_enable_background_threads.sql b/scripts/sys_schema/procedures/ps_setup_enable_background_threads.sql
new file mode 100644
index 00000000..ddca06b1
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_enable_background_threads.sql
@@ -0,0 +1,54 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_enable_background_threads;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_enable_background_threads ()
+ COMMENT '
+ Description
+ -----------
+
+ Enable all background thread instrumentation within Performance Schema.
+
+ Parameters
+ -----------
+
+ None.
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_enable_background_threads();
+ +-------------------------------+
+ | summary |
+ +-------------------------------+
+ | Enabled 18 background threads |
+ +-------------------------------+
+ 1 row in set (0.00 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ UPDATE performance_schema.threads
+ SET instrumented = 'YES'
+ WHERE type = 'BACKGROUND';
+
+ SELECT CONCAT('Enabled ', @rows := ROW_COUNT(), ' background thread', IF(@rows != 1, 's', '')) AS summary;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_enable_consumer.sql b/scripts/sys_schema/procedures/ps_setup_enable_consumer.sql
new file mode 100644
index 00000000..66138604
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_enable_consumer.sql
@@ -0,0 +1,74 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_enable_consumer;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_enable_consumer (
+ IN consumer VARCHAR(128)
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Enables consumers within Performance Schema
+ matching the input pattern.
+
+ Parameters
+ -----------
+
+ consumer (VARCHAR(128)):
+ A LIKE pattern match (using "%consumer%") of consumers to enable
+
+ Example
+ -----------
+
+ To enable all consumers:
+
+ mysql> CALL sys.ps_setup_enable_consumer(\'\');
+ +-------------------------+
+ | summary |
+ +-------------------------+
+ | Enabled 10 consumers |
+ +-------------------------+
+ 1 row in set (0.02 sec)
+
+ Query OK, 0 rows affected (0.02 sec)
+
+ To enable just "waits" consumers:
+
+ mysql> CALL sys.ps_setup_enable_consumer(\'waits\');
+ +-----------------------+
+ | summary |
+ +-----------------------+
+ | Enabled 3 consumers |
+ +-----------------------+
+ 1 row in set (0.00 sec)
+
+ Query OK, 0 rows affected (0.00 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ UPDATE performance_schema.setup_consumers
+ SET enabled = 'YES'
+ WHERE name LIKE CONCAT('%', consumer, '%');
+
+ SELECT CONCAT('Enabled ', @rows := ROW_COUNT(), ' consumer', IF(@rows != 1, 's', '')) AS summary;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_enable_instrument.sql b/scripts/sys_schema/procedures/ps_setup_enable_instrument.sql
new file mode 100644
index 00000000..964307de
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_enable_instrument.sql
@@ -0,0 +1,86 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_enable_instrument;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_enable_instrument (
+ IN in_pattern VARCHAR(128)
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Enables instruments within Performance Schema
+ matching the input pattern.
+
+ Parameters
+ -----------
+
+ in_pattern (VARCHAR(128)):
+ A LIKE pattern match (using "%in_pattern%") of events to enable
+
+ Example
+ -----------
+
+ To enable all mutex instruments:
+
+ mysql> CALL sys.ps_setup_enable_instrument(\'wait/synch/mutex\');
+ +-------------------------+
+ | summary |
+ +-------------------------+
+ | Enabled 155 instruments |
+ +-------------------------+
+ 1 row in set (0.02 sec)
+
+ Query OK, 0 rows affected (0.02 sec)
+
+ To enable just a specific TCP/IP based network IO instrument:
+
+ mysql> CALL sys.ps_setup_enable_instrument(\'wait/io/socket/sql/server_tcpip_socket\');
+ +-----------------------+
+ | summary |
+ +-----------------------+
+ | Enabled 1 instruments |
+ +-----------------------+
+ 1 row in set (0.00 sec)
+
+ Query OK, 0 rows affected (0.00 sec)
+
+ To enable all instruments:
+
+ mysql> CALL sys.ps_setup_enable_instrument(\'\');
+ +-------------------------+
+ | summary |
+ +-------------------------+
+ | Enabled 547 instruments |
+ +-------------------------+
+ 1 row in set (0.01 sec)
+
+ Query OK, 0 rows affected (0.01 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ UPDATE performance_schema.setup_instruments
+ SET enabled = 'YES', timed = 'YES'
+ WHERE name LIKE CONCAT('%', in_pattern, '%');
+
+ SELECT CONCAT('Enabled ', @rows := ROW_COUNT(), ' instrument', IF(@rows != 1, 's', '')) AS summary;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_enable_thread.sql b/scripts/sys_schema/procedures/ps_setup_enable_thread.sql
new file mode 100644
index 00000000..15385fc8
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_enable_thread.sql
@@ -0,0 +1,68 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_enable_thread;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_enable_thread (
+ IN in_connection_id BIGINT
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Enable the given connection/thread in Performance Schema.
+
+ Parameters
+ -----------
+
+ in_connection_id (BIGINT):
+ The connection ID (PROCESSLIST_ID from performance_schema.threads
+ or the ID shown within SHOW PROCESSLIST)
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_enable_thread(3);
+ +------------------+
+ | summary |
+ +------------------+
+ | Enabled 1 thread |
+ +------------------+
+ 1 row in set (0.01 sec)
+
+ To enable the current connection:
+
+ mysql> CALL sys.ps_setup_enable_thread(CONNECTION_ID());
+ +------------------+
+ | summary |
+ +------------------+
+ | Enabled 1 thread |
+ +------------------+
+ 1 row in set (0.00 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ UPDATE performance_schema.threads
+ SET instrumented = 'YES'
+ WHERE processlist_id = in_connection_id;
+
+ SELECT CONCAT('Enabled ', @rows := ROW_COUNT(), ' thread', IF(@rows != 1, 's', '')) AS summary;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_reload_saved.sql b/scripts/sys_schema/procedures/ps_setup_reload_saved.sql
new file mode 100644
index 00000000..38d463b1
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_reload_saved.sql
@@ -0,0 +1,146 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_reload_saved;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_reload_saved ()
+ COMMENT '
+ Description
+ -----------
+
+ Reloads a saved Performance Schema configuration,
+ so that you can alter the setup for debugging purposes,
+ but restore it to a previous state.
+
+ Use the companion procedure - ps_setup_save(), to
+ save a configuration.
+
+ Requires the SUPER privilege for "SET sql_log_bin = 0;".
+
+ Parameters
+ -----------
+
+ None.
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_save();
+ Query OK, 0 rows affected (0.08 sec)
+
+ mysql> UPDATE performance_schema.setup_instruments SET enabled = \'YES\', timed = \'YES\';
+ Query OK, 547 rows affected (0.40 sec)
+ Rows matched: 784 Changed: 547 Warnings: 0
+
+ /* Run some tests that need more detailed instrumentation here */
+
+ mysql> CALL sys.ps_setup_reload_saved();
+ Query OK, 0 rows affected (0.32 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ DECLARE v_done bool DEFAULT FALSE;
+ DECLARE v_lock_result INT;
+ DECLARE v_lock_used_by BIGINT;
+ DECLARE v_signal_message TEXT;
+ DECLARE EXIT HANDLER FOR SQLEXCEPTION
+ BEGIN
+ SIGNAL SQLSTATE VALUE '90001'
+ SET MESSAGE_TEXT = 'An error occurred, was sys.ps_setup_save() run before this procedure?';
+ END;
+
+ SET @log_bin := @@sql_log_bin;
+ SET sql_log_bin = 0;
+
+ SELECT IS_USED_LOCK('sys.ps_setup_save') INTO v_lock_used_by;
+
+ IF (v_lock_used_by != CONNECTION_ID()) THEN
+ SET v_signal_message = CONCAT('The sys.ps_setup_save lock is currently owned by ', v_lock_used_by);
+ SIGNAL SQLSTATE VALUE '90002'
+ SET MESSAGE_TEXT = v_signal_message;
+ END IF;
+
+ DELETE FROM performance_schema.setup_actors;
+ INSERT INTO performance_schema.setup_actors SELECT * FROM tmp_setup_actors;
+
+ BEGIN
+ -- Workaround for http://bugs.mysql.com/bug.php?id=70025
+ DECLARE v_name varchar(64);
+ DECLARE v_enabled enum('YES', 'NO');
+ DECLARE c_consumers CURSOR FOR SELECT NAME, ENABLED FROM tmp_setup_consumers;
+ DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
+
+ SET v_done = FALSE;
+ OPEN c_consumers;
+ c_consumers_loop: LOOP
+ FETCH c_consumers INTO v_name, v_enabled;
+ IF v_done THEN
+ LEAVE c_consumers_loop;
+ END IF;
+
+ UPDATE performance_schema.setup_consumers
+ SET ENABLED = v_enabled
+ WHERE NAME = v_name;
+ END LOOP;
+ CLOSE c_consumers;
+ END;
+
+ UPDATE performance_schema.setup_instruments
+ INNER JOIN tmp_setup_instruments USING (NAME)
+ SET performance_schema.setup_instruments.ENABLED = tmp_setup_instruments.ENABLED,
+ performance_schema.setup_instruments.TIMED = tmp_setup_instruments.TIMED;
+ BEGIN
+ -- Workaround for http://bugs.mysql.com/bug.php?id=70025
+ DECLARE v_thread_id bigint unsigned;
+ DECLARE v_instrumented enum('YES', 'NO');
+ DECLARE c_threads CURSOR FOR SELECT THREAD_ID, INSTRUMENTED FROM tmp_threads;
+ DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
+
+ SET v_done = FALSE;
+ OPEN c_threads;
+ c_threads_loop: LOOP
+ FETCH c_threads INTO v_thread_id, v_instrumented;
+ IF v_done THEN
+ LEAVE c_threads_loop;
+ END IF;
+
+ UPDATE performance_schema.threads
+ SET INSTRUMENTED = v_instrumented
+ WHERE THREAD_ID = v_thread_id;
+ END LOOP;
+ CLOSE c_threads;
+ END;
+
+ UPDATE performance_schema.threads
+ SET INSTRUMENTED = IF(PROCESSLIST_USER IS NOT NULL,
+ sys.ps_is_account_enabled(PROCESSLIST_HOST, PROCESSLIST_USER),
+ 'YES')
+ WHERE THREAD_ID NOT IN (SELECT THREAD_ID FROM tmp_threads);
+
+ DROP TEMPORARY TABLE tmp_setup_actors;
+ DROP TEMPORARY TABLE tmp_setup_consumers;
+ DROP TEMPORARY TABLE tmp_setup_instruments;
+ DROP TEMPORARY TABLE tmp_threads;
+
+ SELECT RELEASE_LOCK('sys.ps_setup_save') INTO v_lock_result;
+
+ SET sql_log_bin = @log_bin;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_reset_to_default.sql b/scripts/sys_schema/procedures/ps_setup_reset_to_default.sql
new file mode 100644
index 00000000..b626fae8
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_reset_to_default.sql
@@ -0,0 +1,148 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_reset_to_default;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_reset_to_default (
+ IN in_verbose BOOLEAN
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Resets the Performance Schema setup to the default settings.
+
+ Parameters
+ -----------
+
+ in_verbose (BOOLEAN):
+ Whether to print each setup stage (including the SQL) whilst running.
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_reset_to_default(true)\\G
+ *************************** 1. row ***************************
+ status: Resetting: setup_actors
+ DELETE
+ FROM performance_schema.setup_actors
+ WHERE NOT (HOST = \'%\' AND USER = \'%\' AND ROLE = \'%\')
+ 1 row in set (0.00 sec)
+
+ *************************** 1. row ***************************
+ status: Resetting: setup_actors
+ INSERT IGNORE INTO performance_schema.setup_actors
+ VALUES (\'%\', \'%\', \'%\')
+ 1 row in set (0.00 sec)
+ ...
+
+ mysql> CALL sys.ps_setup_reset_to_default(false)\\G
+ Query OK, 0 rows affected (0.00 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ SET @query = 'DELETE
+ FROM performance_schema.setup_actors
+ WHERE NOT (HOST = ''%'' AND USER = ''%'' AND ROLE = ''%'')';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_actors\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'INSERT IGNORE INTO performance_schema.setup_actors
+ VALUES (''%'', ''%'', ''%'')';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_actors\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'UPDATE performance_schema.setup_instruments
+ SET ENABLED = sys.ps_is_instrument_default_enabled(NAME),
+ TIMED = sys.ps_is_instrument_default_timed(NAME)';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_instruments\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'UPDATE performance_schema.setup_consumers
+ SET ENABLED = IF(NAME IN (''events_statements_current'', ''global_instrumentation'', ''thread_instrumentation'', ''statements_digest''), ''YES'', ''NO'')';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_consumers\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'DELETE
+ FROM performance_schema.setup_objects
+ WHERE NOT (OBJECT_TYPE = ''TABLE'' AND OBJECT_NAME = ''%''
+ AND (OBJECT_SCHEMA = ''mysql'' AND ENABLED = ''NO'' AND TIMED = ''NO'' )
+ OR (OBJECT_SCHEMA = ''performance_schema'' AND ENABLED = ''NO'' AND TIMED = ''NO'' )
+ OR (OBJECT_SCHEMA = ''information_schema'' AND ENABLED = ''NO'' AND TIMED = ''NO'' )
+ OR (OBJECT_SCHEMA = ''%'' AND ENABLED = ''YES'' AND TIMED = ''YES''))';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_objects\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'INSERT IGNORE INTO performance_schema.setup_objects
+ VALUES (''TABLE'', ''mysql'' , ''%'', ''NO'' , ''NO'' ),
+ (''TABLE'', ''performance_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''TABLE'', ''information_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''TABLE'', ''%'' , ''%'', ''YES'', ''YES'')';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_objects\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'UPDATE performance_schema.threads
+ SET INSTRUMENTED = ''YES''';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: threads\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_reset_to_default_57.sql b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57.sql
new file mode 100644
index 00000000..9f2ea468
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57.sql
@@ -0,0 +1,165 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_reset_to_default;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_reset_to_default (
+ IN in_verbose BOOLEAN
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Resets the Performance Schema setup to the default settings.
+
+ Parameters
+ -----------
+
+ in_verbose (BOOLEAN):
+ Whether to print each setup stage (including the SQL) whilst running.
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_reset_to_default(true)\\G
+ *************************** 1. row ***************************
+ status: Resetting: setup_actors
+ DELETE
+ FROM performance_schema.setup_actors
+ WHERE NOT (HOST = \'%\' AND USER = \'%\' AND ROLE = \'%\')
+ 1 row in set (0.00 sec)
+
+ *************************** 1. row ***************************
+ status: Resetting: setup_actors
+ INSERT IGNORE INTO performance_schema.setup_actors
+ VALUES (\'%\', \'%\', \'%\')
+ 1 row in set (0.00 sec)
+ ...
+
+ mysql> CALL sys.ps_setup_reset_to_default(false)\\G
+ Query OK, 0 rows affected (0.00 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ SET @query = 'DELETE
+ FROM performance_schema.setup_actors
+ WHERE NOT (HOST = ''%'' AND USER = ''%'' AND ROLE = ''%'')';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_actors\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'INSERT IGNORE INTO performance_schema.setup_actors
+ VALUES (''%'', ''%'', ''%'', ''YES'', ''YES'')';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_actors\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'UPDATE performance_schema.setup_instruments
+ SET ENABLED = sys.ps_is_instrument_default_enabled(NAME),
+ TIMED = sys.ps_is_instrument_default_timed(NAME)';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_instruments\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'UPDATE performance_schema.setup_consumers
+ SET ENABLED = IF(NAME IN (''events_statements_current'', ''events_transactions_current'', ''global_instrumentation'', ''thread_instrumentation'', ''statements_digest''), ''YES'', ''NO'')';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_consumers\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'DELETE
+ FROM performance_schema.setup_objects
+ WHERE NOT (OBJECT_TYPE IN (''EVENT'', ''FUNCTION'', ''PROCEDURE'', ''TABLE'', ''TRIGGER'') AND OBJECT_NAME = ''%''
+ AND (OBJECT_SCHEMA = ''mysql'' AND ENABLED = ''NO'' AND TIMED = ''NO'' )
+ OR (OBJECT_SCHEMA = ''performance_schema'' AND ENABLED = ''NO'' AND TIMED = ''NO'' )
+ OR (OBJECT_SCHEMA = ''information_schema'' AND ENABLED = ''NO'' AND TIMED = ''NO'' )
+ OR (OBJECT_SCHEMA = ''%'' AND ENABLED = ''YES'' AND TIMED = ''YES''))';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_objects\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'INSERT IGNORE INTO performance_schema.setup_objects
+ VALUES (''EVENT'' , ''mysql'' , ''%'', ''NO'' , ''NO'' ),
+ (''EVENT'' , ''performance_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''EVENT'' , ''information_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''EVENT'' , ''%'' , ''%'', ''YES'', ''YES''),
+ (''FUNCTION'' , ''mysql'' , ''%'', ''NO'' , ''NO'' ),
+ (''FUNCTION'' , ''performance_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''FUNCTION'' , ''information_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''FUNCTION'' , ''%'' , ''%'', ''YES'', ''YES''),
+ (''PROCEDURE'', ''mysql'' , ''%'', ''NO'' , ''NO'' ),
+ (''PROCEDURE'', ''performance_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''PROCEDURE'', ''information_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''PROCEDURE'', ''%'' , ''%'', ''YES'', ''YES''),
+ (''TABLE'' , ''mysql'' , ''%'', ''NO'' , ''NO'' ),
+ (''TABLE'' , ''performance_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''TABLE'' , ''information_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''TABLE'' , ''%'' , ''%'', ''YES'', ''YES''),
+ (''TRIGGER'' , ''mysql'' , ''%'', ''NO'' , ''NO'' ),
+ (''TRIGGER'' , ''performance_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''TRIGGER'' , ''information_schema'', ''%'', ''NO'' , ''NO'' ),
+ (''TRIGGER'' , ''%'' , ''%'', ''YES'', ''YES'')';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: setup_objects\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+
+ SET @query = 'UPDATE performance_schema.threads
+ SET INSTRUMENTED = ''YES''';
+
+ IF (in_verbose) THEN
+ SELECT CONCAT('Resetting: threads\n', REPLACE(@query, ' ', '')) AS status;
+ END IF;
+
+ PREPARE reset_stmt FROM @query;
+ EXECUTE reset_stmt;
+ DEALLOCATE PREPARE reset_stmt;
+END$$
+
+DELIMITER ;
+
diff --git a/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_after.sql b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_after.sql
new file mode 100644
index 00000000..f2c41b01
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_after.sql
@@ -0,0 +1,16 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+SET @@session.sql_mode = @old_sql_mode;
diff --git a/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_before.sql b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_before.sql
new file mode 100644
index 00000000..37001886
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_reset_to_default_57_before.sql
@@ -0,0 +1,17 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+-- Because of bug 11750980/bug 41686, set the sql_mode to ''
+SET @old_sql_mode = @@session.sql_mode, @@session.sql_mode = '';
diff --git a/scripts/sys_schema/procedures/ps_setup_save.sql b/scripts/sys_schema/procedures/ps_setup_save.sql
new file mode 100644
index 00000000..b7843ecd
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_save.sql
@@ -0,0 +1,97 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_save;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_save (
+ IN in_timeout INT
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Saves the current configuration of Performance Schema,
+ so that you can alter the setup for debugging purposes,
+ but restore it to a previous state.
+
+ Use the companion procedure - ps_setup_reload_saved(), to
+ restore the saved config.
+
+ The named lock "sys.ps_setup_save" is taken before the
+ current configuration is saved. If the attempt to get the named
+ lock times out, an error occurs.
+
+ The lock is released after the settings have been restored by
+ calling ps_setup_reload_saved().
+
+ Requires the SUPER privilege for "SET sql_log_bin = 0;".
+
+ Parameters
+ -----------
+
+ in_timeout INT
+ The timeout in seconds used when trying to obtain the lock.
+ A negative timeout means infinite timeout.
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_save(-1);
+ Query OK, 0 rows affected (0.08 sec)
+
+ mysql> UPDATE performance_schema.setup_instruments
+ -> SET enabled = \'YES\', timed = \'YES\';
+ Query OK, 547 rows affected (0.40 sec)
+ Rows matched: 784 Changed: 547 Warnings: 0
+
+ /* Run some tests that need more detailed instrumentation here */
+
+ mysql> CALL sys.ps_setup_reload_saved();
+ Query OK, 0 rows affected (0.32 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ DECLARE v_lock_result INT;
+
+ SET @log_bin := @@sql_log_bin;
+ SET sql_log_bin = 0;
+
+ SELECT GET_LOCK('sys.ps_setup_save', in_timeout) INTO v_lock_result;
+
+ IF v_lock_result THEN
+ DROP TEMPORARY TABLE IF EXISTS tmp_setup_actors;
+ DROP TEMPORARY TABLE IF EXISTS tmp_setup_consumers;
+ DROP TEMPORARY TABLE IF EXISTS tmp_setup_instruments;
+ DROP TEMPORARY TABLE IF EXISTS tmp_threads;
+
+ CREATE TEMPORARY TABLE tmp_setup_actors AS SELECT * FROM performance_schema.setup_actors;
+ CREATE TEMPORARY TABLE tmp_setup_consumers AS SELECT * FROM performance_schema.setup_consumers;
+ CREATE TEMPORARY TABLE tmp_setup_instruments AS SELECT * FROM performance_schema.setup_instruments;
+ CREATE TEMPORARY TABLE tmp_threads (THREAD_ID bigint unsigned NOT NULL PRIMARY KEY, INSTRUMENTED enum('YES','NO') NOT NULL);
+
+ INSERT INTO tmp_threads SELECT THREAD_ID, INSTRUMENTED FROM performance_schema.threads;
+ ELSE
+ SIGNAL SQLSTATE VALUE '90000'
+ SET MESSAGE_TEXT = 'Could not lock the sys.ps_setup_save user lock, another thread has a saved configuration';
+ END IF;
+
+ SET sql_log_bin = @log_bin;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_show_disabled.sql b/scripts/sys_schema/procedures/ps_setup_show_disabled.sql
new file mode 100644
index 00000000..82c69840
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_show_disabled.sql
@@ -0,0 +1,163 @@
+-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_show_disabled;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_disabled (
+ IN in_show_instruments BOOLEAN,
+ IN in_show_threads BOOLEAN
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Shows all currently disable Performance Schema configuration.
+
+ Disabled users is only available for MySQL 5.7.6 and later.
+ In earlier versions it was only possible to enable users.
+
+ Parameters
+ -----------
+
+ in_show_instruments (BOOLEAN):
+ Whether to print disabled instruments (can print many items)
+
+ in_show_threads (BOOLEAN):
+ Whether to print disabled threads
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_show_disabled(TRUE, TRUE);
+ +----------------------------+
+ | performance_schema_enabled |
+ +----------------------------+
+ | 1 |
+ +----------------------------+
+ 1 row in set (0.00 sec)
+
+ +--------------------+
+ | disabled_users |
+ +--------------------+
+ | \'mark\'@\'localhost\' |
+ +--------------------+
+ 1 row in set (0.00 sec)
+
+ +-------------+----------------------+---------+-------+
+ | object_type | objects | enabled | timed |
+ +-------------+----------------------+---------+-------+
+ | EVENT | mysql.% | NO | NO |
+ | EVENT | performance_schema.% | NO | NO |
+ | EVENT | information_schema.% | NO | NO |
+ | FUNCTION | mysql.% | NO | NO |
+ | FUNCTION | performance_schema.% | NO | NO |
+ | FUNCTION | information_schema.% | NO | NO |
+ | PROCEDURE | mysql.% | NO | NO |
+ | PROCEDURE | performance_schema.% | NO | NO |
+ | PROCEDURE | information_schema.% | NO | NO |
+ | TABLE | mysql.% | NO | NO |
+ | TABLE | performance_schema.% | NO | NO |
+ | TABLE | information_schema.% | NO | NO |
+ | TRIGGER | mysql.% | NO | NO |
+ | TRIGGER | performance_schema.% | NO | NO |
+ | TRIGGER | information_schema.% | NO | NO |
+ +-------------+----------------------+---------+-------+
+ 15 rows in set (0.00 sec)
+
+ +----------------------------------+
+ | disabled_consumers |
+ +----------------------------------+
+ | events_stages_current |
+ | events_stages_history |
+ | events_stages_history_long |
+ | events_statements_history |
+ | events_statements_history_long |
+ | events_transactions_history |
+ | events_transactions_history_long |
+ | events_waits_current |
+ | events_waits_history |
+ | events_waits_history_long |
+ +----------------------------------+
+ 10 rows in set (0.00 sec)
+
+ Empty set (0.00 sec)
+
+ +---------------------------------------------------------------------------------------+-------+
+ | disabled_instruments | timed |
+ +---------------------------------------------------------------------------------------+-------+
+ | wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc | NO |
+ | wait/synch/mutex/sql/LOCK_des_key_file | NO |
+ | wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_commit | NO |
+ ...
+ | memory/sql/servers_cache | NO |
+ | memory/sql/udf_mem | NO |
+ | wait/lock/metadata/sql/mdl | NO |
+ +---------------------------------------------------------------------------------------+-------+
+ 547 rows in set (0.00 sec)
+
+ Query OK, 0 rows affected (0.01 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ READS SQL DATA
+BEGIN
+ SELECT @@performance_schema AS performance_schema_enabled;
+
+ -- In 5.7.6 and later the setup_actors table has an ENABLED column to
+ -- specify whether the actor is enabled. Before that all actors matched
+ -- in the setup_actors table were enabled.
+ -- So only execute the query in 5.7.6+
+ /*!50706
+ SELECT CONCAT('\'', user, '\'@\'', host, '\'') AS disabled_users
+ FROM performance_schema.setup_actors
+ WHERE enabled = 'NO'
+ ORDER BY disabled_users;
+ */
+
+ SELECT object_type,
+ CONCAT(object_schema, '.', object_name) AS objects,
+ enabled,
+ timed
+ FROM performance_schema.setup_objects
+ WHERE enabled = 'NO'
+ ORDER BY object_type, objects;
+
+ SELECT name AS disabled_consumers
+ FROM performance_schema.setup_consumers
+ WHERE enabled = 'NO'
+ ORDER BY disabled_consumers;
+
+ IF (in_show_threads) THEN
+ SELECT IF(name = 'thread/sql/one_connection',
+ CONCAT(processlist_user, '@', processlist_host),
+ REPLACE(name, 'thread/', '')) AS disabled_threads,
+ TYPE AS thread_type
+ FROM performance_schema.threads
+ WHERE INSTRUMENTED = 'NO'
+ ORDER BY disabled_threads;
+ END IF;
+
+ IF (in_show_instruments) THEN
+ SELECT name AS disabled_instruments,
+ timed
+ FROM performance_schema.setup_instruments
+ WHERE enabled = 'NO'
+ ORDER BY disabled_instruments;
+ END IF;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_show_disabled_consumers.sql b/scripts/sys_schema/procedures/ps_setup_show_disabled_consumers.sql
new file mode 100644
index 00000000..4c913efd
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_show_disabled_consumers.sql
@@ -0,0 +1,57 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_show_disabled_consumers;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_disabled_consumers ()
+ COMMENT '
+ Description
+ -----------
+
+ Shows all currently disabled consumers.
+
+ Parameters
+ -----------
+
+ None
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_show_disabled_consumers();
+
+ +---------------------------+
+ | disabled_consumers |
+ +---------------------------+
+ | events_statements_current |
+ | global_instrumentation |
+ | thread_instrumentation |
+ | statements_digest |
+ +---------------------------+
+ 4 rows in set (0.05 sec)
+ '
+ SQL SECURITY INVOKER
+ DETERMINISTIC
+ READS SQL DATA
+BEGIN
+ SELECT name AS disabled_consumers
+ FROM performance_schema.setup_consumers
+ WHERE enabled = 'NO'
+ ORDER BY disabled_consumers;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_show_disabled_instruments.sql b/scripts/sys_schema/procedures/ps_setup_show_disabled_instruments.sql
new file mode 100644
index 00000000..45fe7c08
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_show_disabled_instruments.sql
@@ -0,0 +1,47 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_show_disabled_instruments;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_disabled_instruments ()
+ COMMENT '
+ Description
+ -----------
+
+ Shows all currently disabled instruments.
+
+ Parameters
+ -----------
+
+ None
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_show_disabled_instruments();
+ '
+ SQL SECURITY INVOKER
+ DETERMINISTIC
+ READS SQL DATA
+BEGIN
+ SELECT name AS disabled_instruments, timed
+ FROM performance_schema.setup_instruments
+ WHERE enabled = 'NO'
+ ORDER BY disabled_instruments;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_show_enabled.sql b/scripts/sys_schema/procedures/ps_setup_show_enabled.sql
new file mode 100644
index 00000000..8e7c0506
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_show_enabled.sql
@@ -0,0 +1,166 @@
+-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_show_enabled;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_enabled (
+ IN in_show_instruments BOOLEAN,
+ IN in_show_threads BOOLEAN
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Shows all currently enabled Performance Schema configuration.
+
+ Parameters
+ -----------
+
+ in_show_instruments (BOOLEAN):
+ Whether to print enabled instruments (can print many items)
+
+ in_show_threads (BOOLEAN):
+ Whether to print enabled threads
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_show_enabled(TRUE, TRUE);
+ +----------------------------+
+ | performance_schema_enabled |
+ +----------------------------+
+ | 1 |
+ +----------------------------+
+ 1 row in set (0.00 sec)
+
+ +---------------+
+ | enabled_users |
+ +---------------+
+ | \'%\'@\'%\' |
+ +---------------+
+ 1 row in set (0.01 sec)
+
+ +-------------+---------+---------+-------+
+ | object_type | objects | enabled | timed |
+ +-------------+---------+---------+-------+
+ | EVENT | %.% | YES | YES |
+ | FUNCTION | %.% | YES | YES |
+ | PROCEDURE | %.% | YES | YES |
+ | TABLE | %.% | YES | YES |
+ | TRIGGER | %.% | YES | YES |
+ +-------------+---------+---------+-------+
+ 5 rows in set (0.01 sec)
+
+ +---------------------------+
+ | enabled_consumers |
+ +---------------------------+
+ | events_statements_current |
+ | global_instrumentation |
+ | thread_instrumentation |
+ | statements_digest |
+ +---------------------------+
+ 4 rows in set (0.05 sec)
+
+ +---------------------------------+-------------+
+ | enabled_threads | thread_type |
+ +---------------------------------+-------------+
+ | sql/main | BACKGROUND |
+ | sql/thread_timer_notifier | BACKGROUND |
+ | innodb/io_ibuf_thread | BACKGROUND |
+ | innodb/io_log_thread | BACKGROUND |
+ | innodb/io_read_thread | BACKGROUND |
+ | innodb/io_read_thread | BACKGROUND |
+ | innodb/io_write_thread | BACKGROUND |
+ | innodb/io_write_thread | BACKGROUND |
+ | innodb/page_cleaner_thread | BACKGROUND |
+ | innodb/srv_lock_timeout_thread | BACKGROUND |
+ | innodb/srv_error_monitor_thread | BACKGROUND |
+ | innodb/srv_monitor_thread | BACKGROUND |
+ | innodb/srv_master_thread | BACKGROUND |
+ | innodb/srv_purge_thread | BACKGROUND |
+ | innodb/srv_worker_thread | BACKGROUND |
+ | innodb/srv_worker_thread | BACKGROUND |
+ | innodb/srv_worker_thread | BACKGROUND |
+ | innodb/buf_dump_thread | BACKGROUND |
+ | innodb/dict_stats_thread | BACKGROUND |
+ | sql/signal_handler | BACKGROUND |
+ | sql/compress_gtid_table | FOREGROUND |
+ | root@localhost | FOREGROUND |
+ +---------------------------------+-------------+
+ 22 rows in set (0.01 sec)
+
+ +-------------------------------------+-------+
+ | enabled_instruments | timed |
+ +-------------------------------------+-------+
+ | wait/io/file/sql/map | YES |
+ | wait/io/file/sql/binlog | YES |
+ ...
+ | statement/com/Error | YES |
+ | statement/com/ | YES |
+ | idle | YES |
+ +-------------------------------------+-------+
+ 210 rows in set (0.08 sec)
+
+ Query OK, 0 rows affected (0.89 sec)
+ '
+ SQL SECURITY INVOKER
+ DETERMINISTIC
+ READS SQL DATA
+BEGIN
+ SELECT @@performance_schema AS performance_schema_enabled;
+
+ -- In 5.7.6 and later the setup_actors table has an ENABLED column to
+ -- specify whether the actor is enabled. Before that all actors matched
+ -- in the setup_actors table were enabled.
+ SELECT CONCAT('\'', user, '\'@\'', host, '\'') AS enabled_users
+ FROM performance_schema.setup_actors
+ WHERE enabled = 'YES'
+ ORDER BY enabled_users;
+
+ SELECT object_type,
+ CONCAT(object_schema, '.', object_name) AS objects,
+ enabled,
+ timed
+ FROM performance_schema.setup_objects
+ WHERE enabled = 'YES'
+ ORDER BY object_type, objects;
+
+ SELECT name AS enabled_consumers
+ FROM performance_schema.setup_consumers
+ WHERE enabled = 'YES'
+ ORDER BY enabled_consumers;
+
+ IF (in_show_threads) THEN
+ SELECT IF(name = 'thread/sql/one_connection',
+ CONCAT(processlist_user, '@', processlist_host),
+ REPLACE(name, 'thread/', '')) AS enabled_threads,
+ TYPE AS thread_type
+ FROM performance_schema.threads
+ WHERE INSTRUMENTED = 'YES' AND name <> 'thread/innodb/thread_pool_thread'
+ ORDER BY enabled_threads;
+ END IF;
+
+ IF (in_show_instruments) THEN
+ SELECT name AS enabled_instruments,
+ timed
+ FROM performance_schema.setup_instruments
+ WHERE enabled = 'YES'
+ ORDER BY enabled_instruments;
+ END IF;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_show_enabled_consumers.sql b/scripts/sys_schema/procedures/ps_setup_show_enabled_consumers.sql
new file mode 100644
index 00000000..57ec2b75
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_show_enabled_consumers.sql
@@ -0,0 +1,57 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_show_enabled_consumers;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_enabled_consumers ()
+ COMMENT '
+ Description
+ -----------
+
+ Shows all currently enabled consumers.
+
+ Parameters
+ -----------
+
+ None
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_show_enabled_consumers();
+
+ +---------------------------+
+ | enabled_consumers |
+ +---------------------------+
+ | events_statements_current |
+ | global_instrumentation |
+ | thread_instrumentation |
+ | statements_digest |
+ +---------------------------+
+ 4 rows in set (0.05 sec)
+ '
+ SQL SECURITY INVOKER
+ DETERMINISTIC
+ READS SQL DATA
+BEGIN
+ SELECT name AS enabled_consumers
+ FROM performance_schema.setup_consumers
+ WHERE enabled = 'YES'
+ ORDER BY enabled_consumers;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_setup_show_enabled_instruments.sql b/scripts/sys_schema/procedures/ps_setup_show_enabled_instruments.sql
new file mode 100644
index 00000000..d8cfb108
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_setup_show_enabled_instruments.sql
@@ -0,0 +1,47 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_setup_show_enabled_instruments;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_show_enabled_instruments ()
+ COMMENT '
+ Description
+ -----------
+
+ Shows all currently enabled instruments.
+
+ Parameters
+ -----------
+
+ None
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_setup_show_enabled_instruments();
+ '
+ SQL SECURITY INVOKER
+ DETERMINISTIC
+ READS SQL DATA
+BEGIN
+ SELECT name AS enabled_instruments, timed
+ FROM performance_schema.setup_instruments
+ WHERE enabled = 'YES'
+ ORDER BY enabled_instruments;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_statement_avg_latency_histogram.sql b/scripts/sys_schema/procedures/ps_statement_avg_latency_histogram.sql
new file mode 100644
index 00000000..e57cbc1d
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_statement_avg_latency_histogram.sql
@@ -0,0 +1,230 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_statement_avg_latency_histogram;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_statement_avg_latency_histogram ()
+ COMMENT '
+ Description
+ -----------
+
+ Outputs a textual histogram graph of the average latency values
+ across all normalized queries tracked within the Performance Schema
+ events_statements_summary_by_digest table.
+
+ Can be used to show a very high level picture of what kind of
+ latency distribution statements running within this instance have.
+
+ Parameters
+ -----------
+
+ None.
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_statement_avg_latency_histogram()\\G
+ *************************** 1. row ***************************
+ Performance Schema Statement Digest Average Latency Histogram:
+
+ . = 1 unit
+ * = 2 units
+ # = 3 units
+
+ (0 - 38ms) 240 | ################################################################################
+ (38 - 77ms) 38 | ......................................
+ (77 - 115ms) 3 | ...
+ (115 - 154ms) 62 | *******************************
+ (154 - 192ms) 3 | ...
+ (192 - 231ms) 0 |
+ (231 - 269ms) 0 |
+ (269 - 307ms) 0 |
+ (307 - 346ms) 0 |
+ (346 - 384ms) 1 | .
+ (384 - 423ms) 1 | .
+ (423 - 461ms) 0 |
+ (461 - 499ms) 0 |
+ (499 - 538ms) 0 |
+ (538 - 576ms) 0 |
+ (576 - 615ms) 1 | .
+
+ Total Statements: 350; Buckets: 16; Bucket Size: 38 ms;
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ READS SQL DATA
+BEGIN
+SELECT CONCAT('\n',
+ '\n . = 1 unit',
+ '\n * = 2 units',
+ '\n # = 3 units\n',
+ @label := CONCAT(@label_inner := CONCAT('\n(0 - ',
+ ROUND((@bucket_size := (SELECT ROUND((MAX(avg_us) - MIN(avg_us)) / (@buckets := 16)) AS size
+ FROM sys.x$ps_digest_avg_latency_distribution)) / (@unit_div := 1000)),
+ (@unit := 'ms'), ')'),
+ REPEAT(' ', (@max_label_size := ((1 + LENGTH(ROUND((@bucket_size * 15) / @unit_div)) + 3 + LENGTH(ROUND(@bucket_size * 16) / @unit_div)) + 1)) - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us <= @bucket_size), 0)),
+ REPEAT(' ', (@max_label_len := (@max_label_size + LENGTH((@total_queries := (SELECT SUM(cnt) FROM sys.x$ps_digest_avg_latency_distribution)))) + 1) - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < (@one_unit := 40), '.', IF(@count_in_bucket < (@two_unit := 80), '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND(@bucket_size / @unit_div), ' - ', ROUND((@bucket_size * 2) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size AND b1.avg_us <= @bucket_size * 2), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 2) / @unit_div), ' - ', ROUND((@bucket_size * 3) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 2 AND b1.avg_us <= @bucket_size * 3), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 3) / @unit_div), ' - ', ROUND((@bucket_size * 4) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 3 AND b1.avg_us <= @bucket_size * 4), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 4) / @unit_div), ' - ', ROUND((@bucket_size * 5) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 4 AND b1.avg_us <= @bucket_size * 5), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 5) / @unit_div), ' - ', ROUND((@bucket_size * 6) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 5 AND b1.avg_us <= @bucket_size * 6), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 6) / @unit_div), ' - ', ROUND((@bucket_size * 7) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 6 AND b1.avg_us <= @bucket_size * 7), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 7) / @unit_div), ' - ', ROUND((@bucket_size * 8) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 7 AND b1.avg_us <= @bucket_size * 8), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 8) / @unit_div), ' - ', ROUND((@bucket_size * 9) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 8 AND b1.avg_us <= @bucket_size * 9), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 9) / @unit_div), ' - ', ROUND((@bucket_size * 10) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 9 AND b1.avg_us <= @bucket_size * 10), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 10) / @unit_div), ' - ', ROUND((@bucket_size * 11) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 10 AND b1.avg_us <= @bucket_size * 11), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 11) / @unit_div), ' - ', ROUND((@bucket_size * 12) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 11 AND b1.avg_us <= @bucket_size * 12), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 12) / @unit_div), ' - ', ROUND((@bucket_size * 13) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 12 AND b1.avg_us <= @bucket_size * 13), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 13) / @unit_div), ' - ', ROUND((@bucket_size * 14) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 13 AND b1.avg_us <= @bucket_size * 14), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 14) / @unit_div), ' - ', ROUND((@bucket_size * 15) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 14 AND b1.avg_us <= @bucket_size * 15), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+ @label := CONCAT(@label_inner := CONCAT('\n(', ROUND((@bucket_size * 15) / @unit_div), ' - ', ROUND((@bucket_size * 16) / @unit_div), @unit, ')'),
+ REPEAT(' ', @max_label_size - LENGTH(@label_inner)),
+ @count_in_bucket := IFNULL((SELECT SUM(cnt)
+ FROM sys.x$ps_digest_avg_latency_distribution AS b1
+ WHERE b1.avg_us > @bucket_size * 15 AND b1.avg_us <= @bucket_size * 16), 0)),
+ REPEAT(' ', @max_label_len - LENGTH(@label)), '| ',
+ IFNULL(REPEAT(IF(@count_in_bucket < @one_unit, '.', IF(@count_in_bucket < @two_unit, '*', '#')),
+ IF(@count_in_bucket < @one_unit, @count_in_bucket,
+ IF(@count_in_bucket < @two_unit, @count_in_bucket / 2, @count_in_bucket / 3))), ''),
+
+ '\n\n Total Statements: ', @total_queries, '; Buckets: ', @buckets , '; Bucket Size: ', ROUND(@bucket_size / @unit_div) , ' ', @unit, ';\n'
+
+ ) AS `Performance Schema Statement Digest Average Latency Histogram`;
+
+END $$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_trace_statement_digest.sql b/scripts/sys_schema/procedures/ps_trace_statement_digest.sql
new file mode 100644
index 00000000..f9bb4d3b
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_trace_statement_digest.sql
@@ -0,0 +1,324 @@
+-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_trace_statement_digest;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_trace_statement_digest (
+ IN in_digest VARCHAR(32),
+ IN in_runtime INT,
+ IN in_interval DECIMAL(2,2),
+ IN in_start_fresh BOOLEAN,
+ IN in_auto_enable BOOLEAN
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Traces all instrumentation within Performance Schema for a specific
+ Statement Digest.
+
+ When finding a statement of interest within the
+ performance_schema.events_statements_summary_by_digest table, feed
+ the DIGEST MD5 value in to this procedure, set how long to poll for,
+ and at what interval to poll, and it will generate a report of all
+ statistics tracked within Performance Schema for that digest for the
+ interval.
+
+ It will also attempt to generate an EXPLAIN for the longest running
+ example of the digest during the interval. Note this may fail, as:
+
+ * Performance Schema truncates long SQL_TEXT values (and hence the
+ EXPLAIN will fail due to parse errors)
+ * the default schema is sys (so tables that are not fully qualified
+ in the query may not be found)
+ * some queries such as SHOW are not supported in EXPLAIN.
+
+ When the EXPLAIN fails, the error will be ignored and no EXPLAIN
+ output generated.
+
+ Requires the SUPER privilege for "SET sql_log_bin = 0;".
+
+ Parameters
+ -----------
+
+ in_digest (VARCHAR(32)):
+ The statement digest identifier you would like to analyze
+ in_runtime (INT):
+ The number of seconds to run analysis for
+ in_interval (DECIMAL(2,2)):
+ The interval (in seconds, may be fractional) at which to try
+ and take snapshots
+ in_start_fresh (BOOLEAN):
+ Whether to TRUNCATE the events_statements_history_long and
+ events_stages_history_long tables before starting
+ in_auto_enable (BOOLEAN):
+ Whether to automatically turn on required consumers
+
+ Example
+ -----------
+
+ mysql> call ps_trace_statement_digest(\'891ec6860f98ba46d89dd20b0c03652c\', 10, 0.1, true, true);
+ +--------------------+
+ | SUMMARY STATISTICS |
+ +--------------------+
+ | SUMMARY STATISTICS |
+ +--------------------+
+ 1 row in set (9.11 sec)
+
+ +------------+-----------+-----------+-----------+---------------+------------+------------+
+ | executions | exec_time | lock_time | rows_sent | rows_examined | tmp_tables | full_scans |
+ +------------+-----------+-----------+-----------+---------------+------------+------------+
+ | 21 | 4.11 ms | 2.00 ms | 0 | 21 | 0 | 0 |
+ +------------+-----------+-----------+-----------+---------------+------------+------------+
+ 1 row in set (9.11 sec)
+
+ +------------------------------------------+-------+-----------+
+ | event_name | count | latency |
+ +------------------------------------------+-------+-----------+
+ | stage/sql/checking query cache for query | 16 | 724.37 us |
+ | stage/sql/statistics | 16 | 546.92 us |
+ | stage/sql/freeing items | 18 | 520.11 us |
+ | stage/sql/init | 51 | 466.80 us |
+ ...
+ | stage/sql/cleaning up | 18 | 11.92 us |
+ | stage/sql/executing | 16 | 6.95 us |
+ +------------------------------------------+-------+-----------+
+ 17 rows in set (9.12 sec)
+
+ +---------------------------+
+ | LONGEST RUNNING STATEMENT |
+ +---------------------------+
+ | LONGEST RUNNING STATEMENT |
+ +---------------------------+
+ 1 row in set (9.16 sec)
+
+ +-----------+-----------+-----------+-----------+---------------+------------+-----------+
+ | thread_id | exec_time | lock_time | rows_sent | rows_examined | tmp_tables | full_scan |
+ +-----------+-----------+-----------+-----------+---------------+------------+-----------+
+ | 166646 | 618.43 us | 1.00 ms | 0 | 1 | 0 | 0 |
+ +-----------+-----------+-----------+-----------+---------------+------------+-----------+
+ 1 row in set (9.16 sec)
+
+ // Truncated for clarity...
+ +-----------------------------------------------------------------+
+ | sql_text |
+ +-----------------------------------------------------------------+
+ | select hibeventhe0_.id as id1382_, hibeventhe0_.createdTime ... |
+ +-----------------------------------------------------------------+
+ 1 row in set (9.17 sec)
+
+ +------------------------------------------+-----------+
+ | event_name | latency |
+ +------------------------------------------+-----------+
+ | stage/sql/init | 8.61 us |
+ | stage/sql/Waiting for query cache lock | 453.23 us |
+ | stage/sql/init | 331.07 ns |
+ | stage/sql/checking query cache for query | 43.04 us |
+ ...
+ | stage/sql/freeing items | 30.46 us |
+ | stage/sql/cleaning up | 662.13 ns |
+ +------------------------------------------+-----------+
+ 18 rows in set (9.23 sec)
+
+ +----+-------------+--------------+-------+---------------+-----------+---------+-------------+------+-------+
+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+ +----+-------------+--------------+-------+---------------+-----------+---------+-------------+------+-------+
+ | 1 | SIMPLE | hibeventhe0_ | const | fixedTime | fixedTime | 775 | const,const | 1 | NULL |
+ +----+-------------+--------------+-------+---------------+-----------+---------+-------------+------+-------+
+ 1 row in set (9.27 sec)
+
+ Query OK, 0 rows affected (9.28 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+
+ DECLARE v_start_fresh BOOLEAN DEFAULT false;
+ DECLARE v_auto_enable BOOLEAN DEFAULT false;
+ DECLARE v_explain BOOLEAN DEFAULT true;
+ DECLARE v_this_thread_enabed ENUM('YES', 'NO');
+ DECLARE v_runtime INT DEFAULT 0;
+ DECLARE v_start INT DEFAULT 0;
+ DECLARE v_found_stmts INT;
+
+ SET @log_bin := @@sql_log_bin;
+ SET sql_log_bin = 0;
+
+ -- Do not track the current thread, it will kill the stack
+ SELECT INSTRUMENTED INTO v_this_thread_enabed FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID();
+ CALL sys.ps_setup_disable_thread(CONNECTION_ID());
+
+ DROP TEMPORARY TABLE IF EXISTS stmt_trace;
+ CREATE TEMPORARY TABLE stmt_trace (
+ thread_id BIGINT UNSIGNED,
+ timer_start BIGINT UNSIGNED,
+ event_id BIGINT UNSIGNED,
+ sql_text longtext,
+ timer_wait BIGINT UNSIGNED,
+ lock_time BIGINT UNSIGNED,
+ errors BIGINT UNSIGNED,
+ mysql_errno INT,
+ rows_sent BIGINT UNSIGNED,
+ rows_affected BIGINT UNSIGNED,
+ rows_examined BIGINT UNSIGNED,
+ created_tmp_tables BIGINT UNSIGNED,
+ created_tmp_disk_tables BIGINT UNSIGNED,
+ no_index_used BIGINT UNSIGNED,
+ PRIMARY KEY (thread_id, timer_start)
+ );
+
+ DROP TEMPORARY TABLE IF EXISTS stmt_stages;
+ CREATE TEMPORARY TABLE stmt_stages (
+ event_id BIGINT UNSIGNED,
+ stmt_id BIGINT UNSIGNED,
+ event_name VARCHAR(128),
+ timer_wait BIGINT UNSIGNED,
+ PRIMARY KEY (event_id)
+ );
+
+ SET v_start_fresh = in_start_fresh;
+ IF v_start_fresh THEN
+ TRUNCATE TABLE performance_schema.events_statements_history_long;
+ TRUNCATE TABLE performance_schema.events_stages_history_long;
+ END IF;
+
+ SET v_auto_enable = in_auto_enable;
+ IF v_auto_enable THEN
+ CALL sys.ps_setup_save(0);
+
+ UPDATE performance_schema.threads
+ SET INSTRUMENTED = IF(PROCESSLIST_ID IS NOT NULL, 'YES', 'NO');
+
+ -- Only the events_statements_history_long and events_stages_history_long tables and their ancestors are needed
+ UPDATE performance_schema.setup_consumers
+ SET ENABLED = 'YES'
+ WHERE NAME NOT LIKE '%\_history'
+ AND NAME NOT LIKE 'events_wait%'
+ AND NAME NOT LIKE 'events_transactions%'
+ AND NAME <> 'statements_digest';
+
+ UPDATE performance_schema.setup_instruments
+ SET ENABLED = 'YES',
+ TIMED = 'YES'
+ WHERE NAME LIKE 'statement/%' OR NAME LIKE 'stage/%';
+ END IF;
+
+ WHILE v_runtime < in_runtime DO
+ SELECT UNIX_TIMESTAMP() INTO v_start;
+
+ INSERT IGNORE INTO stmt_trace
+ SELECT thread_id, timer_start, event_id, sql_text, timer_wait, lock_time, errors, mysql_errno,
+ rows_sent, rows_affected, rows_examined, created_tmp_tables, created_tmp_disk_tables, no_index_used
+ FROM performance_schema.events_statements_history_long
+ WHERE digest = in_digest;
+
+ INSERT IGNORE INTO stmt_stages
+ SELECT stages.event_id, stmt_trace.event_id,
+ stages.event_name, stages.timer_wait
+ FROM performance_schema.events_stages_history_long AS stages
+ JOIN stmt_trace ON stages.nesting_event_id = stmt_trace.event_id;
+
+ SELECT SLEEP(in_interval) INTO @sleep;
+ SET v_runtime = v_runtime + (UNIX_TIMESTAMP() - v_start);
+ END WHILE;
+
+ SELECT "SUMMARY STATISTICS";
+
+ SELECT COUNT(*) executions,
+ sys.format_time(SUM(timer_wait)) AS exec_time,
+ sys.format_time(SUM(lock_time)) AS lock_time,
+ SUM(rows_sent) AS rows_sent,
+ SUM(rows_affected) AS rows_affected,
+ SUM(rows_examined) AS rows_examined,
+ SUM(created_tmp_tables) AS tmp_tables,
+ SUM(no_index_used) AS full_scans
+ FROM stmt_trace;
+
+ SELECT event_name,
+ COUNT(*) as count,
+ sys.format_time(SUM(timer_wait)) as latency
+ FROM stmt_stages
+ GROUP BY event_name
+ ORDER BY SUM(timer_wait) DESC;
+
+ SELECT "LONGEST RUNNING STATEMENT";
+
+ SELECT thread_id,
+ sys.format_time(timer_wait) AS exec_time,
+ sys.format_time(lock_time) AS lock_time,
+ rows_sent,
+ rows_affected,
+ rows_examined,
+ created_tmp_tables AS tmp_tables,
+ no_index_used AS full_scan
+ FROM stmt_trace
+ ORDER BY timer_wait DESC LIMIT 1;
+
+ SELECT sql_text
+ FROM stmt_trace
+ ORDER BY timer_wait DESC LIMIT 1;
+
+ SELECT sql_text, event_id INTO @sql, @sql_id
+ FROM stmt_trace
+ ORDER BY timer_wait DESC LIMIT 1;
+
+ IF (@sql_id IS NOT NULL) THEN
+ SELECT event_name,
+ sys.format_time(timer_wait) as latency
+ FROM stmt_stages
+ WHERE stmt_id = @sql_id
+ ORDER BY event_id;
+ END IF;
+
+ DROP TEMPORARY TABLE stmt_trace;
+ DROP TEMPORARY TABLE stmt_stages;
+
+ IF (@sql IS NOT NULL) THEN
+ SET @stmt := CONCAT("EXPLAIN FORMAT=JSON ", @sql);
+ BEGIN
+ -- Not all queries support EXPLAIN, so catch the cases that are
+ -- not supported. Currently that includes cases where the table
+ -- is not fully qualified and is not in the default schema for this
+ -- procedure as it's not possible to change the default schema inside
+ -- a procedure.
+ --
+ -- Errno = 1064: You have an error in your SQL syntax
+ -- Errno = 1146: Table '...' doesn't exist
+ DECLARE CONTINUE HANDLER FOR 1064, 1146 SET v_explain = false;
+
+ PREPARE explain_stmt FROM @stmt;
+ END;
+
+ IF (v_explain) THEN
+ EXECUTE explain_stmt;
+ DEALLOCATE PREPARE explain_stmt;
+ END IF;
+ END IF;
+
+ IF v_auto_enable THEN
+ CALL sys.ps_setup_reload_saved();
+ END IF;
+ -- Restore INSTRUMENTED for this thread
+ IF (v_this_thread_enabed = 'YES') THEN
+ CALL sys.ps_setup_enable_thread(CONNECTION_ID());
+ END IF;
+
+ SET sql_log_bin = @log_bin;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_trace_thread.sql b/scripts/sys_schema/procedures/ps_trace_thread.sql
new file mode 100644
index 00000000..1a2ede79
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_trace_thread.sql
@@ -0,0 +1,321 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_trace_thread;
+
+DELIMITER $$
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_trace_thread (
+ IN in_thread_id BIGINT UNSIGNED,
+ IN in_outfile VARCHAR(255),
+ IN in_max_runtime DECIMAL(20,2),
+ IN in_interval DECIMAL(20,2),
+ IN in_start_fresh BOOLEAN,
+ IN in_auto_setup BOOLEAN,
+ IN in_debug BOOLEAN
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Dumps all data within Performance Schema for an instrumented thread,
+ to create a DOT formatted graph file.
+
+ Each resultset returned from the procedure should be used for a complete graph
+
+ Requires the SUPER privilege for "SET sql_log_bin = 0;".
+
+ Parameters
+ -----------
+
+ in_thread_id (BIGINT UNSIGNED):
+ The thread that you would like a stack trace for
+ in_outfile (VARCHAR(255)):
+ The filename the dot file will be written to
+ in_max_runtime (DECIMAL(20,2)):
+ The maximum time to keep collecting data.
+ Use NULL to get the default which is 60 seconds.
+ in_interval (DECIMAL(20,2)):
+ How long to sleep between data collections.
+ Use NULL to get the default which is 1 second.
+ in_start_fresh (BOOLEAN):
+ Whether to reset all Performance Schema data before tracing.
+ in_auto_setup (BOOLEAN):
+ Whether to disable all other threads and enable all consumers/instruments.
+ This will also reset the settings at the end of the run.
+ in_debug (BOOLEAN):
+ Whether you would like to include file:lineno in the graph
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_trace_thread(25, CONCAT(\'/tmp/stack-\', REPLACE(NOW(), \' \', \'-\'), \'.dot\'), NULL, NULL, TRUE, TRUE, TRUE);
+ +-------------------+
+ | summary |
+ +-------------------+
+ | Disabled 1 thread |
+ +-------------------+
+ 1 row in set (0.00 sec)
+
+ +---------------------------------------------+
+ | Info |
+ +---------------------------------------------+
+ | Data collection starting for THREAD_ID = 25 |
+ +---------------------------------------------+
+ 1 row in set (0.03 sec)
+
+ +-----------------------------------------------------------+
+ | Info |
+ +-----------------------------------------------------------+
+ | Stack trace written to /tmp/stack-2014-02-16-21:18:41.dot |
+ +-----------------------------------------------------------+
+ 1 row in set (60.07 sec)
+
+ +-------------------------------------------------------------------+
+ | Convert to PDF |
+ +-------------------------------------------------------------------+
+ | dot -Tpdf -o /tmp/stack_25.pdf /tmp/stack-2014-02-16-21:18:41.dot |
+ +-------------------------------------------------------------------+
+ 1 row in set (60.07 sec)
+
+ +-------------------------------------------------------------------+
+ | Convert to PNG |
+ +-------------------------------------------------------------------+
+ | dot -Tpng -o /tmp/stack_25.png /tmp/stack-2014-02-16-21:18:41.dot |
+ +-------------------------------------------------------------------+
+ 1 row in set (60.07 sec)
+
+ +------------------+
+ | summary |
+ +------------------+
+ | Enabled 1 thread |
+ +------------------+
+ 1 row in set (60.32 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ DECLARE v_done bool DEFAULT FALSE;
+ DECLARE v_start, v_runtime DECIMAL(20,2) DEFAULT 0.0;
+ DECLARE v_min_event_id bigint unsigned DEFAULT 0;
+ DECLARE v_this_thread_enabed ENUM('YES', 'NO');
+ DECLARE v_event longtext;
+ DECLARE c_stack CURSOR FOR
+ SELECT CONCAT(IF(nesting_event_id IS NOT NULL, CONCAT(nesting_event_id, ' -> '), ''),
+ event_id, '; ', event_id, ' [label="',
+ -- Convert from picoseconds to microseconds
+ '(', sys.format_time(timer_wait), ') ',
+ IF (event_name NOT LIKE 'wait/io%',
+ SUBSTRING_INDEX(event_name, '/', -2),
+ IF (event_name NOT LIKE 'wait/io/file%' OR event_name NOT LIKE 'wait/io/socket%',
+ SUBSTRING_INDEX(event_name, '/', -4),
+ event_name)
+ ),
+ -- Always dump the extra wait information gathered for statements
+ IF (event_name LIKE 'statement/%', IFNULL(CONCAT('\\n', wait_info), ''), ''),
+ -- If debug is enabled, add the file:lineno information for waits
+ IF (in_debug AND event_name LIKE 'wait%', wait_info, ''),
+ '", ',
+ -- Depending on the type of event, style appropriately
+ CASE WHEN event_name LIKE 'wait/io/file%' THEN
+ 'shape=box, style=filled, color=red'
+ WHEN event_name LIKE 'wait/io/table%' THEN
+ 'shape=box, style=filled, color=green'
+ WHEN event_name LIKE 'wait/io/socket%' THEN
+ 'shape=box, style=filled, color=yellow'
+ WHEN event_name LIKE 'wait/synch/mutex%' THEN
+ 'style=filled, color=lightskyblue'
+ WHEN event_name LIKE 'wait/synch/cond%' THEN
+ 'style=filled, color=darkseagreen3'
+ WHEN event_name LIKE 'wait/synch/rwlock%' THEN
+ 'style=filled, color=orchid'
+ WHEN event_name LIKE 'wait/lock%' THEN
+ 'shape=box, style=filled, color=tan'
+ WHEN event_name LIKE 'statement/%' THEN
+ CONCAT('shape=box, style=bold',
+ -- Style statements depending on COM vs SQL
+ CASE WHEN event_name LIKE 'statement/com/%' THEN
+ ' style=filled, color=darkseagreen'
+ ELSE
+ -- Use long query time from the server to
+ -- flag long running statements in red
+ IF((timer_wait/1000000000000) > @@log_slow_query_time,
+ ' style=filled, color=red',
+ ' style=filled, color=lightblue')
+ END
+ )
+ WHEN event_name LIKE 'stage/%' THEN
+ 'style=filled, color=slategray3'
+ -- IDLE events are on their own, call attention to them
+ WHEN event_name LIKE '%idle%' THEN
+ 'shape=box, style=filled, color=firebrick3'
+ ELSE '' END,
+ '];\n'
+ ) event, event_id
+ FROM (
+ -- Select all statements, with the extra tracing information available
+ (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id,
+ CONCAT(sql_text, '\\n',
+ 'errors: ', errors, '\\n',
+ 'warnings: ', warnings, '\\n',
+ 'lock time: ', sys.format_time(lock_time),'\\n',
+ 'rows affected: ', rows_affected, '\\n',
+ 'rows sent: ', rows_sent, '\\n',
+ 'rows examined: ', rows_examined, '\\n',
+ 'tmp tables: ', created_tmp_tables, '\\n',
+ 'tmp disk tables: ', created_tmp_disk_tables, '\\n'
+ 'select scan: ', select_scan, '\\n',
+ 'select full join: ', select_full_join, '\\n',
+ 'select full range join: ', select_full_range_join, '\\n',
+ 'select range: ', select_range, '\\n',
+ 'select range check: ', select_range_check, '\\n',
+ 'sort merge passes: ', sort_merge_passes, '\\n',
+ 'sort rows: ', sort_rows, '\\n',
+ 'sort range: ', sort_range, '\\n',
+ 'sort scan: ', sort_scan, '\\n',
+ 'no index used: ', IF(no_index_used, 'TRUE', 'FALSE'), '\\n',
+ 'no good index used: ', IF(no_good_index_used, 'TRUE', 'FALSE'), '\\n'
+ ) AS wait_info
+ FROM performance_schema.events_statements_history_long
+ WHERE thread_id = in_thread_id AND event_id > v_min_event_id)
+ UNION
+ -- Select all stages
+ (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id, null AS wait_info
+ FROM performance_schema.events_stages_history_long
+ WHERE thread_id = in_thread_id AND event_id > v_min_event_id)
+ UNION
+ -- Select all events, adding information appropriate to the event
+ (SELECT thread_id, event_id,
+ CONCAT(event_name,
+ IF(event_name NOT LIKE 'wait/synch/mutex%', IFNULL(CONCAT(' - ', operation), ''), ''),
+ IF(number_of_bytes IS NOT NULL, CONCAT(' ', number_of_bytes, ' bytes'), ''),
+ IF(event_name LIKE 'wait/io/file%', '\\n', ''),
+ IF(object_schema IS NOT NULL, CONCAT('\\nObject: ', object_schema, '.'), ''),
+ IF(object_name IS NOT NULL,
+ IF (event_name LIKE 'wait/io/socket%',
+ -- Print the socket if used, else the IP:port as reported
+ CONCAT('\\n', IF (object_name LIKE ':0%', @@socket, object_name)),
+ object_name),
+ ''
+ ),
+ IF(index_name IS NOT NULL, CONCAT(' Index: ', index_name), ''), '\\n'
+ ) AS event_name,
+ timer_wait, timer_start, nesting_event_id, source AS wait_info
+ FROM performance_schema.events_waits_history_long
+ WHERE thread_id = in_thread_id AND event_id > v_min_event_id)
+ ) events
+ ORDER BY event_id;
+ DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
+
+ SET @log_bin := @@sql_log_bin;
+ SET sql_log_bin = 0;
+
+ -- Do not track the current thread, it will kill the stack
+ SELECT INSTRUMENTED INTO v_this_thread_enabed FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID();
+ CALL sys.ps_setup_disable_thread(CONNECTION_ID());
+
+ IF (in_auto_setup) THEN
+ CALL sys.ps_setup_save(0);
+
+ -- Ensure only the thread to create the stack trace for is instrumented and that we instrument everything.
+ DELETE FROM performance_schema.setup_actors;
+
+ UPDATE performance_schema.threads
+ SET INSTRUMENTED = IF(THREAD_ID = in_thread_id, 'YES', 'NO');
+
+ -- only the %_history_long tables and it ancestors are needed
+ UPDATE performance_schema.setup_consumers
+ SET ENABLED = 'YES'
+ WHERE NAME NOT LIKE '%\_history';
+
+ UPDATE performance_schema.setup_instruments
+ SET ENABLED = 'YES',
+ TIMED = 'YES';
+ END IF;
+
+ IF (in_start_fresh) THEN
+ TRUNCATE performance_schema.events_statements_history_long;
+ TRUNCATE performance_schema.events_stages_history_long;
+ TRUNCATE performance_schema.events_waits_history_long;
+ END IF;
+
+ DROP TEMPORARY TABLE IF EXISTS tmp_events;
+ CREATE TEMPORARY TABLE tmp_events (
+ event_id bigint unsigned NOT NULL,
+ event longblob,
+ PRIMARY KEY (event_id)
+ );
+
+ -- Print headers for a .dot file
+ INSERT INTO tmp_events VALUES (0, CONCAT('digraph events { rankdir=LR; nodesep=0.10;\n',
+ '// Stack created .....: ', NOW(), '\n',
+ '// MySQL version .....: ', VERSION(), '\n',
+ '// MySQL hostname ....: ', @@hostname, '\n',
+ '// MySQL port ........: ', @@port, '\n',
+ '// MySQL socket ......: ', @@socket, '\n',
+ '// MySQL user ........: ', CURRENT_USER(), '\n'));
+
+ SELECT CONCAT('Data collection starting for THREAD_ID = ', in_thread_id) AS 'Info';
+
+ SET v_min_event_id = 0,
+ v_start = UNIX_TIMESTAMP(),
+ in_interval = IFNULL(in_interval, 1.00),
+ in_max_runtime = IFNULL(in_max_runtime, 60.00);
+
+ WHILE (v_runtime < in_max_runtime
+ AND (SELECT INSTRUMENTED FROM performance_schema.threads WHERE THREAD_ID = in_thread_id) = 'YES') DO
+ SET v_done = FALSE;
+ OPEN c_stack;
+ c_stack_loop: LOOP
+ FETCH c_stack INTO v_event, v_min_event_id;
+ IF v_done THEN
+ LEAVE c_stack_loop;
+ END IF;
+
+ IF (LENGTH(v_event) > 0) THEN
+ INSERT INTO tmp_events VALUES (v_min_event_id, v_event);
+ END IF;
+ END LOOP;
+ CLOSE c_stack;
+
+ SELECT SLEEP(in_interval) INTO @sleep;
+ SET v_runtime = (UNIX_TIMESTAMP() - v_start);
+ END WHILE;
+
+ INSERT INTO tmp_events VALUES (v_min_event_id+1, '}');
+
+ SET @query = CONCAT('SELECT event FROM tmp_events ORDER BY event_id INTO OUTFILE ''', in_outfile, ''' FIELDS ESCAPED BY '''' LINES TERMINATED BY ''''');
+ PREPARE stmt_output FROM @query;
+ EXECUTE stmt_output;
+ DEALLOCATE PREPARE stmt_output;
+
+ SELECT CONCAT('Stack trace written to ', in_outfile) AS 'Info';
+ SELECT CONCAT('dot -Tpdf -o /tmp/stack_', in_thread_id, '.pdf ', in_outfile) AS 'Convert to PDF';
+ SELECT CONCAT('dot -Tpng -o /tmp/stack_', in_thread_id, '.png ', in_outfile) AS 'Convert to PNG';
+ DROP TEMPORARY TABLE tmp_events;
+
+ -- Reset the settings for the performance schema
+ IF (in_auto_setup) THEN
+ CALL sys.ps_setup_reload_saved();
+ END IF;
+ -- Restore INSTRUMENTED for this thread
+ IF (v_this_thread_enabed = 'YES') THEN
+ CALL sys.ps_setup_enable_thread(CONNECTION_ID());
+ END IF;
+
+ SET sql_log_bin = @log_bin;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_trace_thread_57.sql b/scripts/sys_schema/procedures/ps_trace_thread_57.sql
new file mode 100644
index 00000000..33dc7961
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_trace_thread_57.sql
@@ -0,0 +1,340 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_trace_thread;
+
+DELIMITER $$
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_trace_thread (
+ IN in_thread_id BIGINT UNSIGNED,
+ IN in_outfile VARCHAR(255),
+ IN in_max_runtime DECIMAL(20,2),
+ IN in_interval DECIMAL(20,2),
+ IN in_start_fresh BOOLEAN,
+ IN in_auto_setup BOOLEAN,
+ IN in_debug BOOLEAN
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Dumps all data within Performance Schema for an instrumented thread,
+ to create a DOT formatted graph file.
+
+ Each resultset returned from the procedure should be used for a complete graph
+
+ Requires the SUPER privilege for "SET sql_log_bin = 0;".
+
+ Parameters
+ -----------
+
+ in_thread_id (BIGINT UNSIGNED):
+ The thread that you would like a stack trace for
+ in_outfile (VARCHAR(255)):
+ The filename the dot file will be written to
+ in_max_runtime (DECIMAL(20,2)):
+ The maximum time to keep collecting data.
+ Use NULL to get the default which is 60 seconds.
+ in_interval (DECIMAL(20,2)):
+ How long to sleep between data collections.
+ Use NULL to get the default which is 1 second.
+ in_start_fresh (BOOLEAN):
+ Whether to reset all Performance Schema data before tracing.
+ in_auto_setup (BOOLEAN):
+ Whether to disable all other threads and enable all consumers/instruments.
+ This will also reset the settings at the end of the run.
+ in_debug (BOOLEAN):
+ Whether you would like to include file:lineno in the graph
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_trace_thread(25, CONCAT(\'/tmp/stack-\', REPLACE(NOW(), \' \', \'-\'), \'.dot\'), NULL, NULL, TRUE, TRUE, TRUE);
+ +-------------------+
+ | summary |
+ +-------------------+
+ | Disabled 1 thread |
+ +-------------------+
+ 1 row in set (0.00 sec)
+
+ +---------------------------------------------+
+ | Info |
+ +---------------------------------------------+
+ | Data collection starting for THREAD_ID = 25 |
+ +---------------------------------------------+
+ 1 row in set (0.03 sec)
+
+ +-----------------------------------------------------------+
+ | Info |
+ +-----------------------------------------------------------+
+ | Stack trace written to /tmp/stack-2014-02-16-21:18:41.dot |
+ +-----------------------------------------------------------+
+ 1 row in set (60.07 sec)
+
+ +-------------------------------------------------------------------+
+ | Convert to PDF |
+ +-------------------------------------------------------------------+
+ | dot -Tpdf -o /tmp/stack_25.pdf /tmp/stack-2014-02-16-21:18:41.dot |
+ +-------------------------------------------------------------------+
+ 1 row in set (60.07 sec)
+
+ +-------------------------------------------------------------------+
+ | Convert to PNG |
+ +-------------------------------------------------------------------+
+ | dot -Tpng -o /tmp/stack_25.png /tmp/stack-2014-02-16-21:18:41.dot |
+ +-------------------------------------------------------------------+
+ 1 row in set (60.07 sec)
+
+ +------------------+
+ | summary |
+ +------------------+
+ | Enabled 1 thread |
+ +------------------+
+ 1 row in set (60.32 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ DECLARE v_done bool DEFAULT FALSE;
+ DECLARE v_start, v_runtime DECIMAL(20,2) DEFAULT 0.0;
+ DECLARE v_min_event_id bigint unsigned DEFAULT 0;
+ DECLARE v_this_thread_enabed ENUM('YES', 'NO');
+ DECLARE v_event longtext;
+ DECLARE c_stack CURSOR FOR
+ SELECT CONCAT(IF(nesting_event_id IS NOT NULL, CONCAT(nesting_event_id, ' -> '), ''),
+ event_id, '; ', event_id, ' [label="',
+ -- Convert from picoseconds to microseconds
+ '(', sys.format_time(timer_wait), ') ',
+ IF (event_name NOT LIKE 'wait/io%',
+ SUBSTRING_INDEX(event_name, '/', -2),
+ IF (event_name NOT LIKE 'wait/io/file%' OR event_name NOT LIKE 'wait/io/socket%',
+ SUBSTRING_INDEX(event_name, '/', -4),
+ event_name)
+ ),
+ -- Always dump the extra wait information gathered for transactions and statements
+ IF (event_name LIKE 'transaction', IFNULL(CONCAT('\\n', wait_info), ''), ''),
+ IF (event_name LIKE 'statement/%', IFNULL(CONCAT('\\n', wait_info), ''), ''),
+ -- If debug is enabled, add the file:lineno information for waits
+ IF (in_debug AND event_name LIKE 'wait%', wait_info, ''),
+ '", ',
+ -- Depending on the type of event, style appropriately
+ CASE WHEN event_name LIKE 'wait/io/file%' THEN
+ 'shape=box, style=filled, color=red'
+ WHEN event_name LIKE 'wait/io/table%' THEN
+ 'shape=box, style=filled, color=green'
+ WHEN event_name LIKE 'wait/io/socket%' THEN
+ 'shape=box, style=filled, color=yellow'
+ WHEN event_name LIKE 'wait/synch/mutex%' THEN
+ 'style=filled, color=lightskyblue'
+ WHEN event_name LIKE 'wait/synch/cond%' THEN
+ 'style=filled, color=darkseagreen3'
+ WHEN event_name LIKE 'wait/synch/rwlock%' THEN
+ 'style=filled, color=orchid'
+ WHEN event_name LIKE 'wait/synch/sxlock%' THEN
+ 'style=filled, color=palevioletred'
+ WHEN event_name LIKE 'wait/lock%' THEN
+ 'shape=box, style=filled, color=tan'
+ WHEN event_name LIKE 'statement/%' THEN
+ CONCAT('shape=box, style=bold',
+ -- Style statements depending on COM vs SQL
+ CASE WHEN event_name LIKE 'statement/com/%' THEN
+ ' style=filled, color=darkseagreen'
+ ELSE
+ -- Use long query time from the server to
+ -- flag long running statements in red
+ IF((timer_wait/1000000000000) > @@log_slow_query_time,
+ ' style=filled, color=red',
+ ' style=filled, color=lightblue')
+ END
+ )
+ WHEN event_name LIKE 'transaction' THEN
+ 'shape=box, style=filled, color=lightblue3'
+ WHEN event_name LIKE 'stage/%' THEN
+ 'style=filled, color=slategray3'
+ -- IDLE events are on their own, call attention to them
+ WHEN event_name LIKE '%idle%' THEN
+ 'shape=box, style=filled, color=firebrick3'
+ ELSE '' END,
+ '];\n'
+ ) event, event_id
+ FROM (
+ -- Select all transactions
+ (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id,
+ CONCAT('trx_id: ', IFNULL(trx_id, ''), '\\n',
+ 'gtid: ', IFNULL(gtid, ''), '\\n',
+ 'state: ', state, '\\n',
+ 'mode: ', access_mode, '\\n',
+ 'isolation: ', isolation_level, '\\n',
+ 'autocommit: ', autocommit, '\\n',
+ 'savepoints: ', number_of_savepoints, '\\n'
+ ) AS wait_info
+ FROM performance_schema.events_transactions_history_long
+ WHERE thread_id = in_thread_id AND event_id > v_min_event_id)
+ UNION
+ -- Select all statements, with the extra tracing information available
+ (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id,
+ CONCAT('statement: ', sql_text, '\\n',
+ 'errors: ', errors, '\\n',
+ 'warnings: ', warnings, '\\n',
+ 'lock time: ', sys.format_time(lock_time),'\\n',
+ 'rows affected: ', rows_affected, '\\n',
+ 'rows sent: ', rows_sent, '\\n',
+ 'rows examined: ', rows_examined, '\\n',
+ 'tmp tables: ', created_tmp_tables, '\\n',
+ 'tmp disk tables: ', created_tmp_disk_tables, '\\n'
+ 'select scan: ', select_scan, '\\n',
+ 'select full join: ', select_full_join, '\\n',
+ 'select full range join: ', select_full_range_join, '\\n',
+ 'select range: ', select_range, '\\n',
+ 'select range check: ', select_range_check, '\\n',
+ 'sort merge passes: ', sort_merge_passes, '\\n',
+ 'sort rows: ', sort_rows, '\\n',
+ 'sort range: ', sort_range, '\\n',
+ 'sort scan: ', sort_scan, '\\n',
+ 'no index used: ', IF(no_index_used, 'TRUE', 'FALSE'), '\\n',
+ 'no good index used: ', IF(no_good_index_used, 'TRUE', 'FALSE'), '\\n'
+ ) AS wait_info
+ FROM performance_schema.events_statements_history_long
+ WHERE thread_id = in_thread_id AND event_id > v_min_event_id)
+ UNION
+ -- Select all stages
+ (SELECT thread_id, event_id, event_name, timer_wait, timer_start, nesting_event_id, null AS wait_info
+ FROM performance_schema.events_stages_history_long
+ WHERE thread_id = in_thread_id AND event_id > v_min_event_id)
+ UNION
+ -- Select all events, adding information appropriate to the event
+ (SELECT thread_id, event_id,
+ CONCAT(event_name,
+ IF(event_name NOT LIKE 'wait/synch/mutex%', IFNULL(CONCAT(' - ', operation), ''), ''),
+ IF(number_of_bytes IS NOT NULL, CONCAT(' ', number_of_bytes, ' bytes'), ''),
+ IF(event_name LIKE 'wait/io/file%', '\\n', ''),
+ IF(object_schema IS NOT NULL, CONCAT('\\nObject: ', object_schema, '.'), ''),
+ IF(object_name IS NOT NULL,
+ IF (event_name LIKE 'wait/io/socket%',
+ -- Print the socket if used, else the IP:port as reported
+ CONCAT('\\n', IF (object_name LIKE ':0%', @@socket, object_name)),
+ object_name),
+ ''
+ ),
+ IF(index_name IS NOT NULL, CONCAT(' Index: ', index_name), ''), '\\n'
+ ) AS event_name,
+ timer_wait, timer_start, nesting_event_id, source AS wait_info
+ FROM performance_schema.events_waits_history_long
+ WHERE thread_id = in_thread_id AND event_id > v_min_event_id)
+ ) events
+ ORDER BY event_id;
+ DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
+
+ SET @log_bin := @@sql_log_bin;
+ SET sql_log_bin = 0;
+
+ -- Do not track the current thread, it will kill the stack
+ SELECT INSTRUMENTED INTO v_this_thread_enabed FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID();
+ CALL sys.ps_setup_disable_thread(CONNECTION_ID());
+
+ IF (in_auto_setup) THEN
+ CALL sys.ps_setup_save(0);
+
+ -- Ensure only the thread to create the stack trace for is instrumented and that we instrument everything.
+ DELETE FROM performance_schema.setup_actors;
+
+ UPDATE performance_schema.threads
+ SET INSTRUMENTED = IF(THREAD_ID = in_thread_id, 'YES', 'NO');
+
+ -- only the %_history_long tables and it ancestors are needed
+ UPDATE performance_schema.setup_consumers
+ SET ENABLED = 'YES'
+ WHERE NAME NOT LIKE '%\_history';
+
+ UPDATE performance_schema.setup_instruments
+ SET ENABLED = 'YES',
+ TIMED = 'YES';
+ END IF;
+
+ IF (in_start_fresh) THEN
+ TRUNCATE performance_schema.events_transactions_history_long;
+ TRUNCATE performance_schema.events_statements_history_long;
+ TRUNCATE performance_schema.events_stages_history_long;
+ TRUNCATE performance_schema.events_waits_history_long;
+ END IF;
+
+ DROP TEMPORARY TABLE IF EXISTS tmp_events;
+ CREATE TEMPORARY TABLE tmp_events (
+ event_id bigint unsigned NOT NULL,
+ event longblob,
+ PRIMARY KEY (event_id)
+ );
+
+ -- Print headers for a .dot file
+ INSERT INTO tmp_events VALUES (0, CONCAT('digraph events { rankdir=LR; nodesep=0.10;\n',
+ '// Stack created .....: ', NOW(), '\n',
+ '// MySQL version .....: ', VERSION(), '\n',
+ '// MySQL hostname ....: ', @@hostname, '\n',
+ '// MySQL port ........: ', @@port, '\n',
+ '// MySQL socket ......: ', @@socket, '\n',
+ '// MySQL user ........: ', CURRENT_USER(), '\n'));
+
+ SELECT CONCAT('Data collection starting for THREAD_ID = ', in_thread_id) AS 'Info';
+
+ SET v_min_event_id = 0,
+ v_start = UNIX_TIMESTAMP(),
+ in_interval = IFNULL(in_interval, 1.00),
+ in_max_runtime = IFNULL(in_max_runtime, 60.00);
+
+ WHILE (v_runtime < in_max_runtime
+ AND (SELECT INSTRUMENTED FROM performance_schema.threads WHERE THREAD_ID = in_thread_id) = 'YES') DO
+ SET v_done = FALSE;
+ OPEN c_stack;
+ c_stack_loop: LOOP
+ FETCH c_stack INTO v_event, v_min_event_id;
+ IF v_done THEN
+ LEAVE c_stack_loop;
+ END IF;
+
+ IF (LENGTH(v_event) > 0) THEN
+ INSERT INTO tmp_events VALUES (v_min_event_id, v_event);
+ END IF;
+ END LOOP;
+ CLOSE c_stack;
+
+ SELECT SLEEP(in_interval) INTO @sleep;
+ SET v_runtime = (UNIX_TIMESTAMP() - v_start);
+ END WHILE;
+
+ INSERT INTO tmp_events VALUES (v_min_event_id+1, '}');
+
+ SET @query = CONCAT('SELECT event FROM tmp_events ORDER BY event_id INTO OUTFILE ''', in_outfile, ''' FIELDS ESCAPED BY '''' LINES TERMINATED BY ''''');
+ PREPARE stmt_output FROM @query;
+ EXECUTE stmt_output;
+ DEALLOCATE PREPARE stmt_output;
+
+ SELECT CONCAT('Stack trace written to ', in_outfile) AS 'Info';
+ SELECT CONCAT('dot -Tpdf -o /tmp/stack_', in_thread_id, '.pdf ', in_outfile) AS 'Convert to PDF';
+ SELECT CONCAT('dot -Tpng -o /tmp/stack_', in_thread_id, '.png ', in_outfile) AS 'Convert to PNG';
+ DROP TEMPORARY TABLE tmp_events;
+
+ -- Reset the settings for the performance schema
+ IF (in_auto_setup) THEN
+ CALL sys.ps_setup_reload_saved();
+ END IF;
+ -- Restore INSTRUMENTED for this thread
+ IF (v_this_thread_enabed = 'YES') THEN
+ CALL sys.ps_setup_enable_thread(CONNECTION_ID());
+ END IF;
+
+ SET sql_log_bin = @log_bin;
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/ps_truncate_all_tables.sql b/scripts/sys_schema/procedures/ps_truncate_all_tables.sql
new file mode 100644
index 00000000..42d904f5
--- /dev/null
+++ b/scripts/sys_schema/procedures/ps_truncate_all_tables.sql
@@ -0,0 +1,90 @@
+-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS ps_truncate_all_tables;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_truncate_all_tables (
+ IN in_verbose BOOLEAN
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Truncates all summary tables within Performance Schema,
+ resetting all aggregated instrumentation as a snapshot.
+
+ Parameters
+ -----------
+
+ in_verbose (BOOLEAN):
+ Whether to print each TRUNCATE statement before running
+
+ Example
+ -----------
+
+ mysql> CALL sys.ps_truncate_all_tables(false);
+ +---------------------+
+ | summary |
+ +---------------------+
+ | Truncated 44 tables |
+ +---------------------+
+ 1 row in set (0.10 sec)
+
+ Query OK, 0 rows affected (0.10 sec)
+ '
+ SQL SECURITY INVOKER
+ DETERMINISTIC
+ MODIFIES SQL DATA
+BEGIN
+ DECLARE v_done INT DEFAULT FALSE;
+ DECLARE v_total_tables INT DEFAULT 0;
+ DECLARE v_ps_table VARCHAR(64);
+ DECLARE ps_tables CURSOR FOR
+ SELECT table_name
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE table_schema = 'performance_schema'
+ AND (table_name LIKE '%summary%'
+ OR table_name LIKE '%history%');
+ DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
+
+ OPEN ps_tables;
+
+ ps_tables_loop: LOOP
+ FETCH ps_tables INTO v_ps_table;
+ IF v_done THEN
+ LEAVE ps_tables_loop;
+ END IF;
+
+ SET @truncate_stmt := CONCAT('TRUNCATE TABLE performance_schema.', v_ps_table);
+ IF in_verbose THEN
+ SELECT CONCAT('Running: ', @truncate_stmt) AS status;
+ END IF;
+
+ PREPARE truncate_stmt FROM @truncate_stmt;
+ EXECUTE truncate_stmt;
+ DEALLOCATE PREPARE truncate_stmt;
+
+ SET v_total_tables = v_total_tables + 1;
+ END LOOP;
+
+ CLOSE ps_tables;
+
+ SELECT CONCAT('Truncated ', v_total_tables, ' tables') AS summary;
+
+END$$
+
+DELIMITER ;
diff --git a/scripts/sys_schema/procedures/statement_performance_analyzer.sql b/scripts/sys_schema/procedures/statement_performance_analyzer.sql
new file mode 100644
index 00000000..f98596ef
--- /dev/null
+++ b/scripts/sys_schema/procedures/statement_performance_analyzer.sql
@@ -0,0 +1,723 @@
+-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS statement_performance_analyzer;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE statement_performance_analyzer (
+ IN in_action ENUM('snapshot', 'overall', 'delta', 'create_table', 'create_tmp', 'save', 'cleanup'),
+ IN in_table VARCHAR(129),
+ IN in_views SET ('with_runtimes_in_95th_percentile', 'analysis', 'with_errors_or_warnings', 'with_full_table_scans', 'with_sorting', 'with_temp_tables', 'custom')
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Create a report of the statements running on the server.
+
+ The views are calculated based on the overall and/or delta activity.
+
+ Requires the SUPER privilege for "SET sql_log_bin = 0;".
+
+ Parameters
+ -----------
+
+ in_action (ENUM(''snapshot'', ''overall'', ''delta'', ''create_tmp'', ''create_table'', ''save'', ''cleanup'')):
+ The action to take. Supported actions are:
+ * snapshot Store a snapshot. The default is to make a snapshot of the current content of
+ performance_schema.events_statements_summary_by_digest, but by setting in_table
+ this can be overwritten to copy the content of the specified table.
+ The snapshot is stored in the sys.tmp_digests temporary table.
+ * overall Generate analyzis based on the content specified by in_table. For the overall analyzis,
+ in_table can be NOW() to use a fresh snapshot. This will overwrite an existing snapshot.
+ Use NULL for in_table to use the existing snapshot. If in_table IS NULL and no snapshot
+ exists, a new will be created.
+ See also in_views and @sys.statement_performance_analyzer.limit.
+ * delta Generate a delta analysis. The delta will be calculated between the reference table in
+ in_table and the snapshot. An existing snapshot must exist.
+ The action uses the sys.tmp_digests_delta temporary table.
+ See also in_views and @sys.statement_performance_analyzer.limit.
+ * create_table Create a regular table suitable for storing the snapshot for later use, e.g. for
+ calculating deltas.
+ * create_tmp Create a temporary table suitable for storing the snapshot for later use, e.g. for
+ calculating deltas.
+ * save Save the snapshot in the table specified by in_table. The table must exists and have
+ the correct structure.
+ If no snapshot exists, a new is created.
+ * cleanup Remove the temporary tables used for the snapshot and delta.
+
+ in_table (VARCHAR(129)):
+ The table argument used for some actions. Use the format ''db1.t1'' or ''t1'' without using any backticks (`)
+ for quoting. Periods (.) are not supported in the database and table names.
+
+ The meaning of the table for each action supporting the argument is:
+
+ * snapshot The snapshot is created based on the specified table. Set to NULL or NOW() to use
+ the current content of performance_schema.events_statements_summary_by_digest.
+ * overall The table with the content to create the overall analyzis for. The following values
+ can be used:
+ - A table name - use the content of that table.
+ - NOW() - create a fresh snapshot and overwrite the existing snapshot.
+ - NULL - use the last stored snapshot.
+ * delta The table name is mandatory and specified the reference view to compare the currently
+ stored snapshot against. If no snapshot exists, a new will be created.
+ * create_table The name of the regular table to create.
+ * create_tmp The name of the temporary table to create.
+ * save The name of the table to save the currently stored snapshot into.
+
+ in_views (SET (''with_runtimes_in_95th_percentile'', ''analysis'', ''with_errors_or_warnings'',
+ ''with_full_table_scans'', ''with_sorting'', ''with_temp_tables'', ''custom''))
+ Which views to include:
+
+ * with_runtimes_in_95th_percentile Based on the sys.statements_with_runtimes_in_95th_percentile view
+ * analysis Based on the sys.statement_analysis view
+ * with_errors_or_warnings Based on the sys.statements_with_errors_or_warnings view
+ * with_full_table_scans Based on the sys.statements_with_full_table_scans view
+ * with_sorting Based on the sys.statements_with_sorting view
+ * with_temp_tables Based on the sys.statements_with_temp_tables view
+ * custom Use a custom view. This view must be specified in @sys.statement_performance_analyzer.view to an existing view or a query
+
+ Default is to include all except ''custom''.
+
+
+ Configuration Options
+ ----------------------
+
+ sys.statement_performance_analyzer.limit
+ The maximum number of rows to include for the views that does not have a built-in limit (e.g. the 95th percentile view).
+ If not set the limit is 100.
+
+ sys.statement_performance_analyzer.view
+ Used together with the ''custom'' view. If the value contains a space, it is considered a query, otherwise it must be
+ an existing view querying the performance_schema.events_statements_summary_by_digest table. There cannot be any limit
+ clause including in the query or view definition if @sys.statement_performance_analyzer.limit > 0.
+ If specifying a view, use the same format as for in_table.
+
+ sys.debug
+ Whether to provide debugging output.
+ Default is ''OFF''. Set to ''ON'' to include.
+
+
+ Example
+ --------
+
+ To create a report with the queries in the 95th percentile since last truncate of performance_schema.events_statements_summary_by_digest
+ and the delta for a 1 minute period:
+
+ 1. Create a temporary table to store the initial snapshot.
+ 2. Create the initial snapshot.
+ 3. Save the initial snapshot in the temporary table.
+ 4. Wait one minute.
+ 5. Create a new snapshot.
+ 6. Perform analyzis based on the new snapshot.
+ 7. Perform analyzis based on the delta between the initial and new snapshots.
+
+ mysql> CALL sys.statement_performance_analyzer(''create_tmp'', ''mydb.tmp_digests_ini'', NULL);
+ Query OK, 0 rows affected (0.08 sec)
+
+ mysql> CALL sys.statement_performance_analyzer(''snapshot'', NULL, NULL);
+ Query OK, 0 rows affected (0.02 sec)
+
+ mysql> CALL sys.statement_performance_analyzer(''save'', ''mydb.tmp_digests_ini'', NULL);
+ Query OK, 0 rows affected (0.00 sec)
+
+ mysql> DO SLEEP(60);
+ Query OK, 0 rows affected (1 min 0.00 sec)
+
+ mysql> CALL sys.statement_performance_analyzer(''snapshot'', NULL, NULL);
+ Query OK, 0 rows affected (0.02 sec)
+
+ mysql> CALL sys.statement_performance_analyzer(''overall'', NULL, ''with_runtimes_in_95th_percentile'');
+ +-----------------------------------------+
+ | Next Output |
+ +-----------------------------------------+
+ | Queries with Runtime in 95th Percentile |
+ +-----------------------------------------+
+ 1 row in set (0.05 sec)
+
+ ...
+
+ mysql> CALL sys.statement_performance_analyzer(''delta'', ''mydb.tmp_digests_ini'', ''with_runtimes_in_95th_percentile'');
+ +-----------------------------------------+
+ | Next Output |
+ +-----------------------------------------+
+ | Queries with Runtime in 95th Percentile |
+ +-----------------------------------------+
+ 1 row in set (0.03 sec)
+
+ ...
+
+
+ To create an overall report of the 95th percentile queries and the top 10 queries with full table scans:
+
+ mysql> CALL sys.statement_performance_analyzer(''snapshot'', NULL, NULL);
+ Query OK, 0 rows affected (0.01 sec)
+
+ mysql> SET @sys.statement_performance_analyzer.limit = 10;
+ Query OK, 0 rows affected (0.00 sec)
+
+ mysql> CALL sys.statement_performance_analyzer(''overall'', NULL, ''with_runtimes_in_95th_percentile,with_full_table_scans'');
+ +-----------------------------------------+
+ | Next Output |
+ +-----------------------------------------+
+ | Queries with Runtime in 95th Percentile |
+ +-----------------------------------------+
+ 1 row in set (0.01 sec)
+
+ ...
+
+ +-------------------------------------+
+ | Next Output |
+ +-------------------------------------+
+ | Top 10 Queries with Full Table Scan |
+ +-------------------------------------+
+ 1 row in set (0.09 sec)
+
+ ...
+
+
+ Use a custom view showing the top 10 query sorted by total execution time refreshing the view every minute using
+ the watch command in Linux.
+
+ mysql> CREATE OR REPLACE VIEW mydb.my_statements AS
+ -> SELECT sys.format_statement(DIGEST_TEXT) AS query,
+ -> SCHEMA_NAME AS db,
+ -> COUNT_STAR AS exec_count,
+ -> sys.format_time(SUM_TIMER_WAIT) AS total_latency,
+ -> sys.format_time(AVG_TIMER_WAIT) AS avg_latency,
+ -> ROUND(IFNULL(SUM_ROWS_SENT / NULLIF(COUNT_STAR, 0), 0)) AS rows_sent_avg,
+ -> ROUND(IFNULL(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0), 0)) AS rows_examined_avg,
+ -> ROUND(IFNULL(SUM_ROWS_AFFECTED / NULLIF(COUNT_STAR, 0), 0)) AS rows_affected_avg,
+ -> DIGEST AS digest
+ -> FROM performance_schema.events_statements_summary_by_digest
+ -> ORDER BY SUM_TIMER_WAIT DESC;
+ Query OK, 0 rows affected (0.01 sec)
+
+ mysql> CALL sys.statement_performance_analyzer(''create_table'', ''mydb.digests_prev'', NULL);
+ Query OK, 0 rows affected (0.10 sec)
+
+ shell$ watch -n 60 "mysql sys --table -e \"
+ > SET @sys.statement_performance_analyzer.view = ''mydb.my_statements'';
+ > SET @sys.statement_performance_analyzer.limit = 10;
+ > CALL statement_performance_analyzer(''snapshot'', NULL, NULL);
+ > CALL statement_performance_analyzer(''delta'', ''mydb.digests_prev'', ''custom'');
+ > CALL statement_performance_analyzer(''save'', ''mydb.digests_prev'', NULL);
+ > \""
+
+ Every 60.0s: mysql sys --table -e " ... Mon Dec 22 10:58:51 2014
+
+ +----------------------------------+
+ | Next Output |
+ +----------------------------------+
+ | Top 10 Queries Using Custom View |
+ +----------------------------------+
+ +-------------------+-------+------------+---------------+-------------+---------------+-------------------+-------------------+----------------------------------+
+ | query | db | exec_count | total_latency | avg_latency | rows_sent_avg | rows_examined_avg | rows_affected_avg | digest |
+ +-------------------+-------+------------+---------------+-------------+---------------+-------------------+-------------------+----------------------------------+
+ ...
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ CONTAINS SQL
+BEGIN
+ DECLARE v_table_exists, v_tmp_digests_table_exists, v_custom_view_exists ENUM('', 'BASE TABLE', 'VIEW', 'TEMPORARY') DEFAULT '';
+ DECLARE v_this_thread_enabled ENUM('YES', 'NO');
+ DECLARE v_force_new_snapshot BOOLEAN DEFAULT FALSE;
+ DECLARE v_digests_table VARCHAR(133);
+ DECLARE v_quoted_table, v_quoted_custom_view VARCHAR(133) DEFAULT '';
+ DECLARE v_table_db, v_table_name, v_custom_db, v_custom_name VARCHAR(64);
+ DECLARE v_digest_table_template, v_checksum_ref, v_checksum_table text;
+ DECLARE v_sql longtext;
+ -- Maximum supported length for MESSAGE_TEXT with the SIGNAL command is 128 chars.
+ DECLARE v_error_msg VARCHAR(128);
+
+
+ -- Don't instrument this thread
+ SELECT INSTRUMENTED INTO v_this_thread_enabled FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID();
+ IF (v_this_thread_enabled = 'YES') THEN
+ CALL sys.ps_setup_disable_thread(CONNECTION_ID());
+ END IF;
+
+ -- Temporary table are used - disable sql_log_bin if necessary to prevent them replicating
+ SET @log_bin := @@sql_log_bin;
+ IF (@log_bin = 1) THEN
+ SET sql_log_bin = 0;
+ END IF;
+
+
+ -- Set configuration options
+ IF (@sys.statement_performance_analyzer.limit IS NULL) THEN
+ SET @sys.statement_performance_analyzer.limit = sys.sys_get_config('statement_performance_analyzer.limit', '100');
+ END IF;
+ IF (@sys.debug IS NULL) THEN
+ SET @sys.debug = sys.sys_get_config('debug' , 'OFF');
+ END IF;
+
+
+ -- If in_table is set, break in_table into a db and table component and check whether it exists
+ -- in_table = NOW() is considered like it's not set.
+ IF (in_table = 'NOW()') THEN
+ SET v_force_new_snapshot = TRUE,
+ in_table = NULL;
+ ELSEIF (in_table IS NOT NULL) THEN
+ IF (NOT INSTR(in_table, '.')) THEN
+ -- No . in the table name - use current database
+ -- DATABASE() will be the database of the procedure
+ SET v_table_db = DATABASE(),
+ v_table_name = in_table;
+ ELSE
+ SET v_table_db = SUBSTRING_INDEX(in_table, '.', 1);
+ SET v_table_name = SUBSTRING(in_table, CHAR_LENGTH(v_table_db)+2);
+ END IF;
+
+ SET v_quoted_table = CONCAT('`', v_table_db, '`.`', v_table_name, '`');
+
+ IF (@sys.debug = 'ON') THEN
+ SELECT CONCAT('in_table is: db = ''', v_table_db, ''', table = ''', v_table_name, '''') AS 'Debug';
+ END IF;
+
+ IF (v_table_db = DATABASE() AND (v_table_name = 'tmp_digests' OR v_table_name = 'tmp_digests_delta')) THEN
+ SET v_error_msg = CONCAT('Invalid value for in_table: ', v_quoted_table, ' is reserved table name.');
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = v_error_msg;
+ END IF;
+
+ CALL sys.table_exists(v_table_db, v_table_name, v_table_exists);
+ IF (@sys.debug = 'ON') THEN
+ SELECT CONCAT('v_table_exists = ', v_table_exists) AS 'Debug';
+ END IF;
+
+ IF (v_table_exists = 'BASE TABLE') THEN
+ -- Verify that the table has the correct table definition
+ -- This can only be done for base tables as temporary aren't in information_schema.COLUMNS.
+ -- This also minimises the risk of using a production table.
+ SET v_checksum_ref = (
+ SELECT GROUP_CONCAT(CONCAT(COLUMN_NAME, COLUMN_TYPE) ORDER BY ORDINAL_POSITION) AS Checksum
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = 'performance_schema' AND TABLE_NAME = 'events_statements_summary_by_digest'
+ ),
+ v_checksum_table = (
+ SELECT GROUP_CONCAT(CONCAT(COLUMN_NAME, COLUMN_TYPE) ORDER BY ORDINAL_POSITION) AS Checksum
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = v_table_db AND TABLE_NAME = v_table_name
+ );
+
+ IF (v_checksum_ref <> v_checksum_table) THEN
+ -- The table does not have the correct definition, so abandon
+ SET v_error_msg = CONCAT('The table ',
+ IF(CHAR_LENGTH(v_quoted_table) > 93, CONCAT('...', SUBSTRING(v_quoted_table, -90)), v_quoted_table),
+ ' has the wrong definition.');
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = v_error_msg;
+ END IF;
+ END IF;
+ END IF;
+
+
+ IF (in_views IS NULL OR in_views = '') THEN
+ -- Set to default
+ SET in_views = 'with_runtimes_in_95th_percentile,analysis,with_errors_or_warnings,with_full_table_scans,with_sorting,with_temp_tables';
+ END IF;
+
+
+ -- Validate settings
+ CALL sys.table_exists(DATABASE(), 'tmp_digests', v_tmp_digests_table_exists);
+ IF (@sys.debug = 'ON') THEN
+ SELECT CONCAT('v_tmp_digests_table_exists = ', v_tmp_digests_table_exists) AS 'Debug';
+ END IF;
+
+ CASE
+ WHEN in_action IN ('snapshot', 'overall') THEN
+ -- in_table must be NULL, NOW(), or an existing table
+ IF (in_table IS NOT NULL) THEN
+ IF (NOT v_table_exists IN ('TEMPORARY', 'BASE TABLE')) THEN
+ SET v_error_msg = CONCAT('The ', in_action, ' action requires in_table to be NULL, NOW() or specify an existing table.',
+ ' The table ',
+ IF(CHAR_LENGTH(v_quoted_table) > 16, CONCAT('...', SUBSTRING(v_quoted_table, -13)), v_quoted_table),
+ ' does not exist.');
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = v_error_msg;
+ END IF;
+ END IF;
+
+ WHEN in_action IN ('delta', 'save') THEN
+ -- in_table must be an existing table
+ IF (v_table_exists NOT IN ('TEMPORARY', 'BASE TABLE')) THEN
+ SET v_error_msg = CONCAT('The ', in_action, ' action requires in_table to be an existing table.',
+ IF(in_table IS NOT NULL, CONCAT(' The table ',
+ IF(CHAR_LENGTH(v_quoted_table) > 39, CONCAT('...', SUBSTRING(v_quoted_table, -36)), v_quoted_table),
+ ' does not exist.'), ''));
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = v_error_msg;
+ END IF;
+
+ IF (in_action = 'delta' AND v_tmp_digests_table_exists <> 'TEMPORARY') THEN
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = 'An existing snapshot generated with the statement_performance_analyzer() must exist.';
+ END IF;
+ WHEN in_action = 'create_tmp' THEN
+ -- in_table must not exists as a temporary table
+ IF (v_table_exists = 'TEMPORARY') THEN
+ SET v_error_msg = CONCAT('Cannot create the table ',
+ IF(CHAR_LENGTH(v_quoted_table) > 72, CONCAT('...', SUBSTRING(v_quoted_table, -69)), v_quoted_table),
+ ' as it already exists.');
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = v_error_msg;
+ END IF;
+
+ WHEN in_action = 'create_table' THEN
+ -- in_table must not exists at all
+ IF (v_table_exists <> '') THEN
+ SET v_error_msg = CONCAT('Cannot create the table ',
+ IF(CHAR_LENGTH(v_quoted_table) > 52, CONCAT('...', SUBSTRING(v_quoted_table, -49)), v_quoted_table),
+ ' as it already exists',
+ IF(v_table_exists = 'TEMPORARY', ' as a temporary table.', '.'));
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = v_error_msg;
+ END IF;
+
+ WHEN in_action = 'cleanup' THEN
+ -- doesn't use any of the arguments
+ DO (SELECT 1);
+ ELSE
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = 'Unknown action. Supported actions are: cleanup, create_table, create_tmp, delta, overall, save, snapshot';
+ END CASE;
+
+ SET v_digest_table_template = 'CREATE %{TEMPORARY}TABLE %{TABLE_NAME} (
+ `SCHEMA_NAME` varchar(64) DEFAULT NULL,
+ `DIGEST` varchar(32) DEFAULT NULL,
+ `DIGEST_TEXT` longtext,
+ `COUNT_STAR` bigint(20) unsigned NOT NULL,
+ `SUM_TIMER_WAIT` bigint(20) unsigned NOT NULL,
+ `MIN_TIMER_WAIT` bigint(20) unsigned NOT NULL,
+ `AVG_TIMER_WAIT` bigint(20) unsigned NOT NULL,
+ `MAX_TIMER_WAIT` bigint(20) unsigned NOT NULL,
+ `SUM_LOCK_TIME` bigint(20) unsigned NOT NULL,
+ `SUM_ERRORS` bigint(20) unsigned NOT NULL,
+ `SUM_WARNINGS` bigint(20) unsigned NOT NULL,
+ `SUM_ROWS_AFFECTED` bigint(20) unsigned NOT NULL,
+ `SUM_ROWS_SENT` bigint(20) unsigned NOT NULL,
+ `SUM_ROWS_EXAMINED` bigint(20) unsigned NOT NULL,
+ `SUM_CREATED_TMP_DISK_TABLES` bigint(20) unsigned NOT NULL,
+ `SUM_CREATED_TMP_TABLES` bigint(20) unsigned NOT NULL,
+ `SUM_SELECT_FULL_JOIN` bigint(20) unsigned NOT NULL,
+ `SUM_SELECT_FULL_RANGE_JOIN` bigint(20) unsigned NOT NULL,
+ `SUM_SELECT_RANGE` bigint(20) unsigned NOT NULL,
+ `SUM_SELECT_RANGE_CHECK` bigint(20) unsigned NOT NULL,
+ `SUM_SELECT_SCAN` bigint(20) unsigned NOT NULL,
+ `SUM_SORT_MERGE_PASSES` bigint(20) unsigned NOT NULL,
+ `SUM_SORT_RANGE` bigint(20) unsigned NOT NULL,
+ `SUM_SORT_ROWS` bigint(20) unsigned NOT NULL,
+ `SUM_SORT_SCAN` bigint(20) unsigned NOT NULL,
+ `SUM_NO_INDEX_USED` bigint(20) unsigned NOT NULL,
+ `SUM_NO_GOOD_INDEX_USED` bigint(20) unsigned NOT NULL,
+ `FIRST_SEEN` timestamp NULL DEFAULT NULL,
+ `LAST_SEEN` timestamp NULL DEFAULT NULL,
+ INDEX (SCHEMA_NAME, DIGEST)
+) DEFAULT CHARSET=utf8';
+
+ -- Do the action
+ -- The actions snapshot, ... requires a fresh snapshot - create it now
+ IF (v_force_new_snapshot
+ OR in_action = 'snapshot'
+ OR (in_action = 'overall' AND in_table IS NULL)
+ OR (in_action = 'save' AND v_tmp_digests_table_exists <> 'TEMPORARY')
+ ) THEN
+ IF (v_tmp_digests_table_exists = 'TEMPORARY') THEN
+ IF (@sys.debug = 'ON') THEN
+ SELECT 'DROP TEMPORARY TABLE IF EXISTS tmp_digests' AS 'Debug';
+ END IF;
+ DROP TEMPORARY TABLE IF EXISTS tmp_digests;
+ END IF;
+ CALL sys.execute_prepared_stmt(REPLACE(REPLACE(v_digest_table_template, '%{TEMPORARY}', 'TEMPORARY '), '%{TABLE_NAME}', 'tmp_digests'));
+
+ SET v_sql = CONCAT('INSERT INTO tmp_digests SELECT * FROM ',
+ IF(in_table IS NULL OR in_action = 'save', 'performance_schema.events_statements_summary_by_digest', v_quoted_table));
+ CALL sys.execute_prepared_stmt(v_sql);
+ END IF;
+
+ -- Go through the remaining actions
+ IF (in_action IN ('create_table', 'create_tmp')) THEN
+ IF (in_action = 'create_table') THEN
+ CALL sys.execute_prepared_stmt(REPLACE(REPLACE(v_digest_table_template, '%{TEMPORARY}', ''), '%{TABLE_NAME}', v_quoted_table));
+ ELSE
+ CALL sys.execute_prepared_stmt(REPLACE(REPLACE(v_digest_table_template, '%{TEMPORARY}', 'TEMPORARY '), '%{TABLE_NAME}', v_quoted_table));
+ END IF;
+ ELSEIF (in_action = 'save') THEN
+ CALL sys.execute_prepared_stmt(CONCAT('DELETE FROM ', v_quoted_table));
+ CALL sys.execute_prepared_stmt(CONCAT('INSERT INTO ', v_quoted_table, ' SELECT * FROM tmp_digests'));
+ ELSEIF (in_action = 'cleanup') THEN
+ DROP TEMPORARY TABLE IF EXISTS sys.tmp_digests;
+ DROP TEMPORARY TABLE IF EXISTS sys.tmp_digests_delta;
+ ELSEIF (in_action IN ('overall', 'delta')) THEN
+ -- These are almost the same - for delta calculate the delta in tmp_digests_delta and use that instead of tmp_digests.
+ -- And overall allows overriding the table to use.
+ IF (in_action = 'overall') THEN
+ IF (in_table IS NULL) THEN
+ SET v_digests_table = 'tmp_digests';
+ ELSE
+ SET v_digests_table = v_quoted_table;
+ END IF;
+ ELSE
+ SET v_digests_table = 'tmp_digests_delta';
+ DROP TEMPORARY TABLE IF EXISTS tmp_digests_delta;
+ CREATE TEMPORARY TABLE tmp_digests_delta LIKE tmp_digests;
+ SET v_sql = CONCAT('INSERT INTO tmp_digests_delta
+SELECT `d_end`.`SCHEMA_NAME`,
+ `d_end`.`DIGEST`,
+ `d_end`.`DIGEST_TEXT`,
+ `d_end`.`COUNT_STAR`-IFNULL(`d_start`.`COUNT_STAR`, 0) AS ''COUNT_STAR'',
+ `d_end`.`SUM_TIMER_WAIT`-IFNULL(`d_start`.`SUM_TIMER_WAIT`, 0) AS ''SUM_TIMER_WAIT'',
+ `d_end`.`MIN_TIMER_WAIT` AS ''MIN_TIMER_WAIT'',
+ IFNULL((`d_end`.`SUM_TIMER_WAIT`-IFNULL(`d_start`.`SUM_TIMER_WAIT`, 0))/NULLIF(`d_end`.`COUNT_STAR`-IFNULL(`d_start`.`COUNT_STAR`, 0), 0), 0) AS ''AVG_TIMER_WAIT'',
+ `d_end`.`MAX_TIMER_WAIT` AS ''MAX_TIMER_WAIT'',
+ `d_end`.`SUM_LOCK_TIME`-IFNULL(`d_start`.`SUM_LOCK_TIME`, 0) AS ''SUM_LOCK_TIME'',
+ `d_end`.`SUM_ERRORS`-IFNULL(`d_start`.`SUM_ERRORS`, 0) AS ''SUM_ERRORS'',
+ `d_end`.`SUM_WARNINGS`-IFNULL(`d_start`.`SUM_WARNINGS`, 0) AS ''SUM_WARNINGS'',
+ `d_end`.`SUM_ROWS_AFFECTED`-IFNULL(`d_start`.`SUM_ROWS_AFFECTED`, 0) AS ''SUM_ROWS_AFFECTED'',
+ `d_end`.`SUM_ROWS_SENT`-IFNULL(`d_start`.`SUM_ROWS_SENT`, 0) AS ''SUM_ROWS_SENT'',
+ `d_end`.`SUM_ROWS_EXAMINED`-IFNULL(`d_start`.`SUM_ROWS_EXAMINED`, 0) AS ''SUM_ROWS_EXAMINED'',
+ `d_end`.`SUM_CREATED_TMP_DISK_TABLES`-IFNULL(`d_start`.`SUM_CREATED_TMP_DISK_TABLES`, 0) AS ''SUM_CREATED_TMP_DISK_TABLES'',
+ `d_end`.`SUM_CREATED_TMP_TABLES`-IFNULL(`d_start`.`SUM_CREATED_TMP_TABLES`, 0) AS ''SUM_CREATED_TMP_TABLES'',
+ `d_end`.`SUM_SELECT_FULL_JOIN`-IFNULL(`d_start`.`SUM_SELECT_FULL_JOIN`, 0) AS ''SUM_SELECT_FULL_JOIN'',
+ `d_end`.`SUM_SELECT_FULL_RANGE_JOIN`-IFNULL(`d_start`.`SUM_SELECT_FULL_RANGE_JOIN`, 0) AS ''SUM_SELECT_FULL_RANGE_JOIN'',
+ `d_end`.`SUM_SELECT_RANGE`-IFNULL(`d_start`.`SUM_SELECT_RANGE`, 0) AS ''SUM_SELECT_RANGE'',
+ `d_end`.`SUM_SELECT_RANGE_CHECK`-IFNULL(`d_start`.`SUM_SELECT_RANGE_CHECK`, 0) AS ''SUM_SELECT_RANGE_CHECK'',
+ `d_end`.`SUM_SELECT_SCAN`-IFNULL(`d_start`.`SUM_SELECT_SCAN`, 0) AS ''SUM_SELECT_SCAN'',
+ `d_end`.`SUM_SORT_MERGE_PASSES`-IFNULL(`d_start`.`SUM_SORT_MERGE_PASSES`, 0) AS ''SUM_SORT_MERGE_PASSES'',
+ `d_end`.`SUM_SORT_RANGE`-IFNULL(`d_start`.`SUM_SORT_RANGE`, 0) AS ''SUM_SORT_RANGE'',
+ `d_end`.`SUM_SORT_ROWS`-IFNULL(`d_start`.`SUM_SORT_ROWS`, 0) AS ''SUM_SORT_ROWS'',
+ `d_end`.`SUM_SORT_SCAN`-IFNULL(`d_start`.`SUM_SORT_SCAN`, 0) AS ''SUM_SORT_SCAN'',
+ `d_end`.`SUM_NO_INDEX_USED`-IFNULL(`d_start`.`SUM_NO_INDEX_USED`, 0) AS ''SUM_NO_INDEX_USED'',
+ `d_end`.`SUM_NO_GOOD_INDEX_USED`-IFNULL(`d_start`.`SUM_NO_GOOD_INDEX_USED`, 0) AS ''SUM_NO_GOOD_INDEX_USED'',
+ `d_end`.`FIRST_SEEN`,
+ `d_end`.`LAST_SEEN`
+ FROM tmp_digests d_end
+ LEFT OUTER JOIN ', v_quoted_table, ' d_start ON `d_start`.`DIGEST` = `d_end`.`DIGEST`
+ AND (`d_start`.`SCHEMA_NAME` = `d_end`.`SCHEMA_NAME`
+ OR (`d_start`.`SCHEMA_NAME` IS NULL AND `d_end`.`SCHEMA_NAME` IS NULL)
+ )
+ WHERE `d_end`.`COUNT_STAR`-IFNULL(`d_start`.`COUNT_STAR`, 0) > 0');
+ CALL sys.execute_prepared_stmt(v_sql);
+ END IF;
+
+ IF (FIND_IN_SET('with_runtimes_in_95th_percentile', in_views)) THEN
+ SELECT 'Queries with Runtime in 95th Percentile' AS 'Next Output';
+
+ DROP TEMPORARY TABLE IF EXISTS tmp_digest_avg_latency_distribution1;
+ DROP TEMPORARY TABLE IF EXISTS tmp_digest_avg_latency_distribution2;
+ DROP TEMPORARY TABLE IF EXISTS tmp_digest_95th_percentile_by_avg_us;
+
+ CREATE TEMPORARY TABLE tmp_digest_avg_latency_distribution1 (
+ cnt bigint unsigned NOT NULL,
+ avg_us decimal(21,0) NOT NULL,
+ PRIMARY KEY (avg_us)
+ ) ENGINE=InnoDB;
+
+ SET v_sql = CONCAT('INSERT INTO tmp_digest_avg_latency_distribution1
+SELECT COUNT(*) cnt,
+ ROUND(avg_timer_wait/1000000) AS avg_us
+ FROM ', v_digests_table, '
+ GROUP BY avg_us');
+ CALL sys.execute_prepared_stmt(v_sql);
+
+ CREATE TEMPORARY TABLE tmp_digest_avg_latency_distribution2 LIKE tmp_digest_avg_latency_distribution1;
+ INSERT INTO tmp_digest_avg_latency_distribution2 SELECT * FROM tmp_digest_avg_latency_distribution1;
+
+ CREATE TEMPORARY TABLE tmp_digest_95th_percentile_by_avg_us (
+ avg_us decimal(21,0) NOT NULL,
+ percentile decimal(46,4) NOT NULL,
+ PRIMARY KEY (avg_us)
+ ) ENGINE=InnoDB;
+
+ SET v_sql = CONCAT('INSERT INTO tmp_digest_95th_percentile_by_avg_us
+SELECT s2.avg_us avg_us,
+ IFNULL(SUM(s1.cnt)/NULLIF((SELECT COUNT(*) FROM ', v_digests_table, '), 0), 0) percentile
+ FROM tmp_digest_avg_latency_distribution1 AS s1
+ JOIN tmp_digest_avg_latency_distribution2 AS s2 ON s1.avg_us <= s2.avg_us
+ GROUP BY s2.avg_us
+HAVING percentile > 0.95
+ ORDER BY percentile
+ LIMIT 1');
+ CALL sys.execute_prepared_stmt(v_sql);
+
+ SET v_sql =
+ REPLACE(
+ REPLACE(
+ (SELECT VIEW_DEFINITION
+ FROM information_schema.VIEWS
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statements_with_runtimes_in_95th_percentile'
+ ),
+ '`performance_schema`.`events_statements_summary_by_digest`',
+ v_digests_table
+ ),
+ 'sys.x$ps_digest_95th_percentile_by_avg_us',
+ '`sys`.`x$ps_digest_95th_percentile_by_avg_us`'
+ );
+ CALL sys.execute_prepared_stmt(v_sql);
+
+ DROP TEMPORARY TABLE tmp_digest_avg_latency_distribution1;
+ DROP TEMPORARY TABLE tmp_digest_avg_latency_distribution2;
+ DROP TEMPORARY TABLE tmp_digest_95th_percentile_by_avg_us;
+ END IF;
+
+ IF (FIND_IN_SET('analysis', in_views)) THEN
+ SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries Ordered by Total Latency') AS 'Next Output';
+ SET v_sql =
+ REPLACE(
+ (SELECT VIEW_DEFINITION
+ FROM information_schema.VIEWS
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statement_analysis'
+ ),
+ '`performance_schema`.`events_statements_summary_by_digest`',
+ v_digests_table
+ );
+ IF (@sys.statement_performance_analyzer.limit > 0) THEN
+ SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit);
+ END IF;
+ CALL sys.execute_prepared_stmt(v_sql);
+ END IF;
+
+ IF (FIND_IN_SET('with_errors_or_warnings', in_views)) THEN
+ SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries with Errors') AS 'Next Output';
+ SET v_sql =
+ REPLACE(
+ (SELECT VIEW_DEFINITION
+ FROM information_schema.VIEWS
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statements_with_errors_or_warnings'
+ ),
+ '`performance_schema`.`events_statements_summary_by_digest`',
+ v_digests_table
+ );
+ IF (@sys.statement_performance_analyzer.limit > 0) THEN
+ SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit);
+ END IF;
+ CALL sys.execute_prepared_stmt(v_sql);
+ END IF;
+
+ IF (FIND_IN_SET('with_full_table_scans', in_views)) THEN
+ SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries with Full Table Scan') AS 'Next Output';
+ SET v_sql =
+ REPLACE(
+ (SELECT VIEW_DEFINITION
+ FROM information_schema.VIEWS
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statements_with_full_table_scans'
+ ),
+ '`performance_schema`.`events_statements_summary_by_digest`',
+ v_digests_table
+ );
+ IF (@sys.statement_performance_analyzer.limit > 0) THEN
+ SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit);
+ END IF;
+ CALL sys.execute_prepared_stmt(v_sql);
+ END IF;
+
+ IF (FIND_IN_SET('with_sorting', in_views)) THEN
+ SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries with Sorting') AS 'Next Output';
+ SET v_sql =
+ REPLACE(
+ (SELECT VIEW_DEFINITION
+ FROM information_schema.VIEWS
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statements_with_sorting'
+ ),
+ '`performance_schema`.`events_statements_summary_by_digest`',
+ v_digests_table
+ );
+ IF (@sys.statement_performance_analyzer.limit > 0) THEN
+ SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit);
+ END IF;
+ CALL sys.execute_prepared_stmt(v_sql);
+ END IF;
+
+ IF (FIND_IN_SET('with_temp_tables', in_views)) THEN
+ SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries with Internal Temporary Tables') AS 'Next Output';
+ SET v_sql =
+ REPLACE(
+ (SELECT VIEW_DEFINITION
+ FROM information_schema.VIEWS
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'statements_with_temp_tables'
+ ),
+ '`performance_schema`.`events_statements_summary_by_digest`',
+ v_digests_table
+ );
+ IF (@sys.statement_performance_analyzer.limit > 0) THEN
+ SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit);
+ END IF;
+ CALL sys.execute_prepared_stmt(v_sql);
+ END IF;
+
+ IF (FIND_IN_SET('custom', in_views)) THEN
+ SELECT CONCAT('Top ', @sys.statement_performance_analyzer.limit, ' Queries Using Custom View') AS 'Next Output';
+
+ IF (@sys.statement_performance_analyzer.view IS NULL) THEN
+ SET @sys.statement_performance_analyzer.view = sys.sys_get_config('statement_performance_analyzer.view', NULL);
+ END IF;
+ IF (@sys.statement_performance_analyzer.view IS NULL) THEN
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = 'The @sys.statement_performance_analyzer.view user variable must be set with the view or query to use.';
+ END IF;
+
+ IF (NOT INSTR(@sys.statement_performance_analyzer.view, ' ')) THEN
+ -- No spaces, so can't be a query
+ IF (NOT INSTR(@sys.statement_performance_analyzer.view, '.')) THEN
+ -- No . in the table name - use current database
+ -- DATABASE() will be the database of the procedure
+ SET v_custom_db = DATABASE(),
+ v_custom_name = @sys.statement_performance_analyzer.view;
+ ELSE
+ SET v_custom_db = SUBSTRING_INDEX(@sys.statement_performance_analyzer.view, '.', 1);
+ SET v_custom_name = SUBSTRING(@sys.statement_performance_analyzer.view, CHAR_LENGTH(v_custom_db)+2);
+ END IF;
+
+ CALL sys.table_exists(v_custom_db, v_custom_name, v_custom_view_exists);
+ IF (v_custom_view_exists <> 'VIEW') THEN
+ SIGNAL SQLSTATE '45000'
+ SET MESSAGE_TEXT = 'The @sys.statement_performance_analyzer.view user variable is set but specified neither an existing view nor a query.';
+ END IF;
+
+ SET v_sql =
+ REPLACE(
+ (SELECT VIEW_DEFINITION
+ FROM information_schema.VIEWS
+ WHERE TABLE_SCHEMA = v_custom_db AND TABLE_NAME = v_custom_name
+ ),
+ '`performance_schema`.`events_statements_summary_by_digest`',
+ v_digests_table
+ );
+ ELSE
+ SET v_sql = REPLACE(@sys.statement_performance_analyzer.view, '`performance_schema`.`events_statements_summary_by_digest`', v_digests_table);
+ END IF;
+
+ IF (@sys.statement_performance_analyzer.limit > 0) THEN
+ SET v_sql = CONCAT(v_sql, ' LIMIT ', @sys.statement_performance_analyzer.limit);
+ END IF;
+
+ CALL sys.execute_prepared_stmt(v_sql);
+ END IF;
+ END IF;
+
+ -- Restore INSTRUMENTED for this thread
+ IF (v_this_thread_enabled = 'YES') THEN
+ CALL sys.ps_setup_enable_thread(CONNECTION_ID());
+ END IF;
+
+ IF (@log_bin = 1) THEN
+ SET sql_log_bin = @log_bin;
+ END IF;
+END$$
+
+DELIMITER ; \ No newline at end of file
diff --git a/scripts/sys_schema/procedures/table_exists.sql b/scripts/sys_schema/procedures/table_exists.sql
new file mode 100644
index 00000000..0f764032
--- /dev/null
+++ b/scripts/sys_schema/procedures/table_exists.sql
@@ -0,0 +1,201 @@
+-- Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; version 2 of the License.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+DROP PROCEDURE IF EXISTS table_exists;
+
+DELIMITER $$
+
+CREATE DEFINER='mariadb.sys'@'localhost' PROCEDURE table_exists (
+ IN in_db VARCHAR(64), IN in_table VARCHAR(64),
+ OUT out_exists ENUM('', 'BASE TABLE', 'VIEW', 'TEMPORARY', 'SEQUENCE', 'SYSTEM VIEW')
+ )
+ COMMENT '
+ Description
+ -----------
+
+ Tests whether the table specified in in_db and in_table exists either as a regular
+ table, or as a temporary table. The returned value corresponds to the table that
+ will be used, so if there''s both a temporary and a permanent table with the given
+ name, then ''TEMPORARY'' will be returned.
+
+ Parameters
+ -----------
+
+ in_db (VARCHAR(64)):
+ The database name to check for the existence of the table in.
+
+ in_table (VARCHAR(64)):
+ The name of the table to check the existence of.
+
+ out_exists ENUM('''', ''BASE TABLE'', ''VIEW'', ''TEMPORARY''):
+ The return value: whether the table exists. The value is one of:
+ * '''' - the table does not exist neither as a base table, view, sequence nor temporary table.
+ * ''BASE TABLE'' - the table name exists as a permanent base table table.
+ * ''VIEW'' - the table name exists as a view.
+ * ''TEMPORARY'' - the table name exists as a temporary table.
+ * ''SEQUENCE'' - the table name exists as a sequence.
+ * ''SYSTEM VIEW'' - the table name exists as a system view.
+
+ Example
+ --------
+
+ mysql> CREATE DATABASE db1;
+ Query OK, 1 row affected (0.07 sec)
+
+ mysql> use db1;
+ Database changed
+ mysql> CREATE TABLE t1 (id INT PRIMARY KEY);
+ Query OK, 0 rows affected (0.08 sec)
+
+ mysql> CREATE TABLE t2 (id INT PRIMARY KEY);
+ Query OK, 0 rows affected (0.08 sec)
+
+ mysql> CREATE view v_t1 AS SELECT * FROM t1;
+ Query OK, 0 rows affected (0.00 sec)
+
+ mysql> CREATE TEMPORARY TABLE t1 (id INT PRIMARY KEY);
+ Query OK, 0 rows affected (0.00 sec)
+
+ mysql> CALL sys.table_exists(''db1'', ''t1'', @exists); SELECT @exists;
+ Query OK, 0 rows affected (0.00 sec)
+
+ +------------+
+ | @exists |
+ +------------+
+ | TEMPORARY |
+ +------------+
+ 1 row in set (0.00 sec)
+
+ mysql> CALL sys.table_exists(''db1'', ''t2'', @exists); SELECT @exists;
+ Query OK, 0 rows affected (0.00 sec)
+
+ +------------+
+ | @exists |
+ +------------+
+ | BASE TABLE |
+ +------------+
+ 1 row in set (0.01 sec)
+
+ mysql> CALL sys.table_exists(''db1'', ''v_t1'', @exists); SELECT @exists;
+ Query OK, 0 rows affected (0.00 sec)
+
+ +---------+
+ | @exists |
+ +---------+
+ | VIEW |
+ +---------+
+ 1 row in set (0.00 sec)
+
+ MariaDB [sys]> CALL sys.table_exists(''db1'', ''s'', @exists); SELECT @exists;
+ Query OK, 0 rows affected (0.006 sec)
+
+ +----------+
+ | @exists |
+ +----------+
+ | SEQUENCE |
+ +----------+
+ 1 row in set (0.000 sec)
+
+ MariaDB [sys]> CALL table_exists(''information_schema'', ''user_variables'', @exists); SELECT @exists;
+ Query OK, 0 rows affected (0.003 sec)
+
+ +-------------+
+ | @exists |
+ +-------------+
+ | SYSTEM VIEW |
+ +-------------+
+ 1 row in set (0.001 sec)
+
+ mysql> CALL sys.table_exists(''db1'', ''t3'', @exists); SELECT @exists;
+ Query OK, 0 rows affected (0.01 sec)
+
+ +---------+
+ | @exists |
+ +---------+
+ | |
+ +---------+
+ 1 row in set (0.00 sec)
+ '
+ SQL SECURITY INVOKER
+ NOT DETERMINISTIC
+ CONTAINS SQL
+BEGIN
+ DECLARE v_error BOOLEAN DEFAULT FALSE;
+ DECLARE db_quoted VARCHAR(64);
+ DECLARE table_quoted VARCHAR(64);
+ DECLARE v_table_type VARCHAR(16) DEFAULT '';
+ DECLARE v_system_db BOOLEAN
+ DEFAULT LOWER(in_db) IN ('information_schema', 'performance_schema');
+ DECLARE CONTINUE HANDLER FOR 1050 SET v_error = TRUE;
+ DECLARE CONTINUE HANDLER FOR 1146 SET v_error = TRUE;
+
+ SET out_exists = '';
+ SET db_quoted = sys.quote_identifier(in_db);
+ SET table_quoted = sys.quote_identifier(in_table);
+
+ -- Verify whether the table name exists as a normal table
+ IF (EXISTS(SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = in_db AND TABLE_NAME = in_table)) THEN
+ -- Unfortunately the only way to determine whether there is also a temporary table is to try to create
+ -- a temporary table with the same name. If it succeeds the table didn't exist as a temporary table.
+ IF v_system_db = FALSE THEN
+ SET @sys.tmp.table_exists.SQL = CONCAT('CREATE TEMPORARY TABLE ',
+ db_quoted,
+ '.',
+ table_quoted,
+ '(id INT PRIMARY KEY)');
+ PREPARE stmt_create_table FROM @sys.tmp.table_exists.SQL;
+ EXECUTE stmt_create_table;
+ DEALLOCATE PREPARE stmt_create_table;
+
+ -- The temporary table was created, i.e. it didn't exist. Remove it again so we don't leave garbage around.
+ SET @sys.tmp.table_exists.SQL = CONCAT('DROP TEMPORARY TABLE ',
+ db_quoted,
+ '.',
+ table_quoted);
+ PREPARE stmt_drop_table FROM @sys.tmp.table_exists.SQL;
+ EXECUTE stmt_drop_table;
+ DEALLOCATE PREPARE stmt_drop_table;
+ END IF;
+ IF (v_error) THEN
+ SET out_exists = 'TEMPORARY';
+ ELSE
+ SET v_table_type = (SELECT TABLE_TYPE FROM information_schema.TABLES WHERE TABLE_SCHEMA = in_db AND TABLE_NAME = in_table);
+ -- Don't fail on table_type='SYSTEM VERSIONED'
+ -- but return 'BASE TABLE' for compatibility with existing tooling
+ IF v_table_type = 'SYSTEM VERSIONED' THEN
+ SET out_exists = 'BASE TABLE';
+ ELSE
+ SET out_exists = v_table_type;
+ END IF;
+ END IF;
+ ELSE
+ -- Check whether a temporary table exists with the same name.
+ -- If it does it's possible to SELECT from the table without causing an error.
+ -- If it does not exist even a PREPARE using the table will fail.
+ IF v_system_db = FALSE THEN
+ SET @sys.tmp.table_exists.SQL = CONCAT('SELECT COUNT(*) FROM ',
+ db_quoted,
+ '.',
+ table_quoted);
+ PREPARE stmt_select FROM @sys.tmp.table_exists.SQL;
+ IF (NOT v_error) THEN
+ DEALLOCATE PREPARE stmt_select;
+ SET out_exists = 'TEMPORARY';
+ END IF;
+ END IF;
+ END IF;
+END$$
+
+DELIMITER ;