├── .gitignore ├── Makefile ├── README.md ├── docker-compose.yml └── services ├── anemometer ├── README.md └── config │ └── anemometer │ └── config.inc.php ├── app ├── Dockerfile ├── README.md ├── commands │ ├── prepare.php │ ├── scheduled_select_big.php │ └── scheduled_select_small.php └── config │ └── cron │ └── crontab ├── grafana ├── config │ ├── dashboards │ │ └── playground.yml │ └── datasources │ │ └── prometheus.yml └── provisioning │ └── dashboards │ ├── mysql_innodb_metrics.json │ └── mysql_overview.json ├── mysql ├── config │ └── mysql │ │ ├── docker.cnf │ │ └── my.cnf └── dump │ └── playground-db.sql ├── prometheus └── config │ └── prometheus.yml ├── slow-log-cron ├── Dockerfile ├── README.md ├── commands │ └── query-digest.sh └── config │ ├── cron │ └── crontab │ └── logrotate │ └── slow_log.conf └── sysbench ├── commands └── tests.sh ├── reports └── .gitignore └── tests ├── insert.lua └── select.lua /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | up: 2 | docker-compose up -d 3 | 4 | status: 5 | docker-compose ps 6 | 7 | stop: 8 | docker-compose stop 9 | 10 | reload: 11 | docker-compose stop && docker-compose up -d 12 | 13 | prepare-db: 14 | docker exec -it playground-app php /commands/prepare.php 15 | 16 | benchmark: 17 | docker exec -it playground-sysbench bash /commands/tests.sh 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## MySQL monitoring with Prometheus, Grafana, Anemometer 2 | 3 | This example provides an easy way to get some knowledge on how to use 4 | MySQL monitoring tools. 5 | 6 | ### Requirements 7 | - Docker 8 | - Docker compose 9 | - make 10 | 11 | ### Warning 12 | This setup should not be used for production purposes as is. 13 | Consider proper configuration for your case. 14 | 15 | ### How to use 16 | 17 | ##### Initialize 18 | Run `make up` 19 | 20 | ##### Seed tables with example data 21 | Run `make prepare-db` 22 | 23 | ### Resources 24 | - Grafana: http://localhost:3000 25 | - Prometheus web UI: http://localhost:9090/targets 26 | - Anemometer: http://localhost 27 | - mysqld_exporter: http://localhost:9104/metrics 28 | - node_exporter: http://localhost:9100/metrics 29 | 30 | ### Sysbench benchmark examples 31 | 32 | Checkout some example benchmarks for SQL queries performance: 33 | `services/sysbench/tests/` 34 | 35 | ##### Run benchmarks 36 | `make benchmark` 37 | 38 | Checkout results in `services/sysbench/reports/` directory 39 | 40 | #### Readme 41 | Check README.md files for services 42 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | playground-anemometer: 6 | command: ["php", "-S", "0.0.0.0:80"] 7 | container_name: playground-anemometer 8 | image: boxinc/anemometer 9 | volumes: 10 | - ./services/anemometer/config/anemometer:/var/www/html/conf 11 | - playground-db:/var/lib/mysql 12 | ports: 13 | - 80:80 14 | 15 | playground-app: 16 | build: ./services/app 17 | command: ["cron", "-f"] 18 | container_name: playground-app 19 | volumes: 20 | - ./services/app/commands:/commands 21 | 22 | playground-db: 23 | command: --default-authentication-plugin=mysql_native_password 24 | container_name: playground-db 25 | environment: 26 | MYSQL_ALLOW_EMPTY_PASSWORD: 'true' 27 | MYSQL_DATABASE: playground-db 28 | MYSQL_USER: root 29 | MYSQL_PASSWORD: '' 30 | image: mysql:8.0 31 | ports: 32 | - 3306:3306 33 | volumes: 34 | - ./services/mysql/dump:/docker-entrypoint-initdb.d 35 | - ./services/mysql/config/supervisor:/etc/supervisor/conf.d 36 | - ./services/mysql/config/mysql:/etc/mysql/conf.d 37 | - playground-db:/var/lib/mysql 38 | 39 | playground-grafana: 40 | container_name: playground-grafana 41 | image: grafana/grafana:6.7.3 42 | ports: 43 | - 3000:3000 44 | volumes: 45 | - ./services/grafana/provisioning/dashboards:/var/lib/grafana/dashboards 46 | - ./services/grafana/config:/etc/grafana/provisioning 47 | 48 | playground-mysqld-exporter: 49 | command: [ 50 | "--collect.engine_innodb_status", 51 | "--collect.info_schema.clientstats", 52 | "--collect.info_schema.innodb_metrics", 53 | "--collect.info_schema.innodb_tablespaces", 54 | "--collect.perf_schema.file_events", 55 | "--collect.info_schema.innodb_cmp", 56 | "--collect.info_schema.processlist", 57 | ] 58 | container_name: playground-mysqld-exporter 59 | image: prom/mysqld-exporter 60 | ports: 61 | - 9104:9104 62 | environment: 63 | DATA_SOURCE_NAME: "root@(playground-db:3306)/" 64 | 65 | playground-node-exporter: 66 | command: [ 67 | "--path.procfs=/host/proc", 68 | "--path.rootfs=/rootfs", 69 | "--path.sysfs=/host/sys", 70 | "--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)", 71 | ] 72 | container_name: playground-node-exporter 73 | image: prom/node-exporter 74 | ports: 75 | - 9100:9100 76 | volumes: 77 | - /proc:/host/proc:ro 78 | - /sys:/host/sys:ro 79 | - /:/rootfs:ro 80 | 81 | playground-prometheus: 82 | command: 83 | - --config.file=/etc/prometheus/prometheus.yml 84 | container_name: playground-prometheus 85 | image: prom/prometheus 86 | ports: 87 | - 9090:9090 88 | volumes: 89 | - ./services/prometheus/config:/etc/prometheus/ 90 | 91 | playground-slow-log-cron: 92 | build: ./services/slow-log-cron 93 | command: ["cron", "-f"] 94 | container_name: playground-slow-log-cron 95 | volumes: 96 | - ./services/slow-log-cron/commands:/commands 97 | - ./services/slow-log-cron/config/logrotate:/etc/logrotate.d 98 | - playground-db:/var/lib/mysql 99 | 100 | playground-sysbench: 101 | container_name: playground-sysbench 102 | image: severalnines/sysbench 103 | tty: true 104 | volumes: 105 | - ./services/sysbench/commands:/commands 106 | - ./services/sysbench/reports:/reports 107 | - ./services/sysbench/tests:/usr/share/sysbench 108 | 109 | volumes: 110 | playground-db: 111 | driver: local 112 | -------------------------------------------------------------------------------- /services/anemometer/README.md: -------------------------------------------------------------------------------- 1 | ### Service `Anemometer` 2 | 3 | `Anemometer` service provides pretty web interface to analyse slow log file data. 4 | Slow log file data is processed and prepared beforehand by `slow-log-cron` service. 5 | 6 | Data source tables for `Anemometer` service are configured in `services/anemometer/config/anemometer/config.inc.php` file. 7 | -------------------------------------------------------------------------------- /services/anemometer/config/anemometer/config.inc.php: -------------------------------------------------------------------------------- 1 | 8 | * @license Apache 2.0 license. See LICENSE document for more info 9 | * @created 2012-01-01 10 | * 11 | **/ 12 | 13 | /** 14 | * Datasources are a combination of database server, database name and the tables 15 | * used for reporting. This enables you to set up collection to different review 16 | * and review_history tables to keep data separate. 17 | * 18 | * For instance, you might want a different datasource for your development environment 19 | * and your production environment, and keep them on different servers. Or 20 | * you might want to log different applications into different tables, and have 21 | * something like app1_query_review and app2_query_review. 22 | * 23 | * The array of tables *must* include the review and review_history table (with 24 | * whatever name you gave them when collecting the data.) The review table must 25 | * be defined as 'fact' and the history table must be defined as 'dimension'. 26 | * These are table aliases that are used when building the search form and queries 27 | * against them. 28 | * 29 | * You can add as many datasources as you wish. If you only define one, then 30 | * the index page with no arguments will automatically take you to the report page. 31 | * If there are more than one, then you will be given a page to choose which 32 | * one you want to report on. 33 | * 34 | */ 35 | $conf['datasources']['playground-db'] = array( 36 | 'host' => 'playground-db', 37 | 'port' => 3306, 38 | 'db' => 'slow_query_log', 39 | 'user' => 'root', 40 | 'password' => '', 41 | 'tables' => array( 42 | 'global_query_review' => 'fact', 43 | 'global_query_review_history' => 'dimension' 44 | ), 45 | 'source_type' => 'slow_query_log' 46 | ); 47 | 48 | 49 | /** 50 | * This setting defines which report interface you get first when selecting a 51 | * datasource. There are two possible values: report and graph_search 52 | * 53 | * 'report' will take you to the more verbose search form that displays 54 | * results as an html table. 55 | * 56 | * 'graph_search' will take you to the search form which displays results as an 57 | * interactive graph, and lets you select ranges in that graph. The queries from 58 | * the selected time range will be displayed as a table below. 59 | **/ 60 | $conf['default_report_action'] = 'report'; 61 | 62 | /** 63 | * Set the reviewers list to the names of all people who might review queries. 64 | * This allows you to better track who has evaluated a query. 65 | * 66 | * These names will be displayed near the comments section on detail page when you 67 | * select a query. 68 | * 69 | * review_types can be configured with whichever values you want. A basic list has 70 | * been provided. These will also show up on the query detail page, and the status 71 | * can be set when you review a query. 72 | **/ 73 | $conf['reviewers'] = array('dba1', 'dba2'); 74 | $conf['review_types'] = array('good', 'bad', 'ticket-created', 'needs-fix', 'fixed', 'needs-analysis', 'review-again'); 75 | 76 | /** 77 | * These are default values for reports. You can choose which column headings you 78 | * wish to see by default, the date range for the report, and other values as well. 79 | * Take care when changing values here, since you can create some pretty strange results. 80 | * It's best to keep a copy of the original values so you can change them back if needed. 81 | * 82 | * There are three reports here: report, history and graph 83 | * 84 | * report_defaults contains the settings for the basic html table search. 85 | * 86 | * history_defaults contains the settings for the query history shown at the bottom 87 | * of the query details page. 88 | * 89 | * graph_defaults contains the settings for the interactive graph search page 90 | * where you can select specific time ranges from a graph. 91 | **/ 92 | $conf['history_defaults'] = array( 93 | 'output' => 'table', 94 | 'fact-group' => 'date', 95 | 'fact-order' => 'date DESC', 96 | 'fact-limit' => '90', 97 | 'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime('-90 day')), 98 | 'dimension-ts_min_end' => date("Y-m-d H:i:s"), 99 | 'table_fields' => array('date', 'index_ratio', 'query_time_avg', 'rows_sent_avg', 'ts_cnt', 'Query_time_sum', 'Lock_time_sum', 'Rows_sent_sum', 'Rows_examined_sum', 'Tmp_table_sum', 'Filesort_sum', 'Full_scan_sum') 100 | ); 101 | 102 | $conf['report_defaults'] = array( 103 | 'fact-group' => 'checksum', 104 | 'fact-order' => 'Query_time_sum DESC', 105 | 'fact-limit' => '20', 106 | 'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime('-1 day')), 107 | 'dimension-ts_min_end' => date("Y-m-d H:i:s"), 108 | 'table_fields' => array('checksum', 'snippet', 'index_ratio', 'query_time_avg', 'rows_sent_avg', 'ts_cnt', 'Query_time_sum', 'Lock_time_sum', 'Rows_sent_sum', 'Rows_examined_sum', 'Tmp_table_sum', 'Filesort_sum', 'Full_scan_sum'), 109 | 'dimension-pivot-hostname_max' => null 110 | ); 111 | 112 | $conf['graph_defaults'] = array( 113 | 'fact-group' => 'minute_ts', 114 | 'fact-order' => 'minute_ts', 115 | 'fact-limit' => '', 116 | 'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime('-7 day')), 117 | 'dimension-ts_min_end' => date("Y-m-d H:i:s"), 118 | 'table_fields' => array('minute_ts'), 119 | // hack ... fix is to make query builder select the group and order fields, 120 | // then table fields only has to contain the plot_field 121 | 'plot_field' => 'Query_time_sum', 122 | ); 123 | 124 | // these are the default values for mysql 5.6 performance schema datasources 125 | $conf['report_defaults']['performance_schema'] = array( 126 | 'fact-order' => 'SUM_TIMER_WAIT DESC', 127 | 'fact-limit' => '20', 128 | 'fact-group' => 'DIGEST', 129 | 'table_fields' => array('DIGEST', 'snippet', 'index_ratio', 'COUNT_STAR', 'SUM_TIMER_WAIT', 'SUM_LOCK_TIME', 'SUM_ROWS_AFFECTED', 'SUM_ROWS_SENT', 'SUM_ROWS_EXAMINED', 'SUM_CREATED_TMP_TABLES', 'SUM_SORT_SCAN', 'SUM_NO_INDEX_USED') 130 | ); 131 | 132 | // these are the default values for mysql 5.6 performance schema datasources 133 | $conf['history_defaults']['performance_schema'] = array( 134 | 'fact-order' => 'SUM_TIMER_WAIT DESC', 135 | 'fact-limit' => '20', 136 | 'fact-group' => 'DIGEST', 137 | 'table_fields' => array('DIGEST', 'index_ratio', 'COUNT_STAR', 'SUM_LOCK_TIME', 'SUM_ROWS_AFFECTED', 'SUM_ROWS_SENT', 'SUM_ROWS_EXAMINED', 'SUM_CREATED_TMP_TABLES', 'SUM_SORT_SCAN', 'SUM_NO_INDEX_USED') 138 | ); 139 | 140 | // these are the default values for using performance schema to save your own 141 | // query history in a table structure similar to percona's pt-query-digest format 142 | $conf['report_defaults']['performance_schema_history'] = array( 143 | 'fact-group' => 'DIGEST', 144 | 'fact-order' => 'SUM_TIMER_WAIT DESC', 145 | 'fact-limit' => '20', 146 | 'dimension-FIRST_SEEN_start' => date("Y-m-d H:i:s", strtotime('-1 day')), 147 | 'dimension-FIRST_SEEN_end' => date("Y-m-d H:i:s"), 148 | 'table_fields' => array('DIGEST', 'snippet', 'index_ratio', 'COUNT_STAR', 'SUM_LOCK_TIME', 'SUM_ROWS_AFFECTED', 'SUM_ROWS_SENT', 'SUM_ROWS_EXAMINED', 'SUM_CREATED_TMP_TABLES', 'SUM_SORT_SCAN', 'SUM_NO_INDEX_USED') 149 | ); 150 | 151 | $conf['graph_defaults']['performance_schema_history'] = array( 152 | 'fact-group' => 'minute_ts', 153 | 'fact-order' => 'minute_ts', 154 | 'fact-limit' => '', 155 | 'dimension-FIRST_SEEN_start' => date("Y-m-d H:i:s", strtotime('-7 day')), 156 | 'dimension-FIRST_SEEN_end' => date("Y-m-d H:i:s"), 157 | 'table_fields' => array('minute_ts'), 158 | // hack ... fix is to make query builder select the group and order fields, 159 | // then table fields only has to contain the plot_field 160 | 'plot_field' => 'SUM_TIMER_WAIT', 161 | 'dimension-pivot-hostname_max' => null 162 | ); 163 | 164 | $conf['history_defaults']['performance_schema_history'] = array( 165 | 'output' => 'table', 166 | 'fact-group' => 'date', 167 | 'fact-order' => 'date DESC', 168 | 'fact-limit' => '90', 169 | 'dimension-FIRST_SEEN_start' => date("Y-m-d H:i:s", strtotime('-90 day')), 170 | 'dimension-FIRST_SEEN_end' => date("Y-m-d H:i:s"), 171 | 'table_fields' => array('date', 'snippet', 'index_ratio', 'COUNT_STAR', 'SUM_LOCK_TIME', 'SUM_ROWS_AFFECTED', 'SUM_ROWS_SENT', 'SUM_ROWS_EXAMINED', 'SUM_CREATED_TMP_TABLES', 'SUM_SORT_SCAN', 'SUM_NO_INDEX_USED') 172 | ); 173 | /** 174 | * Plugins are optional extra information that can be displayed, but often 175 | * relies on information specific to your system, and has to be set manually. 176 | * 177 | * This includes the explain plan information, percona toolkit plugins like 178 | * visual explain and query advisor output, and the table structure and status 179 | * information. 180 | * 181 | * To get the explain plan information, this application needs a way to figure 182 | * out exactly where the original query came from, so it can connect to the database 183 | * and run EXPLAIN SELECT ... ; There is not enough information collected by 184 | * the query digest to always know this information, so a callback function is 185 | * used to help provide the extra information. 186 | * 187 | * This callback function is passed the full row from the history table, this gives 188 | * it access to the full query sample collected, and fields such as hostname_max 189 | * if they were defined in your _history table and collected. 190 | * 191 | * To get the explain plan, the callback function must return an array that looks like 192 | * the following: 193 | * 194 | * array( 195 | * 'host' => $host, 196 | * 'port' => $port, 197 | * 'db' => $database_name, 198 | * 'user' => $username, 199 | * 'password' => $password 200 | * ); 201 | * 202 | * If the callback cannot return that information, then the application will 203 | * not display the EXPLAIN plan. 204 | * 205 | * A sample callback has been provided below, you will at least need to fill 206 | * in the username and password fields, and it might work for most users. 207 | * 208 | * 209 | * pt-visual-explain and pt-query-advisor: 210 | * For these plugins, you simply need to provide the full path to those scripts 211 | * on your system. They will be called when appropriate. 212 | * 213 | * SHOW TABLE STATUS and SHOW CREATE TABLE: 214 | * Simply set these to true if you want the information to be displayed. They 215 | * will use the same connection information extracted by the explain callback 216 | * plugin. If a valid database connection can't be made from the result of the 217 | * explain plugin, then these sections will not be displayed. 218 | * 219 | */ 220 | $conf['plugins'] = array( 221 | 222 | 'visual_explain' => '/usr/bin/pt-visual-explain', 223 | # percona toolkit has removed query advisor 224 | # 'query_advisor' => '/usr/bin/pt-query-advisor', 225 | 226 | 'show_create' => true, 227 | 'show_status' => true, 228 | 229 | 'explain' => function ($sample) { 230 | $conn = array(); 231 | 232 | if (!array_key_exists('hostname_max', $sample) or strlen($sample['hostname_max']) < 5) { 233 | return; 234 | } 235 | 236 | $pos = strpos($sample['hostname_max'], ':'); 237 | if ($pos === false) { 238 | $conn['port'] = 3306; 239 | $conn['host'] = $sample['hostname_max']; 240 | } else { 241 | $parts = preg_split("/:/", $sample['hostname_max']); 242 | $conn['host'] = $parts[0]; 243 | $conn['port'] = $parts[1]; 244 | } 245 | 246 | $conn['db'] = 'mysql'; 247 | if ($sample['db_max'] != '') { 248 | $conn['db'] = $sample['db_max']; 249 | } 250 | 251 | $conn['user'] = 'root'; 252 | $conn['password'] = ''; 253 | 254 | return $conn; 255 | }, 256 | ); 257 | 258 | /** 259 | * This is configuration information for how the actual sql queries are built 260 | * from the form values. It shouldn't be necessary to modify any of these 261 | * values, and you can possibly break reporting functionality by doing so. 262 | * 263 | * For more information, see the phpDoc or comments in the MySQLTableReport class. 264 | */ 265 | $conf['reports']['slow_query_log'] = array( 266 | // joins 267 | 'join' => array( 268 | 'dimension' => 'USING (`checksum`)' 269 | ), 270 | 271 | // form fields 272 | // these are the fields that the report object looks for to build the query 273 | // they are defined by the table *alias* and not the name. 274 | // The names are defined by the datasource 275 | 'fields' => array( 276 | 'fact' => array( 277 | 'group' => 'group', 278 | 'order' => 'order', 279 | 'having' => 'having', 280 | 'limit' => 'limit', 281 | 'first_seen' => 'clear|reldate|ge|where', 282 | 'where' => 'raw_where', 283 | 'sample' => 'clear|like|where', 284 | 'checksum' => 'clear|where', 285 | 'reviewed_status' => 'clear|where', 286 | 287 | ), 288 | 289 | 'dimension' => array( 290 | 'extra_fields' => 'where', 291 | 'hostname_max' => 'clear|where', 292 | 'ts_min' => 'date_range|reldate|clear|where', 293 | 'pivot-hostname_max' => 'clear|pivot|select', 294 | 'pivot-checksum' => 'clear|pivot|select', 295 | ), 296 | ), 297 | // custom fields 298 | 'custom_fields' => array( 299 | 'checksum' => 'checksum', 300 | 'date' => 'DATE(ts_min)', 301 | 'hour' => 'substring(ts_min,1,13)', 302 | 'hour_ts' => 'round(unix_timestamp(substring(ts_min,1,13)))', 303 | 'minute_ts' => 'round(unix_timestamp(substring(ts_min,1,16)))', 304 | 'minute' => 'substring(ts_min,1,16)', 305 | 'snippet' => 'LEFT(dimension.sample,20)', 306 | 'index_ratio' => 'ROUND(SUM(Rows_examined_sum)/SUM(rows_sent_sum),2)', 307 | 'query_time_avg' => 'SUM(Query_time_sum) / SUM(ts_cnt)', 308 | 'rows_sent_avg' => 'ROUND(SUM(Rows_sent_sum)/SUM(ts_cnt),0)', 309 | ), 310 | 311 | 'callbacks' => array( 312 | 'table' => array( 313 | 'date' => function ($x) { 314 | $type = ''; 315 | if (date('N', strtotime($x)) >= 6) { 316 | $type = 'weekend'; 317 | } 318 | return array($x, $type); 319 | }, 320 | 'checksum' => function ($x) { 321 | return array(dec2hex($x), ''); 322 | } 323 | ) 324 | ) 325 | 326 | ); 327 | 328 | $conf['reports']['performance_schema'] = array( 329 | // form fields 330 | 'fields' => array( 331 | 'fact' => array( 332 | //'group' => 'group', 333 | 'order' => 'order', 334 | 'having' => 'having', 335 | 'limit' => 'limit', 336 | 'first_seen' => 'date_range|reldate|clear|where', 337 | 'where' => 'raw_where', 338 | 'DIGEST' => 'clear|where', 339 | 'DIGEST_TEXT' => 'clear|like|where', 340 | 'group' => 'group', 341 | ), 342 | ), 343 | // custom fields 344 | 'custom_fields' => array( 345 | 'snippet' => 'LEFT(fact.DIGEST_TEXT,20)', 346 | 'index_ratio' => 'ROUND(SUM_ROWS_EXAMINED/SUM_ROWS_SENT,2)', 347 | 'rows_sent_avg' => 'ROUND(SUM_ROWS_SENT/COUNT_STAR,0)', 348 | 349 | ), 350 | 351 | 'special_field_names' => array( 352 | 'time' => 'FIRST_SEEN', 353 | 'checksum' => 'DIGEST', 354 | 'sample' => 'DIGEST_TEXT', 355 | 'fingerprint' => 'DIGEST_TEXT', 356 | ), 357 | ); 358 | 359 | $conf['reports']['performance_schema_history'] = array( 360 | // joins 361 | 'join' => array( 362 | 'dimension' => 'USING (`DIGEST`)' 363 | ), 364 | 365 | // form fields 366 | 'fields' => array( 367 | 'fact' => array( 368 | 'group' => 'group', 369 | 'order' => 'order', 370 | 'having' => 'having', 371 | 'limit' => 'limit', 372 | 'first_seen' => 'clear|reldate|ge|where', 373 | 'where' => 'raw_where', 374 | 'DIGEST_TEXT' => 'clear|like|where', 375 | 'DIGEST' => 'clear|where', 376 | 'reviewed_status' => 'clear|where', 377 | 378 | ), 379 | 380 | 'dimension' => array( 381 | 'extra_fields' => 'where', 382 | 'hostname' => 'clear|where', 383 | 'FIRST_SEEN' => 'date_range|reldate|clear|where', 384 | 'pivot-hostname' => 'clear|pivot|select', 385 | ), 386 | ), 387 | // custom fields 388 | 'custom_fields' => array( 389 | 'date' => 'DATE(fact.FIRST_SEEN)', 390 | 'snippet' => 'LEFT(fact.DIGEST_TEXT,20)', 391 | 'index_ratio' => 'ROUND(SUM_ROWS_EXAMINED/SUM_ROWS_SENT,2)', 392 | 'rows_sent_avg' => 'ROUND(SUM_ROWS_SENT/COUNT_STAR,0)', 393 | 'hour' => 'substring(dimension.FIRST_SEEN,1,13)', 394 | 'hour_ts' => 'round(unix_timestamp(substring(dimension.FIRST_SEEN,1,13)))', 395 | 'minute_ts' => 'round(unix_timestamp(substring(dimension.FIRST_SEEN,1,16)))', 396 | 'minute' => 'substring(dimension.FIRST_SEEN,1,16)', 397 | ), 398 | 399 | 'special_field_names' => array( 400 | 'time' => 'FIRST_SEEN', 401 | 'checksum' => 'DIGEST', 402 | 'hostname' => 'hostname', 403 | 'sample' => 'DIGEST_TEXT' 404 | ), 405 | ); 406 | 407 | /** 408 | * end of configuration settings 409 | */ 410 | -------------------------------------------------------------------------------- /services/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-cli 2 | 3 | RUN docker-php-ext-install pdo_mysql 4 | 5 | RUN apt update 6 | 7 | RUN apt install -y cron nano 8 | 9 | COPY ./config/cron/crontab /etc/cron.d/crontab 10 | RUN crontab /etc/cron.d/crontab 11 | -------------------------------------------------------------------------------- /services/app/README.md: -------------------------------------------------------------------------------- 1 | ### Service `App` 2 | 3 | Service `App` is used to prepare test data and to emulate some workload. 4 | 5 | #### Data preparation 6 | 7 | To prepare test data use: 8 | ```$xslt 9 | $ make prepare-db 10 | ``` 11 | This will insert 100K and 3M records to `test_table_small` and `test_table_big` tables. 12 | 13 | #### Emulating workloads 14 | 15 | Check the schedule for running example queries to test tables at `services/app/config/cron/crontab` file. 16 | -------------------------------------------------------------------------------- /services/app/commands/prepare.php: -------------------------------------------------------------------------------- 1 | prepare("INSERT INTO $tableName (number, string_short, string_long) VALUES (?, ?, ?)"); 34 | $steps = $recordsCount / $insertBatchSize; 35 | 36 | for ($j = 1; $j <= $steps; $j++) { 37 | echo "Step: $j of $steps" . PHP_EOL; 38 | $values = []; 39 | for ($i = 0; $i < $insertBatchSize; $i++) { 40 | $values[] = [ 41 | rand(1, 100), 42 | generateRandomString(5), 43 | generateRandomString(500), 44 | ]; 45 | } 46 | $pdo->beginTransaction(); 47 | foreach ($values as $row) { 48 | $stmt->execute($row); 49 | } 50 | $pdo->commit(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /services/app/commands/scheduled_select_big.php: -------------------------------------------------------------------------------- 1 | prepare("SELECT * FROM test_table_big WHERE number = ? ORDER BY number LIMIT 20000"); 11 | 12 | for($i = 1; $i <= BAD_QUERY_RUN_COUNT; $i++) { 13 | echo "Step: $i of ". BAD_QUERY_RUN_COUNT . PHP_EOL; 14 | $timeStart = microtime(true); 15 | 16 | $params = [rand(1,100)]; 17 | 18 | if ($stmt->execute($params)) { 19 | while ($row = $stmt->fetch()) {} 20 | } 21 | 22 | echo 'Query finished in: ' . (microtime(true) - $timeStart) . PHP_EOL . PHP_EOL; 23 | } 24 | -------------------------------------------------------------------------------- /services/app/commands/scheduled_select_small.php: -------------------------------------------------------------------------------- 1 | query($query); 18 | 19 | echo 'Query finished in: ' . (microtime(true) - $timeStart) . PHP_EOL . PHP_EOL; 20 | sleep(1); 21 | } 22 | -------------------------------------------------------------------------------- /services/app/config/cron/crontab: -------------------------------------------------------------------------------- 1 | 5-9,15-19,25-29,35-39,45-49,55-59 * * * * /usr/local/bin/php /commands/scheduled_select_small.php 2 | 0-2,10-12,20-22,30-32,40-42,50-52 * * * * /usr/local/bin/php /commands/scheduled_select_big.php 3 | -------------------------------------------------------------------------------- /services/grafana/config/dashboards/playground.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | # an unique provider name. Required 5 | - name: 'Playground' 6 | # Org id. Default to 1 7 | orgId: 1 8 | # name of the dashboard folder. 9 | folder: '' 10 | # folder UID. will be automatically generated if not specified 11 | folderUid: '' 12 | # provider type. Default to 'file' 13 | type: file 14 | # disable dashboard deletion 15 | disableDeletion: false 16 | # enable dashboard editing 17 | editable: true 18 | # how often Grafana will scan for changed dashboards 19 | updateIntervalSeconds: 10 20 | # allow updating provisioned dashboards from the UI 21 | allowUiUpdates: false 22 | options: 23 | # path to dashboard files on disk. Required when using the 'file' type 24 | path: /var/lib/grafana/dashboards 25 | -------------------------------------------------------------------------------- /services/grafana/config/datasources/prometheus.yml: -------------------------------------------------------------------------------- 1 | # config file version 2 | apiVersion: 1 3 | 4 | # list of datasources that should be deleted from the database 5 | deleteDatasources: 6 | - name: Prometheus 7 | orgId: 1 8 | 9 | # list of datasources to insert/update depending 10 | # whats available in the database 11 | datasources: 12 | # name of the datasource. Required 13 | - name: Prometheus 14 | # datasource type. Required 15 | type: prometheus 16 | # access mode. direct or proxy. Required 17 | access: proxy 18 | # org id. will default to orgId 1 if not specified 19 | orgId: 1 20 | # url 21 | url: http://playground-prometheus:9090 22 | # database password, if used 23 | password: 24 | # database user, if used 25 | user: 26 | # database name, if used 27 | database: 28 | # enable/disable basic auth 29 | basicAuth: false 30 | # basic auth username, if used 31 | basicAuthUser: 32 | # basic auth password, if used 33 | basicAuthPassword: 34 | # enable/disable with credentials headers 35 | withCredentials: 36 | # mark as default datasource. Max one per org 37 | isDefault: true 38 | # fields that will be converted to json and stored in json_data 39 | jsonData: 40 | graphiteVersion: "1.1" 41 | tlsAuth: false 42 | tlsAuthWithCACert: false 43 | # json object of data that will be encrypted. 44 | secureJsonData: 45 | tlsCACert: "..." 46 | tlsClientCert: "..." 47 | tlsClientKey: "..." 48 | version: 1 49 | # allow users to edit datasources from the UI. 50 | editable: true -------------------------------------------------------------------------------- /services/grafana/provisioning/dashboards/mysql_innodb_metrics.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": false, 9 | "iconColor": "#e0752d", 10 | "limit": 100, 11 | "name": "PMM Annotations", 12 | "showIn": 0, 13 | "tags": [ 14 | "pmm_annotation" 15 | ], 16 | "type": "tags" 17 | }, 18 | { 19 | "builtIn": 1, 20 | "datasource": "-- Grafana --", 21 | "enable": true, 22 | "hide": true, 23 | "iconColor": "#6ed0e0", 24 | "limit": 100, 25 | "name": "Annotations & Alerts", 26 | "showIn": 0, 27 | "tags": [], 28 | "type": "dashboard" 29 | } 30 | ] 31 | }, 32 | "editable": true, 33 | "gnetId": null, 34 | "graphTooltip": 1, 35 | "id": 3, 36 | "iteration": 1590428181254, 37 | "links": [ 38 | { 39 | "icon": "dashboard", 40 | "includeVars": true, 41 | "keepTime": true, 42 | "tags": [ 43 | "QAN" 44 | ], 45 | "targetBlank": false, 46 | "title": "Query Analytics", 47 | "type": "link", 48 | "url": "/graph/dashboard/db/_pmm-query-analytics" 49 | }, 50 | { 51 | "asDropdown": true, 52 | "includeVars": true, 53 | "keepTime": true, 54 | "tags": [ 55 | "OS" 56 | ], 57 | "targetBlank": false, 58 | "title": "OS", 59 | "type": "dashboards" 60 | }, 61 | { 62 | "asDropdown": true, 63 | "includeVars": true, 64 | "keepTime": true, 65 | "tags": [ 66 | "MySQL" 67 | ], 68 | "targetBlank": false, 69 | "title": "MySQL", 70 | "type": "dashboards" 71 | }, 72 | { 73 | "asDropdown": true, 74 | "includeVars": true, 75 | "keepTime": true, 76 | "tags": [ 77 | "MongoDB" 78 | ], 79 | "targetBlank": false, 80 | "title": "MongoDB", 81 | "type": "dashboards" 82 | }, 83 | { 84 | "asDropdown": true, 85 | "includeVars": true, 86 | "keepTime": true, 87 | "tags": [ 88 | "PostgreSQL" 89 | ], 90 | "targetBlank": false, 91 | "title": "PostgreSQL", 92 | "type": "dashboards" 93 | }, 94 | { 95 | "asDropdown": true, 96 | "includeVars": true, 97 | "keepTime": true, 98 | "tags": [ 99 | "HA" 100 | ], 101 | "targetBlank": false, 102 | "title": "HA", 103 | "type": "dashboards" 104 | }, 105 | { 106 | "asDropdown": true, 107 | "includeVars": true, 108 | "keepTime": true, 109 | "tags": [ 110 | "Cloud" 111 | ], 112 | "targetBlank": false, 113 | "title": "Cloud", 114 | "type": "dashboards" 115 | }, 116 | { 117 | "asDropdown": true, 118 | "includeVars": true, 119 | "keepTime": true, 120 | "tags": [ 121 | "Insight" 122 | ], 123 | "targetBlank": false, 124 | "title": "Insight", 125 | "type": "dashboards" 126 | }, 127 | { 128 | "asDropdown": true, 129 | "includeVars": true, 130 | "keepTime": true, 131 | "tags": [ 132 | "PMM" 133 | ], 134 | "targetBlank": false, 135 | "title": "PMM", 136 | "type": "dashboards" 137 | } 138 | ], 139 | "panels": [ 140 | { 141 | "collapsed": true, 142 | "datasource": null, 143 | "gridPos": { 144 | "h": 1, 145 | "w": 24, 146 | "x": 0, 147 | "y": 0 148 | }, 149 | "id": 51, 150 | "panels": [ 151 | { 152 | "aliasColors": { 153 | "Max Checkpoint Age": "#BF1B00", 154 | "Uncheckpointed Bytes": "#E0752D" 155 | }, 156 | "bars": false, 157 | "dashLength": 10, 158 | "dashes": false, 159 | "datasource": "Prometheus", 160 | "decimals": 2, 161 | "description": "**InnoDB Checkpoint Age**\n\nThe maximum checkpoint age is determined by the total length of all transaction log files (`innodb_log_file_size`).\n\nWhen the checkpoint age reaches the maximum checkpoint age, blocks are flushed syncronously. The rules of the thumb is to keep one hour of traffic in those logs and let the checkpointing perform its work as smooth as possible. If you don't do this, InnoDB will do synchronous flushing at the worst possible time, ie when you are busiest.", 162 | "editable": true, 163 | "error": false, 164 | "fill": 2, 165 | "fillGradient": 0, 166 | "grid": {}, 167 | "gridPos": { 168 | "h": 7, 169 | "w": 12, 170 | "x": 0, 171 | "y": 1 172 | }, 173 | "hiddenSeries": false, 174 | "id": 19, 175 | "legend": { 176 | "alignAsTable": true, 177 | "avg": true, 178 | "current": false, 179 | "max": true, 180 | "min": true, 181 | "rightSide": false, 182 | "show": true, 183 | "sort": "avg", 184 | "sortDesc": true, 185 | "total": false, 186 | "values": true 187 | }, 188 | "lines": true, 189 | "linewidth": 2, 190 | "links": [], 191 | "nullPointMode": "null", 192 | "options": { 193 | "dataLinks": [] 194 | }, 195 | "percentage": false, 196 | "pointradius": 5, 197 | "points": false, 198 | "renderer": "flot", 199 | "seriesOverrides": [ 200 | { 201 | "alias": "Max Checkpoint Age", 202 | "color": "#BF1B00", 203 | "fill": 0 204 | } 205 | ], 206 | "spaceLength": 10, 207 | "stack": false, 208 | "steppedLine": false, 209 | "targets": [ 210 | { 211 | "calculatedInterval": "2m", 212 | "datasourceErrors": {}, 213 | "errors": {}, 214 | "expr": "max_over_time(mysql_global_status_innodb_checkpoint_age{instance=~\"$host\"}[$interval]) or \nmax_over_time(mysql_global_status_innodb_checkpoint_age{instance=~\"$host\"}[5m]) or\nmax_over_time(mysql_info_schema_innodb_metrics_recovery_log_lsn_checkpoint_age_total{instance=~\"$host\"}[$interval]) or\nmax_over_time(mysql_info_schema_innodb_metrics_recovery_log_lsn_checkpoint_age_total{instance=~\"$host\"}[5m]) or\nmax_over_time(mysql_info_schema_innodb_metrics_log_log_lsn_checkpoint_age{instance=~\"$host\"}[$interval]) or\nmax_over_time(mysql_info_schema_innodb_metrics_log_log_lsn_checkpoint_age{instance=~\"$host\"}[5m])", 215 | "format": "time_series", 216 | "interval": "$interval", 217 | "intervalFactor": 1, 218 | "legendFormat": "Uncheckpointed Bytes", 219 | "metric": "", 220 | "refId": "A", 221 | "step": 300 222 | }, 223 | { 224 | "calculatedInterval": "2m", 225 | "datasourceErrors": {}, 226 | "errors": {}, 227 | "expr": "max_over_time(mysql_global_status_innodb_checkpoint_max_age{instance=~\"$host\"}[$interval]) or\nmax_over_time(mysql_global_status_innodb_checkpoint_max_age{instance=~\"$host\"}[5m]) or\nmax_over_time(mysql_info_schema_innodb_metrics_recovery_log_max_modified_age_async{instance=~\"$host\"}[$interval]) or\nmax_over_time(mysql_info_schema_innodb_metrics_recovery_log_max_modified_age_async{instance=~\"$host\"}[5m]) or\nmax_over_time(mysql_info_schema_innodb_metrics_log_log_max_modified_age_async{instance=~\"$host\"}[$interval]) or\nmax_over_time(mysql_info_schema_innodb_metrics_log_log_max_modified_age_async{instance=~\"$host\"}[5m])", 228 | "format": "time_series", 229 | "interval": "$interval", 230 | "intervalFactor": 1, 231 | "legendFormat": "Max Checkpoint Age", 232 | "metric": "", 233 | "refId": "B", 234 | "step": 300 235 | } 236 | ], 237 | "thresholds": [], 238 | "timeFrom": null, 239 | "timeRegions": [], 240 | "timeShift": null, 241 | "title": "InnoDB Checkpoint Age", 242 | "tooltip": { 243 | "msResolution": false, 244 | "shared": true, 245 | "sort": 0, 246 | "value_type": "individual" 247 | }, 248 | "type": "graph", 249 | "xaxis": { 250 | "buckets": null, 251 | "mode": "time", 252 | "name": null, 253 | "show": true, 254 | "values": [] 255 | }, 256 | "yaxes": [ 257 | { 258 | "decimals": 2, 259 | "format": "bytes", 260 | "logBase": 1, 261 | "max": null, 262 | "min": 0, 263 | "show": true 264 | }, 265 | { 266 | "decimals": null, 267 | "format": "bytes", 268 | "logBase": 1, 269 | "max": null, 270 | "min": 0, 271 | "show": false 272 | } 273 | ], 274 | "yaxis": { 275 | "align": false, 276 | "alignLevel": null 277 | } 278 | }, 279 | { 280 | "aliasColors": {}, 281 | "bars": false, 282 | "dashLength": 10, 283 | "dashes": false, 284 | "datasource": "Prometheus", 285 | "decimals": 2, 286 | "description": "**Innodb Transactions** \n\nInnoDB is an MVCC storage engine, which means you can start a transaction and continue to see a consistent snapshot \neven as the data changes. This is implemented by keeping old versions of rows as they are modified.\n\nThe InnoDB History List is the undo logs which are used to store these modifications. They are a fundamental part of InnoDB’s transactional architecture.\n\nIf history length is rising regularly, do not let open connections linger for a long period as this can affect the performance of InnoDB considerably. It is also a good idea to look for long running queries in PMM's Query Analytics.", 287 | "editable": true, 288 | "error": false, 289 | "fill": 2, 290 | "fillGradient": 0, 291 | "grid": {}, 292 | "gridPos": { 293 | "h": 7, 294 | "w": 12, 295 | "x": 12, 296 | "y": 1 297 | }, 298 | "hiddenSeries": false, 299 | "id": 20, 300 | "legend": { 301 | "alignAsTable": true, 302 | "avg": true, 303 | "current": false, 304 | "hideZero": true, 305 | "max": true, 306 | "min": true, 307 | "rightSide": false, 308 | "show": true, 309 | "sort": "avg", 310 | "sortDesc": true, 311 | "total": false, 312 | "values": true 313 | }, 314 | "lines": true, 315 | "linewidth": 2, 316 | "links": [ 317 | { 318 | "title": "Query Analytics", 319 | "url": "dashboard/db/_pmm-query-analytics" 320 | } 321 | ], 322 | "nullPointMode": "null", 323 | "options": { 324 | "dataLinks": [] 325 | }, 326 | "percentage": false, 327 | "pointradius": 5, 328 | "points": false, 329 | "renderer": "flot", 330 | "seriesOverrides": [ 331 | { 332 | "alias": "InnoDB Transactions", 333 | "yaxis": 2 334 | } 335 | ], 336 | "spaceLength": 10, 337 | "stack": false, 338 | "steppedLine": false, 339 | "targets": [ 340 | { 341 | "calculatedInterval": "2m", 342 | "datasourceErrors": {}, 343 | "errors": {}, 344 | "expr": "rate(mysql_global_status_innodb_max_trx_id{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_max_trx_id{instance=~\"$host\"}[5m])", 345 | "format": "time_series", 346 | "hide": false, 347 | "interval": "$interval", 348 | "intervalFactor": 1, 349 | "legendFormat": "InnoDB Transactions", 350 | "metric": "", 351 | "refId": "A", 352 | "step": 300 353 | }, 354 | { 355 | "calculatedInterval": "2m", 356 | "datasourceErrors": {}, 357 | "errors": {}, 358 | "expr": "(max_over_time(mysql_global_status_innodb_history_list_length{instance=~\"$host\"}[$interval]) or \nmax_over_time(mysql_global_status_innodb_history_list_length{instance=~\"$host\"}[5m])) or \n(max_over_time(mysql_info_schema_innodb_metrics_transaction_trx_rseg_history_len{instance=~\"$host\"}[$interval]) or \nmax_over_time(mysql_info_schema_innodb_metrics_transaction_trx_rseg_history_len{instance=~\"$host\"}[5m]))", 359 | "format": "time_series", 360 | "interval": "$interval", 361 | "intervalFactor": 1, 362 | "legendFormat": "History Length", 363 | "metric": "", 364 | "refId": "B", 365 | "step": 300 366 | } 367 | ], 368 | "thresholds": [], 369 | "timeFrom": null, 370 | "timeRegions": [], 371 | "timeShift": null, 372 | "title": "InnoDB Transactions", 373 | "tooltip": { 374 | "msResolution": false, 375 | "shared": true, 376 | "sort": 0, 377 | "value_type": "individual" 378 | }, 379 | "type": "graph", 380 | "xaxis": { 381 | "buckets": null, 382 | "mode": "time", 383 | "name": null, 384 | "show": true, 385 | "values": [] 386 | }, 387 | "yaxes": [ 388 | { 389 | "format": "short", 390 | "logBase": 1, 391 | "max": null, 392 | "min": 0, 393 | "show": true 394 | }, 395 | { 396 | "format": "short", 397 | "logBase": 1, 398 | "max": null, 399 | "min": 0, 400 | "show": true 401 | } 402 | ], 403 | "yaxis": { 404 | "align": false, 405 | "alignLevel": null 406 | } 407 | } 408 | ], 409 | "repeat": null, 410 | "title": "Checkpoint", 411 | "type": "row" 412 | }, 413 | { 414 | "collapsed": false, 415 | "datasource": null, 416 | "gridPos": { 417 | "h": 1, 418 | "w": 24, 419 | "x": 0, 420 | "y": 1 421 | }, 422 | "id": 52, 423 | "panels": [], 424 | "repeat": null, 425 | "title": "Row Operations", 426 | "type": "row" 427 | }, 428 | { 429 | "aliasColors": {}, 430 | "bars": false, 431 | "dashLength": 10, 432 | "dashes": false, 433 | "datasource": "Prometheus", 434 | "decimals": 2, 435 | "description": "**InnoDB Row Operations**\n\nThis graph allows you to see which operations occur and the number of rows affected per operation. A graph like Queries Per Second will give you an idea of queries, but one query could effect millions of rows.", 436 | "editable": true, 437 | "error": false, 438 | "fill": 2, 439 | "fillGradient": 0, 440 | "grid": {}, 441 | "gridPos": { 442 | "h": 7, 443 | "w": 12, 444 | "x": 0, 445 | "y": 2 446 | }, 447 | "hiddenSeries": false, 448 | "id": 23, 449 | "legend": { 450 | "alignAsTable": true, 451 | "avg": true, 452 | "current": false, 453 | "max": true, 454 | "min": true, 455 | "rightSide": false, 456 | "show": true, 457 | "sort": "avg", 458 | "sortDesc": true, 459 | "total": false, 460 | "values": true 461 | }, 462 | "lines": true, 463 | "linewidth": 2, 464 | "links": [], 465 | "nullPointMode": "null", 466 | "options": { 467 | "dataLinks": [] 468 | }, 469 | "percentage": false, 470 | "pointradius": 5, 471 | "points": false, 472 | "renderer": "flot", 473 | "seriesOverrides": [], 474 | "spaceLength": 10, 475 | "stack": false, 476 | "steppedLine": false, 477 | "targets": [ 478 | { 479 | "calculatedInterval": "2m", 480 | "datasourceErrors": {}, 481 | "errors": {}, 482 | "expr": "rate(mysql_global_status_innodb_row_ops_total{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_row_ops_total{instance=~\"$host\"}[5m])", 483 | "format": "time_series", 484 | "interval": "$interval", 485 | "intervalFactor": 1, 486 | "legendFormat": "Rows {{ operation }}", 487 | "metric": "", 488 | "refId": "A", 489 | "step": 300 490 | } 491 | ], 492 | "thresholds": [], 493 | "timeFrom": null, 494 | "timeRegions": [], 495 | "timeShift": null, 496 | "title": "InnoDB Row Operations", 497 | "tooltip": { 498 | "msResolution": false, 499 | "shared": true, 500 | "sort": 0, 501 | "value_type": "individual" 502 | }, 503 | "type": "graph", 504 | "xaxis": { 505 | "buckets": null, 506 | "mode": "time", 507 | "name": null, 508 | "show": true, 509 | "values": [] 510 | }, 511 | "yaxes": [ 512 | { 513 | "format": "short", 514 | "logBase": 1, 515 | "max": null, 516 | "min": 0, 517 | "show": true 518 | }, 519 | { 520 | "format": "short", 521 | "logBase": 1, 522 | "max": null, 523 | "min": 0, 524 | "show": true 525 | } 526 | ], 527 | "yaxis": { 528 | "align": false, 529 | "alignLevel": null 530 | } 531 | }, 532 | { 533 | "aliasColors": { 534 | "Avg Row Lock Wait Time": "#BF1B00" 535 | }, 536 | "bars": false, 537 | "dashLength": 10, 538 | "dashes": false, 539 | "datasource": "Prometheus", 540 | "decimals": 2, 541 | "description": "**InnoDB Row Lock Time**\n\nWhen data is locked, then that means that another ***session can NOT update that data until the lock*** is released (which unlocks the data and allows other users to update that data). Locks are usually released by either a ROLLBACK or COMMIT SQL statement.\n\nInnoDB implements standard row-level locking where there are two types of locks, [shared (S) locks](https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_shared_lock) and [exclusive (X) locks](https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_exclusive_lock).\n\n* A [shared (S) lock](https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_shared_lock) permits the transaction that holds the lock to read a row.\n* An [exclusive (X) lock](https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_exclusive_lock) permits the transaction that holds the lock to update or delete a row.\n\n_Average Row Lock Wait Time_ is the row lock wait time divided by the number of row locks.\\\n_Row Lock Waits_ are how many times a transaction waited on a row lock per second.\\\n_Row Lock Wait Load_ is a rolling 5 minute average of Row Lock Waits.", 542 | "editable": true, 543 | "error": false, 544 | "fill": 1, 545 | "fillGradient": 0, 546 | "grid": { 547 | "leftLogBase": 1, 548 | "leftMax": null, 549 | "leftMin": 0, 550 | "rightLogBase": 1, 551 | "rightMax": null, 552 | "rightMin": 0 553 | }, 554 | "gridPos": { 555 | "h": 7, 556 | "w": 12, 557 | "x": 12, 558 | "y": 2 559 | }, 560 | "hiddenSeries": false, 561 | "id": 46, 562 | "legend": { 563 | "alignAsTable": true, 564 | "avg": true, 565 | "current": false, 566 | "max": true, 567 | "min": true, 568 | "rightSide": false, 569 | "show": true, 570 | "sort": "avg", 571 | "sortDesc": true, 572 | "total": false, 573 | "values": true 574 | }, 575 | "lines": false, 576 | "linewidth": 2, 577 | "links": [ 578 | { 579 | "targetBlank": true, 580 | "title": "InnoDB Locking", 581 | "url": "https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html" 582 | } 583 | ], 584 | "nullPointMode": "null", 585 | "options": { 586 | "dataLinks": [] 587 | }, 588 | "percentage": false, 589 | "pointradius": 1, 590 | "points": true, 591 | "renderer": "flot", 592 | "seriesOverrides": [ 593 | { 594 | "alias": "Avg Row Lock Wait Time", 595 | "yaxis": 2 596 | } 597 | ], 598 | "spaceLength": 10, 599 | "stack": false, 600 | "steppedLine": true, 601 | "targets": [ 602 | { 603 | "calculatedInterval": "2m", 604 | "datasourceErrors": {}, 605 | "errors": {}, 606 | "expr": "rate(mysql_global_status_innodb_row_lock_waits{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_row_lock_waits{instance=~\"$host\"}[5m])", 607 | "format": "time_series", 608 | "interval": "$interval", 609 | "intervalFactor": 1, 610 | "legendFormat": "Row Lock Waits", 611 | "metric": "", 612 | "refId": "B", 613 | "step": 300 614 | }, 615 | { 616 | "expr": "rate(mysql_global_status_innodb_row_lock_time{instance=~\"$host\"}[$interval])/1000 or irate(mysql_global_status_innodb_row_lock_time{instance=~\"$host\"}[5m])/1000", 617 | "format": "time_series", 618 | "interval": "$interval", 619 | "intervalFactor": 1, 620 | "legendFormat": "Row Lock Wait Load", 621 | "metric": "", 622 | "refId": "A", 623 | "step": 300 624 | }, 625 | { 626 | "expr": "rate(mysql_global_status_innodb_row_lock_time{instance=~\"$host\"}[$interval])/rate(mysql_global_status_innodb_row_lock_waits{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_row_lock_time{instance=~\"$host\"}[5m])/irate(mysql_global_status_innodb_row_lock_waits{instance=~\"$host\"}[5m])", 627 | "format": "time_series", 628 | "interval": "$interval", 629 | "intervalFactor": 1, 630 | "legendFormat": "Avg Row Lock Wait Time", 631 | "refId": "C", 632 | "step": 300 633 | } 634 | ], 635 | "thresholds": [], 636 | "timeFrom": null, 637 | "timeRegions": [], 638 | "timeShift": null, 639 | "title": "InnoDB Row Lock Time", 640 | "tooltip": { 641 | "msResolution": false, 642 | "shared": true, 643 | "sort": 0, 644 | "value_type": "individual" 645 | }, 646 | "type": "graph", 647 | "x-axis": true, 648 | "xaxis": { 649 | "buckets": null, 650 | "mode": "time", 651 | "name": null, 652 | "show": true, 653 | "values": [] 654 | }, 655 | "y-axis": true, 656 | "y_formats": [ 657 | "short", 658 | "ms" 659 | ], 660 | "yaxes": [ 661 | { 662 | "format": "short", 663 | "label": null, 664 | "logBase": 1, 665 | "max": null, 666 | "min": 0, 667 | "show": true 668 | }, 669 | { 670 | "format": "ms", 671 | "label": null, 672 | "logBase": 1, 673 | "max": null, 674 | "min": 0, 675 | "show": true 676 | } 677 | ], 678 | "yaxis": { 679 | "align": false, 680 | "alignLevel": null 681 | } 682 | }, 683 | { 684 | "collapsed": false, 685 | "datasource": null, 686 | "gridPos": { 687 | "h": 1, 688 | "w": 24, 689 | "x": 0, 690 | "y": 9 691 | }, 692 | "id": 53, 693 | "panels": [], 694 | "repeat": null, 695 | "title": "I/O", 696 | "type": "row" 697 | }, 698 | { 699 | "aliasColors": {}, 700 | "bars": false, 701 | "dashLength": 10, 702 | "dashes": false, 703 | "datasource": "Prometheus", 704 | "decimals": 2, 705 | "description": "**InnoDB I/O**\n\n_Data Writes_ - The total number of InnoDB data writes.\\\n_Data Reads_ - The total number of InnoDB data reads (OS file reads).\\\n_Log Writes_ - The number of physical writes to the InnoDB redo log file.\\\n_Data Fsyncs_ - The number of fsync() operations. The frequency of fsync() calls is influenced by the setting of the `innodb_flush_method` configuration option.", 706 | "editable": true, 707 | "error": false, 708 | "fill": 2, 709 | "fillGradient": 0, 710 | "grid": {}, 711 | "gridPos": { 712 | "h": 7, 713 | "w": 12, 714 | "x": 0, 715 | "y": 10 716 | }, 717 | "hiddenSeries": false, 718 | "id": 38, 719 | "legend": { 720 | "alignAsTable": true, 721 | "avg": true, 722 | "current": false, 723 | "max": true, 724 | "min": true, 725 | "rightSide": false, 726 | "show": true, 727 | "sort": "avg", 728 | "sortDesc": true, 729 | "total": false, 730 | "values": true 731 | }, 732 | "lines": true, 733 | "linewidth": 2, 734 | "links": [], 735 | "nullPointMode": "null", 736 | "options": { 737 | "dataLinks": [] 738 | }, 739 | "percentage": false, 740 | "pointradius": 5, 741 | "points": false, 742 | "renderer": "flot", 743 | "seriesOverrides": [], 744 | "spaceLength": 10, 745 | "stack": false, 746 | "steppedLine": false, 747 | "targets": [ 748 | { 749 | "calculatedInterval": "2m", 750 | "datasourceErrors": {}, 751 | "errors": {}, 752 | "expr": "rate(mysql_global_status_innodb_data_reads{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_data_reads{instance=~\"$host\"}[5m])", 753 | "format": "time_series", 754 | "interval": "$interval", 755 | "intervalFactor": 1, 756 | "legendFormat": "Data Reads", 757 | "metric": "", 758 | "refId": "C", 759 | "step": 300 760 | }, 761 | { 762 | "calculatedInterval": "2m", 763 | "datasourceErrors": {}, 764 | "errors": {}, 765 | "expr": "rate(mysql_global_status_innodb_data_writes{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_data_writes{instance=~\"$host\"}[5m])", 766 | "format": "time_series", 767 | "interval": "$interval", 768 | "intervalFactor": 1, 769 | "legendFormat": "Data Writes", 770 | "metric": "", 771 | "refId": "D", 772 | "step": 300 773 | }, 774 | { 775 | "calculatedInterval": "2m", 776 | "datasourceErrors": {}, 777 | "errors": {}, 778 | "expr": "rate(mysql_global_status_innodb_data_fsyncs{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_data_fsyncs{instance=~\"$host\"}[5m])", 779 | "format": "time_series", 780 | "interval": "$interval", 781 | "intervalFactor": 1, 782 | "legendFormat": "Data Fsyncs", 783 | "metric": "", 784 | "refId": "A", 785 | "step": 300 786 | }, 787 | { 788 | "calculatedInterval": "2m", 789 | "datasourceErrors": {}, 790 | "errors": {}, 791 | "expr": "rate(mysql_global_status_innodb_log_writes{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_log_writes{instance=~\"$host\"}[5m])", 792 | "format": "time_series", 793 | "interval": "$interval", 794 | "intervalFactor": 1, 795 | "legendFormat": "Log Writes", 796 | "metric": "", 797 | "refId": "B", 798 | "step": 300 799 | } 800 | ], 801 | "thresholds": [], 802 | "timeFrom": null, 803 | "timeRegions": [], 804 | "timeShift": null, 805 | "title": "InnoDB I/O", 806 | "tooltip": { 807 | "msResolution": false, 808 | "shared": true, 809 | "sort": 0, 810 | "value_type": "individual" 811 | }, 812 | "type": "graph", 813 | "xaxis": { 814 | "buckets": null, 815 | "mode": "time", 816 | "name": null, 817 | "show": true, 818 | "values": [] 819 | }, 820 | "yaxes": [ 821 | { 822 | "format": "short", 823 | "logBase": 1, 824 | "max": null, 825 | "min": 0, 826 | "show": true 827 | }, 828 | { 829 | "format": "short", 830 | "logBase": 1, 831 | "max": null, 832 | "min": 0, 833 | "show": true 834 | } 835 | ], 836 | "yaxis": { 837 | "align": false, 838 | "alignLevel": null 839 | } 840 | }, 841 | { 842 | "aliasColors": {}, 843 | "bars": true, 844 | "dashLength": 10, 845 | "dashes": false, 846 | "datasource": "Prometheus", 847 | "decimals": 2, 848 | "description": "**InnoDB Log File Usage Hourly**\n\nAlong with the buffer pool size, `innodb_log_file_size` is the most important setting when we are working with InnoDB. This graph shows how much data was written to InnoDB's redo logs over each hour. When the InnoDB log files are full, InnoDB needs to flush the modified pages from memory to disk.\n\nThe rules of the thumb is to keep one hour of traffic in those logs and let the checkpointing perform its work as smooth as possible. If you don't do this, InnoDB will do synchronous flushing at the worst possible time, ie when you are busiest.\n\nThis graph can help guide you in setting the correct `innodb_log_file_size`.", 849 | "editable": true, 850 | "error": false, 851 | "fill": 2, 852 | "fillGradient": 0, 853 | "grid": {}, 854 | "gridPos": { 855 | "h": 7, 856 | "w": 12, 857 | "x": 12, 858 | "y": 10 859 | }, 860 | "hiddenSeries": false, 861 | "id": 37, 862 | "legend": { 863 | "alignAsTable": true, 864 | "avg": true, 865 | "current": false, 866 | "max": true, 867 | "min": true, 868 | "rightSide": false, 869 | "show": true, 870 | "sort": "avg", 871 | "sortDesc": true, 872 | "total": false, 873 | "values": true 874 | }, 875 | "lines": false, 876 | "linewidth": 2, 877 | "links": [ 878 | { 879 | "targetBlank": true, 880 | "title": "How to calculate a good InnoDB log file size", 881 | "url": "https://www.percona.com/blog/2008/11/21/how-to-calculate-a-good-innodb-log-file-size/" 882 | }, 883 | { 884 | "targetBlank": true, 885 | "title": "System Variables (innodb_log_file_size)", 886 | "url": "http://www.percona.com/doc/percona-server/5.5/scalability/innodb_io_55.html#innodb_log_file_size" 887 | } 888 | ], 889 | "nullPointMode": "null", 890 | "options": { 891 | "dataLinks": [] 892 | }, 893 | "percentage": false, 894 | "pointradius": 5, 895 | "points": false, 896 | "renderer": "flot", 897 | "seriesOverrides": [ 898 | { 899 | "alias": "Total Size of InnoDB Log Files", 900 | "bars": false, 901 | "color": "#E24D42", 902 | "fill": 0, 903 | "lines": true 904 | }, 905 | { 906 | "alias": "Data Written", 907 | "color": "#E0752D" 908 | } 909 | ], 910 | "spaceLength": 10, 911 | "stack": false, 912 | "steppedLine": false, 913 | "targets": [ 914 | { 915 | "calculatedInterval": "2m", 916 | "datasourceErrors": {}, 917 | "errors": {}, 918 | "expr": "increase(mysql_global_status_innodb_os_log_written{instance=~\"$host\"}[1h])", 919 | "format": "time_series", 920 | "interval": "1h", 921 | "intervalFactor": 1, 922 | "legendFormat": "Data Written", 923 | "metric": "", 924 | "refId": "A", 925 | "step": 3600 926 | }, 927 | { 928 | "calculatedInterval": "2m", 929 | "datasourceErrors": {}, 930 | "errors": {}, 931 | "expr": "mysql_global_variables_innodb_log_files_in_group{instance=~\"$host\"} * mysql_global_variables_innodb_log_file_size{instance=~\"$host\"}", 932 | "format": "time_series", 933 | "interval": "$interval", 934 | "intervalFactor": 1, 935 | "legendFormat": "Total Size of InnoDB Log Files", 936 | "metric": "", 937 | "refId": "B", 938 | "step": 300 939 | } 940 | ], 941 | "thresholds": [], 942 | "timeFrom": "24h", 943 | "timeRegions": [], 944 | "timeShift": null, 945 | "title": "InnoDB Log File Usage Hourly", 946 | "tooltip": { 947 | "msResolution": false, 948 | "shared": true, 949 | "sort": 0, 950 | "value_type": "individual" 951 | }, 952 | "type": "graph", 953 | "xaxis": { 954 | "buckets": null, 955 | "mode": "time", 956 | "name": null, 957 | "show": true, 958 | "values": [] 959 | }, 960 | "yaxes": [ 961 | { 962 | "format": "bytes", 963 | "logBase": 2, 964 | "max": null, 965 | "min": 0, 966 | "show": true 967 | }, 968 | { 969 | "format": "short", 970 | "logBase": 1, 971 | "max": null, 972 | "min": 0, 973 | "show": false 974 | } 975 | ], 976 | "yaxis": { 977 | "align": false, 978 | "alignLevel": null 979 | } 980 | }, 981 | { 982 | "aliasColors": { 983 | "Data Written to Logs": "#E24D42", 984 | "Time to Use Redo Log Space ": "#447EBC" 985 | }, 986 | "bars": false, 987 | "dashLength": 10, 988 | "dashes": false, 989 | "datasource": "Prometheus", 990 | "decimals": 2, 991 | "editable": true, 992 | "error": false, 993 | "fill": 2, 994 | "fillGradient": 0, 995 | "grid": {}, 996 | "gridPos": { 997 | "h": 7, 998 | "w": 12, 999 | "x": 0, 1000 | "y": 17 1001 | }, 1002 | "hiddenSeries": false, 1003 | "id": 50, 1004 | "legend": { 1005 | "alignAsTable": true, 1006 | "avg": true, 1007 | "current": false, 1008 | "max": true, 1009 | "min": true, 1010 | "rightSide": false, 1011 | "show": true, 1012 | "sort": null, 1013 | "sortDesc": null, 1014 | "total": false, 1015 | "values": true 1016 | }, 1017 | "lines": false, 1018 | "linewidth": 2, 1019 | "links": [], 1020 | "nullPointMode": "null", 1021 | "options": { 1022 | "dataLinks": [] 1023 | }, 1024 | "percentage": false, 1025 | "pointradius": 1, 1026 | "points": true, 1027 | "renderer": "flot", 1028 | "seriesOverrides": [ 1029 | { 1030 | "alias": "Time to Use Redo Log Space ", 1031 | "yaxis": 2 1032 | }, 1033 | { 1034 | "alias": "Time to Use In-Memory Log Buffer", 1035 | "yaxis": 2 1036 | } 1037 | ], 1038 | "spaceLength": 10, 1039 | "stack": false, 1040 | "steppedLine": false, 1041 | "targets": [ 1042 | { 1043 | "calculatedInterval": "2m", 1044 | "datasourceErrors": {}, 1045 | "errors": {}, 1046 | "expr": "rate(mysql_global_status_innodb_os_log_written{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_os_log_written{instance=~\"$host\"}[5m])", 1047 | "format": "time_series", 1048 | "interval": "$interval", 1049 | "intervalFactor": 1, 1050 | "legendFormat": "Data Written to Logs", 1051 | "metric": "", 1052 | "refId": "A", 1053 | "step": 300 1054 | }, 1055 | { 1056 | "calculatedInterval": "2m", 1057 | "datasourceErrors": {}, 1058 | "errors": {}, 1059 | "expr": "(mysql_global_variables_innodb_log_files_in_group{instance=~\"$host\"} * mysql_global_variables_innodb_log_file_size{instance=~\"$host\"})/(rate(mysql_global_status_innodb_os_log_written{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_os_log_written{instance=~\"$host\"}[5m]))", 1060 | "format": "time_series", 1061 | "interval": "$interval", 1062 | "intervalFactor": 1, 1063 | "legendFormat": "Time to Use Redo Log Space ", 1064 | "metric": "", 1065 | "refId": "B", 1066 | "step": 300 1067 | }, 1068 | { 1069 | "expr": "(mysql_global_variables_innodb_log_buffer_size{instance=~\"$host\"})/(rate(mysql_global_status_innodb_os_log_written{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_os_log_written{instance=~\"$host\"}[5m]))", 1070 | "format": "time_series", 1071 | "interval": "$interval", 1072 | "intervalFactor": 1, 1073 | "legendFormat": "Time to Use In-Memory Log Buffer", 1074 | "refId": "C", 1075 | "step": 300 1076 | } 1077 | ], 1078 | "thresholds": [], 1079 | "timeFrom": null, 1080 | "timeRegions": [], 1081 | "timeShift": null, 1082 | "title": "Innodb Logging Performance", 1083 | "tooltip": { 1084 | "msResolution": false, 1085 | "shared": true, 1086 | "sort": 0, 1087 | "value_type": "individual" 1088 | }, 1089 | "type": "graph", 1090 | "xaxis": { 1091 | "buckets": null, 1092 | "mode": "time", 1093 | "name": null, 1094 | "show": true, 1095 | "values": [] 1096 | }, 1097 | "yaxes": [ 1098 | { 1099 | "format": "Bps", 1100 | "logBase": 1, 1101 | "max": null, 1102 | "min": 0, 1103 | "show": true 1104 | }, 1105 | { 1106 | "format": "s", 1107 | "label": "", 1108 | "logBase": 2, 1109 | "max": null, 1110 | "min": 0, 1111 | "show": true 1112 | } 1113 | ], 1114 | "yaxis": { 1115 | "align": false, 1116 | "alignLevel": null 1117 | } 1118 | }, 1119 | { 1120 | "collapsed": true, 1121 | "datasource": null, 1122 | "gridPos": { 1123 | "h": 1, 1124 | "w": 24, 1125 | "x": 0, 1126 | "y": 24 1127 | }, 1128 | "id": 54, 1129 | "panels": [ 1130 | { 1131 | "aliasColors": {}, 1132 | "bars": false, 1133 | "dashLength": 10, 1134 | "dashes": false, 1135 | "datasource": "Prometheus", 1136 | "decimals": 2, 1137 | "description": "**InnoDB Deadlocks**\n\nA deadlock in MySQL happens when two or more transactions mutually hold and request for locks, creating a cycle of dependencies. In a transaction system, deadlocks are a fact of life and not completely avoidable. InnoDB automatically detects transaction deadlocks, rollbacks a transaction immediately and returns an error.", 1138 | "editable": true, 1139 | "error": false, 1140 | "fill": 2, 1141 | "fillGradient": 0, 1142 | "grid": {}, 1143 | "gridPos": { 1144 | "h": 7, 1145 | "w": 12, 1146 | "x": 0, 1147 | "y": 25 1148 | }, 1149 | "hiddenSeries": false, 1150 | "id": 47, 1151 | "legend": { 1152 | "alignAsTable": true, 1153 | "avg": true, 1154 | "current": false, 1155 | "max": true, 1156 | "min": true, 1157 | "rightSide": false, 1158 | "show": true, 1159 | "sort": null, 1160 | "sortDesc": null, 1161 | "total": false, 1162 | "values": true 1163 | }, 1164 | "lines": true, 1165 | "linewidth": 2, 1166 | "links": [ 1167 | { 1168 | "targetBlank": true, 1169 | "title": "How to deal with MySQL deadlocks", 1170 | "url": "https://www.percona.com/blog/2014/10/28/how-to-deal-with-mysql-deadlocks/" 1171 | } 1172 | ], 1173 | "nullPointMode": "null", 1174 | "options": { 1175 | "dataLinks": [] 1176 | }, 1177 | "percentage": false, 1178 | "pointradius": 5, 1179 | "points": false, 1180 | "renderer": "flot", 1181 | "seriesOverrides": [], 1182 | "spaceLength": 10, 1183 | "stack": false, 1184 | "steppedLine": false, 1185 | "targets": [ 1186 | { 1187 | "calculatedInterval": "2m", 1188 | "datasourceErrors": {}, 1189 | "errors": {}, 1190 | "expr": "(rate(mysql_global_status_innodb_deadlocks{instance=~\"$host\"}[$interval]) or rate(mysql_info_schema_innodb_metrics_lock_lock_deadlocks_total{instance=~\"$host\"}[$interval])) or (irate(mysql_global_status_innodb_deadlocks{instance=~\"$host\"}[5m]) or irate(mysql_info_schema_innodb_metrics_lock_lock_deadlocks_total{instance=~\"$host\"}[5m]))", 1191 | "format": "time_series", 1192 | "interval": "$interval", 1193 | "intervalFactor": 1, 1194 | "legendFormat": "Deadlocks", 1195 | "metric": "", 1196 | "refId": "B", 1197 | "step": 300 1198 | } 1199 | ], 1200 | "thresholds": [], 1201 | "timeFrom": null, 1202 | "timeRegions": [], 1203 | "timeShift": null, 1204 | "title": "InnoDB Deadlocks", 1205 | "tooltip": { 1206 | "msResolution": false, 1207 | "shared": true, 1208 | "sort": 0, 1209 | "value_type": "individual" 1210 | }, 1211 | "type": "graph", 1212 | "xaxis": { 1213 | "buckets": null, 1214 | "mode": "time", 1215 | "name": null, 1216 | "show": true, 1217 | "values": [] 1218 | }, 1219 | "yaxes": [ 1220 | { 1221 | "format": "short", 1222 | "logBase": 1, 1223 | "max": null, 1224 | "min": 0, 1225 | "show": true 1226 | }, 1227 | { 1228 | "format": "short", 1229 | "logBase": 1, 1230 | "max": null, 1231 | "min": 0, 1232 | "show": true 1233 | } 1234 | ], 1235 | "yaxis": { 1236 | "align": false, 1237 | "alignLevel": null 1238 | } 1239 | }, 1240 | { 1241 | "aliasColors": {}, 1242 | "bars": false, 1243 | "dashLength": 10, 1244 | "dashes": false, 1245 | "datasource": "Prometheus", 1246 | "description": "Index Condition Pushdown (ICP) is an optimization for the case where MySQL retrieves rows from a table using an index. Without ICP, the storage engine traverses the index to locate rows in the base table and returns them to the MySQL server which evaluates the WHERE condition for the rows. With ICP enabled, and if parts of the WHERE condition can be evaluated by using only columns from the index, the MySQL server pushes this part of the WHERE condition down to the storage engine. The storage engine then evaluates the pushed index condition by using the index entry and only if this is satisfied is the row read from the table. ICP can reduce the number of times the storage engine must access the base table and the number of times the MySQL server must access the storage engine.", 1247 | "fill": 1, 1248 | "fillGradient": 0, 1249 | "gridPos": { 1250 | "h": 7, 1251 | "w": 12, 1252 | "x": 12, 1253 | "y": 25 1254 | }, 1255 | "hiddenSeries": false, 1256 | "id": 48, 1257 | "legend": { 1258 | "alignAsTable": true, 1259 | "avg": true, 1260 | "current": true, 1261 | "hideEmpty": false, 1262 | "hideZero": true, 1263 | "max": true, 1264 | "min": true, 1265 | "rightSide": false, 1266 | "show": true, 1267 | "total": false, 1268 | "values": true 1269 | }, 1270 | "lines": true, 1271 | "linewidth": 1, 1272 | "links": [ 1273 | { 1274 | "targetBlank": true, 1275 | "title": "Index Condition Pushdown optimisation - MySQL 5.7 Manual", 1276 | "url": "https://dev.mysql.com/doc/refman/5.7/en/index-condition-pushdown-optimization.html" 1277 | }, 1278 | { 1279 | "targetBlank": true, 1280 | "title": "ICP counters and how to interpret them", 1281 | "url": "https://www.percona.com/blog/2017/05/09/mariadb-handler_icp_-counters-what-they-are-and-how-to-use-them/" 1282 | } 1283 | ], 1284 | "nullPointMode": "null", 1285 | "options": { 1286 | "dataLinks": [] 1287 | }, 1288 | "percentage": false, 1289 | "pointradius": 5, 1290 | "points": false, 1291 | "renderer": "flot", 1292 | "seriesOverrides": [], 1293 | "spaceLength": 10, 1294 | "stack": false, 1295 | "steppedLine": false, 1296 | "targets": [ 1297 | { 1298 | "expr": "rate(mysql_info_schema_innodb_metrics_icp_icp_attempts_total{instance=~\"$host\"}[$interval])", 1299 | "interval": "$interval", 1300 | "intervalFactor": 1, 1301 | "legendFormat": "Attempts", 1302 | "refId": "A", 1303 | "step": 300 1304 | }, 1305 | { 1306 | "expr": "rate(mysql_info_schema_innodb_metrics_icp_icp_match_total{instance=~\"$host\"}[$interval])", 1307 | "interval": "$interval", 1308 | "intervalFactor": 1, 1309 | "legendFormat": "Matches", 1310 | "refId": "B", 1311 | "step": 300 1312 | }, 1313 | { 1314 | "expr": "rate(mysql_info_schema_innodb_metrics_icp_icp_no_match_total{instance=~\"$host\"}[$interval])", 1315 | "interval": "$interval", 1316 | "intervalFactor": 1, 1317 | "legendFormat": "No Matches", 1318 | "refId": "C", 1319 | "step": 300 1320 | }, 1321 | { 1322 | "expr": "rate(mysql_info_schema_innodb_metrics_icp_icp_out_of_range_total{instance=~\"$host\"}[$interval])", 1323 | "interval": "$interval", 1324 | "intervalFactor": 1, 1325 | "legendFormat": "Out of Range", 1326 | "refId": "D", 1327 | "step": 300 1328 | } 1329 | ], 1330 | "thresholds": [], 1331 | "timeFrom": null, 1332 | "timeRegions": [], 1333 | "timeShift": null, 1334 | "title": "Index Condition Pushdown (ICP)", 1335 | "tooltip": { 1336 | "shared": true, 1337 | "sort": 0, 1338 | "value_type": "individual" 1339 | }, 1340 | "type": "graph", 1341 | "xaxis": { 1342 | "buckets": null, 1343 | "mode": "time", 1344 | "name": null, 1345 | "show": true, 1346 | "values": [] 1347 | }, 1348 | "yaxes": [ 1349 | { 1350 | "format": "short", 1351 | "label": "", 1352 | "logBase": 1, 1353 | "max": null, 1354 | "min": "0", 1355 | "show": true 1356 | }, 1357 | { 1358 | "format": "short", 1359 | "label": null, 1360 | "logBase": 1, 1361 | "max": null, 1362 | "min": null, 1363 | "show": false 1364 | } 1365 | ], 1366 | "yaxis": { 1367 | "align": false, 1368 | "alignLevel": null 1369 | } 1370 | } 1371 | ], 1372 | "repeat": null, 1373 | "title": "Deadlocks and ICP", 1374 | "type": "row" 1375 | }, 1376 | { 1377 | "collapsed": false, 1378 | "datasource": null, 1379 | "gridPos": { 1380 | "h": 1, 1381 | "w": 24, 1382 | "x": 0, 1383 | "y": 25 1384 | }, 1385 | "id": 55, 1386 | "panels": [], 1387 | "repeat": null, 1388 | "title": "Buffer Pool", 1389 | "type": "row" 1390 | }, 1391 | { 1392 | "aliasColors": {}, 1393 | "bars": false, 1394 | "dashLength": 10, 1395 | "dashes": false, 1396 | "datasource": "Prometheus", 1397 | "decimals": 2, 1398 | "editable": true, 1399 | "error": false, 1400 | "fill": 2, 1401 | "fillGradient": 0, 1402 | "grid": {}, 1403 | "gridPos": { 1404 | "h": 7, 1405 | "w": 12, 1406 | "x": 0, 1407 | "y": 26 1408 | }, 1409 | "hiddenSeries": false, 1410 | "id": 42, 1411 | "legend": { 1412 | "alignAsTable": true, 1413 | "avg": true, 1414 | "current": false, 1415 | "max": true, 1416 | "min": true, 1417 | "rightSide": false, 1418 | "show": true, 1419 | "sort": "avg", 1420 | "sortDesc": true, 1421 | "total": false, 1422 | "values": true 1423 | }, 1424 | "lines": true, 1425 | "linewidth": 2, 1426 | "links": [], 1427 | "nullPointMode": "null", 1428 | "options": { 1429 | "dataLinks": [] 1430 | }, 1431 | "percentage": false, 1432 | "pointradius": 5, 1433 | "points": false, 1434 | "renderer": "flot", 1435 | "seriesOverrides": [], 1436 | "spaceLength": 10, 1437 | "stack": false, 1438 | "steppedLine": false, 1439 | "targets": [ 1440 | { 1441 | "calculatedInterval": "2m", 1442 | "datasourceErrors": {}, 1443 | "errors": {}, 1444 | "expr": "mysql_global_status_innodb_buffer_pool_bytes_data{instance=~\"$host\"}", 1445 | "interval": "$interval", 1446 | "intervalFactor": 1, 1447 | "legendFormat": "Data Total", 1448 | "metric": "", 1449 | "refId": "B", 1450 | "step": 300 1451 | }, 1452 | { 1453 | "calculatedInterval": "2m", 1454 | "datasourceErrors": {}, 1455 | "errors": {}, 1456 | "expr": "mysql_global_status_innodb_buffer_pool_bytes_dirty{instance=~\"$host\"}", 1457 | "interval": "$interval", 1458 | "intervalFactor": 1, 1459 | "legendFormat": "Data Dirty", 1460 | "metric": "", 1461 | "refId": "A", 1462 | "step": 300 1463 | } 1464 | ], 1465 | "thresholds": [], 1466 | "timeFrom": null, 1467 | "timeRegions": [], 1468 | "timeShift": null, 1469 | "title": "InnoDB Buffer Pool Content", 1470 | "tooltip": { 1471 | "msResolution": false, 1472 | "shared": true, 1473 | "sort": 0, 1474 | "value_type": "individual" 1475 | }, 1476 | "type": "graph", 1477 | "xaxis": { 1478 | "buckets": null, 1479 | "mode": "time", 1480 | "name": null, 1481 | "show": true, 1482 | "values": [] 1483 | }, 1484 | "yaxes": [ 1485 | { 1486 | "format": "bytes", 1487 | "logBase": 1, 1488 | "max": null, 1489 | "min": 0, 1490 | "show": true 1491 | }, 1492 | { 1493 | "format": "short", 1494 | "logBase": 1, 1495 | "max": null, 1496 | "min": 0, 1497 | "show": true 1498 | } 1499 | ], 1500 | "yaxis": { 1501 | "align": false, 1502 | "alignLevel": null 1503 | } 1504 | }, 1505 | { 1506 | "aliasColors": {}, 1507 | "bars": false, 1508 | "dashLength": 10, 1509 | "dashes": false, 1510 | "datasource": "Prometheus", 1511 | "decimals": 2, 1512 | "editable": true, 1513 | "error": false, 1514 | "fill": 6, 1515 | "fillGradient": 0, 1516 | "grid": {}, 1517 | "gridPos": { 1518 | "h": 7, 1519 | "w": 12, 1520 | "x": 12, 1521 | "y": 26 1522 | }, 1523 | "hiddenSeries": false, 1524 | "id": 3, 1525 | "legend": { 1526 | "alignAsTable": true, 1527 | "avg": true, 1528 | "current": false, 1529 | "max": true, 1530 | "min": true, 1531 | "rightSide": false, 1532 | "show": true, 1533 | "sort": "avg", 1534 | "sortDesc": true, 1535 | "total": false, 1536 | "values": true 1537 | }, 1538 | "lines": true, 1539 | "linewidth": 2, 1540 | "links": [], 1541 | "nullPointMode": "null", 1542 | "options": { 1543 | "dataLinks": [] 1544 | }, 1545 | "percentage": false, 1546 | "pointradius": 5, 1547 | "points": false, 1548 | "renderer": "flot", 1549 | "seriesOverrides": [], 1550 | "spaceLength": 10, 1551 | "stack": true, 1552 | "steppedLine": false, 1553 | "targets": [ 1554 | { 1555 | "calculatedInterval": "2m", 1556 | "datasourceErrors": {}, 1557 | "errors": {}, 1558 | "expr": "mysql_global_status_buffer_pool_pages{instance=~\"$host\", state=~\"free|data|misc\"}", 1559 | "interval": "$interval", 1560 | "intervalFactor": 1, 1561 | "legendFormat": "{{ state }}", 1562 | "metric": "", 1563 | "refId": "B", 1564 | "step": 300 1565 | } 1566 | ], 1567 | "thresholds": [], 1568 | "timeFrom": null, 1569 | "timeRegions": [], 1570 | "timeShift": null, 1571 | "title": "InnoDB Buffer Pool Pages", 1572 | "tooltip": { 1573 | "msResolution": false, 1574 | "shared": true, 1575 | "sort": 0, 1576 | "value_type": "individual" 1577 | }, 1578 | "type": "graph", 1579 | "xaxis": { 1580 | "buckets": null, 1581 | "mode": "time", 1582 | "name": null, 1583 | "show": true, 1584 | "values": [] 1585 | }, 1586 | "yaxes": [ 1587 | { 1588 | "format": "short", 1589 | "logBase": 1, 1590 | "max": null, 1591 | "min": 0, 1592 | "show": true 1593 | }, 1594 | { 1595 | "format": "short", 1596 | "logBase": 1, 1597 | "max": null, 1598 | "min": 0, 1599 | "show": true 1600 | } 1601 | ], 1602 | "yaxis": { 1603 | "align": false, 1604 | "alignLevel": null 1605 | } 1606 | }, 1607 | { 1608 | "collapsed": false, 1609 | "datasource": null, 1610 | "gridPos": { 1611 | "h": 1, 1612 | "w": 24, 1613 | "x": 0, 1614 | "y": 33 1615 | }, 1616 | "id": 56, 1617 | "panels": [], 1618 | "repeat": null, 1619 | "title": "Buffer Pool I/O", 1620 | "type": "row" 1621 | }, 1622 | { 1623 | "aliasColors": {}, 1624 | "bars": false, 1625 | "dashLength": 10, 1626 | "dashes": false, 1627 | "datasource": "Prometheus", 1628 | "decimals": 2, 1629 | "editable": true, 1630 | "error": false, 1631 | "fill": 2, 1632 | "fillGradient": 0, 1633 | "grid": {}, 1634 | "gridPos": { 1635 | "h": 7, 1636 | "w": 12, 1637 | "x": 0, 1638 | "y": 34 1639 | }, 1640 | "hiddenSeries": false, 1641 | "id": 21, 1642 | "legend": { 1643 | "alignAsTable": true, 1644 | "avg": true, 1645 | "current": false, 1646 | "max": true, 1647 | "min": true, 1648 | "rightSide": false, 1649 | "show": true, 1650 | "sort": "avg", 1651 | "sortDesc": true, 1652 | "total": false, 1653 | "values": true 1654 | }, 1655 | "lines": true, 1656 | "linewidth": 2, 1657 | "links": [], 1658 | "nullPointMode": "null", 1659 | "options": { 1660 | "dataLinks": [] 1661 | }, 1662 | "percentage": false, 1663 | "pointradius": 5, 1664 | "points": false, 1665 | "renderer": "flot", 1666 | "seriesOverrides": [], 1667 | "spaceLength": 10, 1668 | "stack": false, 1669 | "steppedLine": false, 1670 | "targets": [ 1671 | { 1672 | "calculatedInterval": "2m", 1673 | "datasourceErrors": {}, 1674 | "errors": {}, 1675 | "expr": "rate(mysql_global_status_innodb_pages_created{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_pages_created{instance=~\"$host\"}[5m])", 1676 | "interval": "$interval", 1677 | "intervalFactor": 1, 1678 | "legendFormat": "Pages Created", 1679 | "metric": "", 1680 | "refId": "A", 1681 | "step": 300 1682 | }, 1683 | { 1684 | "calculatedInterval": "2m", 1685 | "datasourceErrors": {}, 1686 | "errors": {}, 1687 | "expr": "rate(mysql_global_status_innodb_pages_read{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_pages_read{instance=~\"$host\"}[5m])", 1688 | "interval": "$interval", 1689 | "intervalFactor": 1, 1690 | "legendFormat": "Pages Read", 1691 | "metric": "", 1692 | "refId": "B", 1693 | "step": 300 1694 | }, 1695 | { 1696 | "calculatedInterval": "2m", 1697 | "datasourceErrors": {}, 1698 | "errors": {}, 1699 | "expr": "rate(mysql_global_status_innodb_pages_written{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_pages_written{instance=~\"$host\"}[5m])", 1700 | "interval": "$interval", 1701 | "intervalFactor": 1, 1702 | "legendFormat": "Pages Written", 1703 | "metric": "", 1704 | "refId": "C", 1705 | "step": 300 1706 | } 1707 | ], 1708 | "thresholds": [], 1709 | "timeFrom": null, 1710 | "timeRegions": [], 1711 | "timeShift": null, 1712 | "title": "InnoDB Buffer Pool I/O", 1713 | "tooltip": { 1714 | "msResolution": false, 1715 | "shared": true, 1716 | "sort": 0, 1717 | "value_type": "individual" 1718 | }, 1719 | "type": "graph", 1720 | "xaxis": { 1721 | "buckets": null, 1722 | "mode": "time", 1723 | "name": null, 1724 | "show": true, 1725 | "values": [] 1726 | }, 1727 | "yaxes": [ 1728 | { 1729 | "format": "short", 1730 | "logBase": 1, 1731 | "max": null, 1732 | "min": 0, 1733 | "show": true 1734 | }, 1735 | { 1736 | "format": "short", 1737 | "logBase": 1, 1738 | "max": null, 1739 | "min": 0, 1740 | "show": true 1741 | } 1742 | ], 1743 | "yaxis": { 1744 | "align": false, 1745 | "alignLevel": null 1746 | } 1747 | }, 1748 | { 1749 | "aliasColors": {}, 1750 | "bars": false, 1751 | "dashLength": 10, 1752 | "dashes": false, 1753 | "datasource": "Prometheus", 1754 | "decimals": 2, 1755 | "editable": true, 1756 | "error": false, 1757 | "fill": 2, 1758 | "fillGradient": 0, 1759 | "grid": {}, 1760 | "gridPos": { 1761 | "h": 7, 1762 | "w": 12, 1763 | "x": 12, 1764 | "y": 34 1765 | }, 1766 | "hiddenSeries": false, 1767 | "id": 41, 1768 | "legend": { 1769 | "alignAsTable": true, 1770 | "avg": true, 1771 | "current": false, 1772 | "max": true, 1773 | "min": true, 1774 | "rightSide": false, 1775 | "show": true, 1776 | "sort": "avg", 1777 | "sortDesc": true, 1778 | "total": false, 1779 | "values": true 1780 | }, 1781 | "lines": true, 1782 | "linewidth": 2, 1783 | "links": [], 1784 | "nullPointMode": "null", 1785 | "options": { 1786 | "dataLinks": [] 1787 | }, 1788 | "percentage": false, 1789 | "pointradius": 5, 1790 | "points": false, 1791 | "renderer": "flot", 1792 | "seriesOverrides": [ 1793 | { 1794 | "alias": "Disk Reads", 1795 | "yaxis": 2 1796 | } 1797 | ], 1798 | "spaceLength": 10, 1799 | "stack": false, 1800 | "steppedLine": false, 1801 | "targets": [ 1802 | { 1803 | "calculatedInterval": "2m", 1804 | "datasourceErrors": {}, 1805 | "errors": {}, 1806 | "expr": "rate(mysql_global_status_innodb_buffer_pool_read_requests{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_read_requests{instance=~\"$host\"}[5m])", 1807 | "interval": "$interval", 1808 | "intervalFactor": 1, 1809 | "legendFormat": "Read Requests", 1810 | "metric": "", 1811 | "refId": "A", 1812 | "step": 300 1813 | }, 1814 | { 1815 | "calculatedInterval": "2m", 1816 | "datasourceErrors": {}, 1817 | "errors": {}, 1818 | "expr": "rate(mysql_global_status_innodb_buffer_pool_write_requests{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_write_requests{instance=~\"$host\"}[5m])", 1819 | "interval": "$interval", 1820 | "intervalFactor": 1, 1821 | "legendFormat": "Write Requests", 1822 | "metric": "", 1823 | "refId": "B", 1824 | "step": 300 1825 | }, 1826 | { 1827 | "calculatedInterval": "2m", 1828 | "datasourceErrors": {}, 1829 | "errors": {}, 1830 | "expr": "rate(mysql_global_status_innodb_buffer_pool_reads{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_reads{instance=~\"$host\"}[5m]) ", 1831 | "interval": "$interval", 1832 | "intervalFactor": 1, 1833 | "legendFormat": "Disk Reads", 1834 | "metric": "", 1835 | "refId": "C", 1836 | "step": 300 1837 | } 1838 | ], 1839 | "thresholds": [], 1840 | "timeFrom": null, 1841 | "timeRegions": [], 1842 | "timeShift": null, 1843 | "title": "InnoDB Buffer Pool Requests", 1844 | "tooltip": { 1845 | "msResolution": true, 1846 | "shared": true, 1847 | "sort": 0, 1848 | "value_type": "individual" 1849 | }, 1850 | "type": "graph", 1851 | "xaxis": { 1852 | "buckets": null, 1853 | "mode": "time", 1854 | "name": null, 1855 | "show": true, 1856 | "values": [] 1857 | }, 1858 | "yaxes": [ 1859 | { 1860 | "format": "short", 1861 | "logBase": 1, 1862 | "max": null, 1863 | "min": 0, 1864 | "show": true 1865 | }, 1866 | { 1867 | "format": "short", 1868 | "logBase": 1, 1869 | "max": null, 1870 | "min": 0, 1871 | "show": true 1872 | } 1873 | ], 1874 | "yaxis": { 1875 | "align": false, 1876 | "alignLevel": null 1877 | } 1878 | }, 1879 | { 1880 | "aliasColors": { 1881 | "Paged Fetched by Random Read Ahead": "#6ED0E0", 1882 | "Paged Fetched by Read Ahead but Never Accessed": "#EF843C", 1883 | "Percent of IO Caused by Read Ahead": "#0A437C", 1884 | "Read Ahead Waste Percent": "#BF1B00" 1885 | }, 1886 | "bars": false, 1887 | "dashLength": 10, 1888 | "dashes": false, 1889 | "datasource": "Prometheus", 1890 | "decimals": 2, 1891 | "editable": true, 1892 | "error": false, 1893 | "fill": 2, 1894 | "fillGradient": 0, 1895 | "grid": {}, 1896 | "gridPos": { 1897 | "h": 7, 1898 | "w": 12, 1899 | "x": 0, 1900 | "y": 41 1901 | }, 1902 | "hiddenSeries": false, 1903 | "id": 49, 1904 | "legend": { 1905 | "alignAsTable": true, 1906 | "avg": true, 1907 | "current": false, 1908 | "max": true, 1909 | "min": true, 1910 | "rightSide": false, 1911 | "show": true, 1912 | "sort": "avg", 1913 | "sortDesc": true, 1914 | "total": false, 1915 | "values": true 1916 | }, 1917 | "lines": true, 1918 | "linewidth": 2, 1919 | "links": [], 1920 | "nullPointMode": "null", 1921 | "options": { 1922 | "dataLinks": [] 1923 | }, 1924 | "percentage": false, 1925 | "pointradius": 5, 1926 | "points": false, 1927 | "renderer": "flot", 1928 | "seriesOverrides": [ 1929 | { 1930 | "alias": "Read Ahead Waste Percent", 1931 | "yaxis": 2 1932 | }, 1933 | { 1934 | "alias": "Percent of IO Caused by Read Ahead", 1935 | "yaxis": 2 1936 | } 1937 | ], 1938 | "spaceLength": 10, 1939 | "stack": false, 1940 | "steppedLine": false, 1941 | "targets": [ 1942 | { 1943 | "calculatedInterval": "2m", 1944 | "datasourceErrors": {}, 1945 | "errors": {}, 1946 | "expr": "rate(mysql_global_status_innodb_buffer_pool_read_ahead{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_read_ahead{instance=~\"$host\"}[5m])", 1947 | "format": "time_series", 1948 | "interval": "$interval", 1949 | "intervalFactor": 1, 1950 | "legendFormat": "Pages Fetched by Linear Read Ahead ", 1951 | "metric": "", 1952 | "refId": "A", 1953 | "step": 300 1954 | }, 1955 | { 1956 | "calculatedInterval": "2m", 1957 | "datasourceErrors": {}, 1958 | "errors": {}, 1959 | "expr": "rate(mysql_global_status_innodb_buffer_pool_read_ahead_rnd{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_read_ahead_rnd{instance=~\"$host\"}[5m])", 1960 | "format": "time_series", 1961 | "interval": "$interval", 1962 | "intervalFactor": 1, 1963 | "legendFormat": "Paged Fetched by Random Read Ahead", 1964 | "metric": "", 1965 | "refId": "B", 1966 | "step": 300 1967 | }, 1968 | { 1969 | "expr": "rate(mysql_global_status_innodb_buffer_pool_read_ahead_evicted{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_read_ahead_evicted{instance=~\"$host\"}[5m])", 1970 | "format": "time_series", 1971 | "interval": "$interval", 1972 | "intervalFactor": 1, 1973 | "legendFormat": "Paged Fetched by Read Ahead but Never Accessed", 1974 | "metric": "go_gc_duration_seconds_count", 1975 | "refId": "C", 1976 | "step": 300 1977 | }, 1978 | { 1979 | "expr": "(rate(mysql_global_status_innodb_buffer_pool_read_ahead_evicted{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_read_ahead_evicted{instance=~\"$host\"}[5m])) / ((rate(mysql_global_status_innodb_buffer_pool_read_ahead{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_read_ahead{instance=~\"$host\"}[5m])) + (rate(mysql_global_status_innodb_buffer_pool_read_ahead_rnd{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_read_ahead_rnd{instance=~\"$host\"}[5m])))", 1980 | "format": "time_series", 1981 | "interval": "$interval", 1982 | "intervalFactor": 1, 1983 | "legendFormat": "Read Ahead Waste Percent", 1984 | "refId": "D", 1985 | "step": 300 1986 | }, 1987 | { 1988 | "expr": "((rate(mysql_global_status_innodb_buffer_pool_read_ahead{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_read_ahead{instance=~\"$host\"}[5m]))+(rate(mysql_global_status_innodb_buffer_pool_read_ahead_rnd{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_buffer_pool_read_ahead_rnd{instance=~\"$host\"}[5m])))/(rate(mysql_global_status_innodb_pages_read{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_pages_read{instance=~\"$host\"}[5m])\n)", 1989 | "format": "time_series", 1990 | "interval": "$interval", 1991 | "intervalFactor": 1, 1992 | "legendFormat": "Percent of IO Caused by Read Ahead", 1993 | "refId": "E", 1994 | "step": 300 1995 | } 1996 | ], 1997 | "thresholds": [], 1998 | "timeFrom": null, 1999 | "timeRegions": [], 2000 | "timeShift": null, 2001 | "title": "Innodb Read-Ahead", 2002 | "tooltip": { 2003 | "msResolution": true, 2004 | "shared": true, 2005 | "sort": 0, 2006 | "value_type": "individual" 2007 | }, 2008 | "type": "graph", 2009 | "xaxis": { 2010 | "buckets": null, 2011 | "mode": "time", 2012 | "name": null, 2013 | "show": true, 2014 | "values": [] 2015 | }, 2016 | "yaxes": [ 2017 | { 2018 | "format": "short", 2019 | "logBase": 1, 2020 | "max": null, 2021 | "min": 0, 2022 | "show": true 2023 | }, 2024 | { 2025 | "format": "percentunit", 2026 | "logBase": 1, 2027 | "max": null, 2028 | "min": 0, 2029 | "show": true 2030 | } 2031 | ], 2032 | "yaxis": { 2033 | "align": false, 2034 | "alignLevel": null 2035 | } 2036 | }, 2037 | { 2038 | "collapsed": true, 2039 | "datasource": null, 2040 | "gridPos": { 2041 | "h": 1, 2042 | "w": 24, 2043 | "x": 0, 2044 | "y": 48 2045 | }, 2046 | "id": 57, 2047 | "panels": [ 2048 | { 2049 | "aliasColors": { 2050 | "Uncheckpointed Bytes": "#E0752D" 2051 | }, 2052 | "bars": false, 2053 | "dashLength": 10, 2054 | "dashes": false, 2055 | "datasource": "Prometheus", 2056 | "decimals": 2, 2057 | "editable": true, 2058 | "error": false, 2059 | "fill": 6, 2060 | "fillGradient": 0, 2061 | "grid": {}, 2062 | "gridPos": { 2063 | "h": 7, 2064 | "w": 12, 2065 | "x": 0, 2066 | "y": 49 2067 | }, 2068 | "hiddenSeries": false, 2069 | "id": 39, 2070 | "legend": { 2071 | "alignAsTable": true, 2072 | "avg": true, 2073 | "current": false, 2074 | "max": true, 2075 | "min": true, 2076 | "rightSide": false, 2077 | "show": true, 2078 | "sort": "avg", 2079 | "sortDesc": true, 2080 | "total": false, 2081 | "values": true 2082 | }, 2083 | "lines": true, 2084 | "linewidth": 2, 2085 | "links": [], 2086 | "nullPointMode": "null", 2087 | "options": { 2088 | "dataLinks": [] 2089 | }, 2090 | "percentage": false, 2091 | "pointradius": 5, 2092 | "points": false, 2093 | "renderer": "flot", 2094 | "seriesOverrides": [], 2095 | "spaceLength": 10, 2096 | "stack": false, 2097 | "steppedLine": false, 2098 | "targets": [ 2099 | { 2100 | "calculatedInterval": "2m", 2101 | "datasourceErrors": {}, 2102 | "errors": {}, 2103 | "expr": "mysql_global_status_innodb_ibuf_segment_size{instance=~\"$host\"} * mysql_global_status_innodb_page_size{instance=~\"$host\"}", 2104 | "interval": "$interval", 2105 | "intervalFactor": 1, 2106 | "legendFormat": "Allocated", 2107 | "metric": "", 2108 | "refId": "A", 2109 | "step": 300 2110 | }, 2111 | { 2112 | "calculatedInterval": "2m", 2113 | "datasourceErrors": {}, 2114 | "errors": {}, 2115 | "expr": "(mysql_global_status_innodb_ibuf_segment_size{instance=~\"$host\"} - mysql_global_status_innodb_ibuf_free_list{instance=~\"$host\"})*mysql_global_status_innodb_page_size{instance=~\"$host\"}", 2116 | "interval": "$interval", 2117 | "intervalFactor": 1, 2118 | "legendFormat": "Used", 2119 | "metric": "", 2120 | "refId": "B", 2121 | "step": 300 2122 | } 2123 | ], 2124 | "thresholds": [], 2125 | "timeFrom": null, 2126 | "timeRegions": [], 2127 | "timeShift": null, 2128 | "title": "InnoDB Change Buffer", 2129 | "tooltip": { 2130 | "msResolution": false, 2131 | "shared": true, 2132 | "sort": 0, 2133 | "value_type": "individual" 2134 | }, 2135 | "type": "graph", 2136 | "xaxis": { 2137 | "buckets": null, 2138 | "mode": "time", 2139 | "name": null, 2140 | "show": true, 2141 | "values": [] 2142 | }, 2143 | "yaxes": [ 2144 | { 2145 | "format": "bytes", 2146 | "logBase": 1, 2147 | "max": null, 2148 | "min": 0, 2149 | "show": true 2150 | }, 2151 | { 2152 | "format": "short", 2153 | "logBase": 1, 2154 | "max": null, 2155 | "min": 0, 2156 | "show": true 2157 | } 2158 | ], 2159 | "yaxis": { 2160 | "align": false, 2161 | "alignLevel": null 2162 | } 2163 | }, 2164 | { 2165 | "aliasColors": {}, 2166 | "bars": false, 2167 | "dashLength": 10, 2168 | "dashes": false, 2169 | "datasource": "Prometheus", 2170 | "decimals": 2, 2171 | "editable": true, 2172 | "error": false, 2173 | "fill": 2, 2174 | "fillGradient": 0, 2175 | "grid": {}, 2176 | "gridPos": { 2177 | "h": 7, 2178 | "w": 12, 2179 | "x": 12, 2180 | "y": 49 2181 | }, 2182 | "hiddenSeries": false, 2183 | "id": 40, 2184 | "legend": { 2185 | "alignAsTable": true, 2186 | "avg": true, 2187 | "current": false, 2188 | "hideEmpty": false, 2189 | "hideZero": false, 2190 | "max": true, 2191 | "min": true, 2192 | "rightSide": false, 2193 | "show": true, 2194 | "sort": "avg", 2195 | "sortDesc": true, 2196 | "total": false, 2197 | "values": true 2198 | }, 2199 | "lines": true, 2200 | "linewidth": 2, 2201 | "links": [], 2202 | "nullPointMode": "null", 2203 | "options": { 2204 | "dataLinks": [] 2205 | }, 2206 | "percentage": false, 2207 | "pointradius": 5, 2208 | "points": false, 2209 | "renderer": "flot", 2210 | "seriesOverrides": [], 2211 | "spaceLength": 10, 2212 | "stack": false, 2213 | "steppedLine": false, 2214 | "targets": [ 2215 | { 2216 | "calculatedInterval": "2m", 2217 | "datasourceErrors": {}, 2218 | "errors": {}, 2219 | "expr": "rate(mysql_global_status_innodb_ibuf_merges{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_ibuf_merges{instance=~\"$host\"}[5m]) or rate(mysql_info_schema_innodb_metrics_change_buffer_ibuf_merges_total{instance=~\"$host\"}[$interval]) or irate(mysql_info_schema_innodb_metrics_change_buffer_ibuf_merges_total{instance=~\"$host\"}[5m])", 2220 | "interval": "$interval", 2221 | "intervalFactor": 1, 2222 | "legendFormat": "Merges", 2223 | "metric": "", 2224 | "refId": "A", 2225 | "step": 300 2226 | }, 2227 | { 2228 | "calculatedInterval": "2m", 2229 | "datasourceErrors": {}, 2230 | "errors": {}, 2231 | "expr": "rate(mysql_global_status_innodb_ibuf_merged_inserts{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_ibuf_merged_inserts{instance=~\"$host\"}[5m]) or rate(mysql_info_schema_innodb_metrics_change_buffer_ibuf_merges_insert_total{instance=~\"$host\"}[$interval]) or irate(mysql_info_schema_innodb_metrics_change_buffer_ibuf_merges_insert_total{instance=~\"$host\"}[5m])", 2232 | "interval": "$interval", 2233 | "intervalFactor": 1, 2234 | "legendFormat": "Merged Inserts", 2235 | "metric": "", 2236 | "refId": "B", 2237 | "step": 300 2238 | }, 2239 | { 2240 | "calculatedInterval": "2m", 2241 | "datasourceErrors": {}, 2242 | "errors": {}, 2243 | "expr": "rate(mysql_global_status_innodb_ibuf_merged_deletes{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_ibuf_merged_deletes{instance=~\"$host\"}[5m]) or rate(mysql_info_schema_innodb_metrics_change_buffer_ibuf_merges_delete_total{instance=~\"$host\"}[$interval]) or irate(mysql_info_schema_innodb_metrics_change_buffer_ibuf_merges_delete_total{instance=~\"$host\"}[5m])", 2244 | "interval": "$interval", 2245 | "intervalFactor": 1, 2246 | "legendFormat": "Merged Deletes", 2247 | "metric": "", 2248 | "refId": "C", 2249 | "step": 300 2250 | }, 2251 | { 2252 | "calculatedInterval": "2m", 2253 | "datasourceErrors": {}, 2254 | "errors": {}, 2255 | "expr": "rate(mysql_global_status_innodb_ibuf_merged_delete_marks{instance=~\"$host\"}[$interval]) or irate(mysql_global_status_innodb_ibuf_merged_delete_marks{instance=~\"$host\"}[5m]) or rate(mysql_info_schema_innodb_metrics_change_buffer_ibuf_merges_delete_mark_total{instance=~\"$host\"}[$interval]) or irate(mysql_info_schema_innodb_metrics_change_buffer_ibuf_merges_delete_mark_total{instance=~\"$host\"}[5m])", 2256 | "interval": "$interval", 2257 | "intervalFactor": 1, 2258 | "legendFormat": "Merged Delete Marks", 2259 | "metric": "", 2260 | "refId": "D", 2261 | "step": 300 2262 | } 2263 | ], 2264 | "thresholds": [], 2265 | "timeFrom": null, 2266 | "timeRegions": [], 2267 | "timeShift": null, 2268 | "title": "InnoDB Change Buffer Activity", 2269 | "tooltip": { 2270 | "msResolution": false, 2271 | "shared": true, 2272 | "sort": 0, 2273 | "value_type": "individual" 2274 | }, 2275 | "type": "graph", 2276 | "xaxis": { 2277 | "buckets": null, 2278 | "mode": "time", 2279 | "name": null, 2280 | "show": true, 2281 | "values": [] 2282 | }, 2283 | "yaxes": [ 2284 | { 2285 | "format": "short", 2286 | "logBase": 1, 2287 | "max": null, 2288 | "min": 0, 2289 | "show": true 2290 | }, 2291 | { 2292 | "format": "short", 2293 | "logBase": 1, 2294 | "max": null, 2295 | "min": 0, 2296 | "show": true 2297 | } 2298 | ], 2299 | "yaxis": { 2300 | "align": false, 2301 | "alignLevel": null 2302 | } 2303 | } 2304 | ], 2305 | "repeat": null, 2306 | "title": "Change/Insert Buffer", 2307 | "type": "row" 2308 | } 2309 | ], 2310 | "refresh": "1m", 2311 | "schemaVersion": 22, 2312 | "style": "dark", 2313 | "tags": [ 2314 | "MySQL", 2315 | "Percona" 2316 | ], 2317 | "templating": { 2318 | "list": [ 2319 | { 2320 | "allFormat": "glob", 2321 | "auto": true, 2322 | "auto_count": 200, 2323 | "auto_min": "1s", 2324 | "current": { 2325 | "selected": false, 2326 | "text": "auto", 2327 | "value": "$__auto_interval_interval" 2328 | }, 2329 | "datasource": "Prometheus", 2330 | "hide": 0, 2331 | "includeAll": false, 2332 | "label": "Interval", 2333 | "multi": false, 2334 | "multiFormat": "glob", 2335 | "name": "interval", 2336 | "options": [ 2337 | { 2338 | "selected": true, 2339 | "text": "auto", 2340 | "value": "$__auto_interval_interval" 2341 | }, 2342 | { 2343 | "selected": false, 2344 | "text": "1s", 2345 | "value": "1s" 2346 | }, 2347 | { 2348 | "selected": false, 2349 | "text": "5s", 2350 | "value": "5s" 2351 | }, 2352 | { 2353 | "selected": false, 2354 | "text": "1m", 2355 | "value": "1m" 2356 | }, 2357 | { 2358 | "selected": false, 2359 | "text": "5m", 2360 | "value": "5m" 2361 | }, 2362 | { 2363 | "selected": false, 2364 | "text": "1h", 2365 | "value": "1h" 2366 | }, 2367 | { 2368 | "selected": false, 2369 | "text": "6h", 2370 | "value": "6h" 2371 | }, 2372 | { 2373 | "selected": false, 2374 | "text": "1d", 2375 | "value": "1d" 2376 | } 2377 | ], 2378 | "query": "1s,5s,1m,5m,1h,6h,1d", 2379 | "refresh": 2, 2380 | "skipUrlSync": false, 2381 | "type": "interval" 2382 | }, 2383 | { 2384 | "allFormat": "glob", 2385 | "allValue": null, 2386 | "current": { 2387 | "text": "playground-mysqld-exporter:9104", 2388 | "value": "playground-mysqld-exporter:9104" 2389 | }, 2390 | "datasource": "Prometheus", 2391 | "definition": "", 2392 | "hide": 0, 2393 | "includeAll": false, 2394 | "index": -1, 2395 | "label": "Host", 2396 | "multi": false, 2397 | "multiFormat": "regex values", 2398 | "name": "host", 2399 | "options": [], 2400 | "query": "label_values(mysql_up, instance)", 2401 | "refresh": 2, 2402 | "refresh_on_load": false, 2403 | "regex": "", 2404 | "skipUrlSync": false, 2405 | "sort": 1, 2406 | "tagValuesQuery": null, 2407 | "tags": [], 2408 | "tagsQuery": null, 2409 | "type": "query", 2410 | "useTags": false 2411 | } 2412 | ] 2413 | }, 2414 | "time": { 2415 | "from": "now-12h", 2416 | "to": "now" 2417 | }, 2418 | "timepicker": { 2419 | "collapse": false, 2420 | "enable": true, 2421 | "hidden": false, 2422 | "notice": false, 2423 | "now": true, 2424 | "refresh_intervals": [ 2425 | "5s", 2426 | "10s", 2427 | "30s", 2428 | "1m", 2429 | "5m", 2430 | "15m", 2431 | "30m", 2432 | "1h", 2433 | "2h", 2434 | "1d" 2435 | ], 2436 | "status": "Stable", 2437 | "time_options": [ 2438 | "5m", 2439 | "15m", 2440 | "1h", 2441 | "6h", 2442 | "12h", 2443 | "24h", 2444 | "2d", 2445 | "7d", 2446 | "30d" 2447 | ], 2448 | "type": "timepicker" 2449 | }, 2450 | "timezone": "browser", 2451 | "title": "MySQL InnoDB Metrics", 2452 | "uid": "giGgrTimz", 2453 | "variables": { 2454 | "list": [] 2455 | }, 2456 | "version": 1 2457 | } -------------------------------------------------------------------------------- /services/mysql/config/mysql/docker.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | skip-host-cache 3 | skip-name-resolve 4 | -------------------------------------------------------------------------------- /services/mysql/config/mysql/my.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | slow_query_log = ON 3 | slow_query_log_file = /var/lib/mysql/slow.log 4 | long_query_time = 2 5 | log_slow_extra = ON 6 | sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION 7 | -------------------------------------------------------------------------------- /services/mysql/dump/playground-db.sql: -------------------------------------------------------------------------------- 1 | -- MySQL dump 10.13 Distrib 8.0.16, for macos10.14 (x86_64) 2 | -- 3 | -- Host: 127.0.0.1 Database: playground-db 4 | -- ------------------------------------------------------ 5 | -- Server version 8.0.19 6 | 7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 10 | SET NAMES utf8 ; 11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 12 | /*!40103 SET TIME_ZONE='+00:00' */; 13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 17 | 18 | -- 19 | -- Table structure for table `test_table_big` 20 | -- 21 | 22 | DROP TABLE IF EXISTS `test_table_big`; 23 | /*!40101 SET @saved_cs_client = @@character_set_client */; 24 | SET character_set_client = utf8mb4 ; 25 | CREATE TABLE `test_table_big` ( 26 | `id` int NOT NULL AUTO_INCREMENT, 27 | `number` tinyint DEFAULT NULL, 28 | `string_short` varchar(5) DEFAULT NULL, 29 | `string_long` varchar(500) DEFAULT NULL, 30 | PRIMARY KEY (`id`) 31 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 32 | /*!40101 SET character_set_client = @saved_cs_client */; 33 | 34 | -- 35 | -- Table structure for table `test_table_small` 36 | -- 37 | 38 | DROP TABLE IF EXISTS `test_table_small`; 39 | /*!40101 SET @saved_cs_client = @@character_set_client */; 40 | SET character_set_client = utf8mb4 ; 41 | CREATE TABLE `test_table_small` ( 42 | `id` int NOT NULL AUTO_INCREMENT, 43 | `number` tinyint DEFAULT NULL, 44 | `string_short` varchar(5) DEFAULT NULL, 45 | `string_long` varchar(500) DEFAULT NULL, 46 | PRIMARY KEY (`id`) 47 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 48 | /*!40101 SET character_set_client = @saved_cs_client */; 49 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 50 | 51 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 52 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 53 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 54 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 55 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 56 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 57 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 58 | 59 | -- Dump completed on 2020-05-26 8:55:21 60 | -------------------------------------------------------------------------------- /services/prometheus/config/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 5s 3 | 4 | scrape_configs: 5 | - job_name: 'playground-db' 6 | static_configs: 7 | - targets: 8 | - playground-mysqld-exporter:9104 # mysqld_exporter 9 | - targets: 10 | - playground-node-exporter:9100 # node_exporter 11 | -------------------------------------------------------------------------------- /services/slow-log-cron/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM perconalab/percona-toolkit 2 | 3 | RUN apt update 4 | 5 | RUN apt install -y cron logrotate mysql-client nano 6 | 7 | COPY ./config/cron/crontab /etc/cron.d/crontab 8 | RUN crontab /etc/cron.d/crontab 9 | -------------------------------------------------------------------------------- /services/slow-log-cron/README.md: -------------------------------------------------------------------------------- 1 | ### Service `Slow log cron` 2 | 3 | #### Scheduled digest updates 4 | Every 5 minutes service `slow log cron` parses MySQL slow log file to get the data for anemometer. 5 | Time frame could be configured in crontab config file: `services/slow-log-cron/config/cron/crontab` 6 | 7 | #### Percona toolkit query digest 8 | You can configure database host and destination tables for slow log data as `pt-query-digest` 9 | command arguments in file: `services/slow-log-cron/commands/query-digest.sh` 10 | 11 | `pt-query-digest` tool has some specifics: 12 | - It processes slow log file and stores information to the database. 13 | - If the same (with no changes) file is processed again, nothing happens. 14 | - If new record was added to already processed slow log file, `pt-query-digest` would assume this file 15 | as new, so whole slow log file would be processed again (this should avoided). 16 | - To avoid duplicated records from slow log file `logrotate` utility is used. In current setup it will rotate 17 | slow log file every 5 minutes (old file is erased right after it was processed), so no duplicates would be saved to the database. 18 | Also, `logrotate` provides graceful copy-truncate procedure of slow log file regarding the database. 19 | -------------------------------------------------------------------------------- /services/slow-log-cron/commands/query-digest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | /usr/bin/pt-query-digest --user=root \ 4 | --review h=playground-db,D=slow_query_log,t=global_query_review \ 5 | --history h=playground-db,D=slow_query_log,t=global_query_review_history \ 6 | --no-report --limit=0% \ 7 | --filter=" \$event->{Bytes} = length(\$event->{arg}) and \$event->{hostname}=\"playground-db\"" \ 8 | /var/lib/mysql/slow.log 9 | 10 | /usr/sbin/logrotate /etc/logrotate.d/slow_log.conf 11 | -------------------------------------------------------------------------------- /services/slow-log-cron/config/cron/crontab: -------------------------------------------------------------------------------- 1 | 5 * * * * bash /commands/query-digest.sh 2 | -------------------------------------------------------------------------------- /services/slow-log-cron/config/logrotate/slow_log.conf: -------------------------------------------------------------------------------- 1 | /var/lib/mysql/slow.log { 2 | size 10 3 | missingok 4 | notifempty 5 | rotate 0 6 | delaycompress 7 | sharedscripts 8 | nocopytruncate 9 | create 660 10 | postrotate 11 | /usr/bin/mysql -h playground-db -u root -e 'select @@global.slow_query_log into @sq_log_save; set global slow_query_log=off; select sleep(2); FLUSH SLOW LOGS; select sleep(2); set global slow_query_log=@sq_log_save;' 12 | endscript 13 | } 14 | -------------------------------------------------------------------------------- /services/sysbench/commands/tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | mkdir -p /reports 4 | 5 | sysbench select \ 6 | --mysql-host=playground-db \ 7 | --mysql-port=3306 \ 8 | --mysql-user=root \ 9 | --mysql-password='' \ 10 | --mysql-db=playground-db \ 11 | --threads=1 \ 12 | --time=60 \ 13 | run > /reports/select_1_thread.txt 14 | 15 | sysbench select \ 16 | --mysql-host=playground-db \ 17 | --mysql-port=3306 \ 18 | --mysql-user=root \ 19 | --mysql-password='' \ 20 | --mysql-db=playground-db \ 21 | --threads=10 \ 22 | --time=60 \ 23 | run > /reports/select_10_threads.txt 24 | 25 | sysbench insert \ 26 | --mysql-host=playground-db \ 27 | --mysql-port=3306 \ 28 | --mysql-user=root \ 29 | --mysql-password='' \ 30 | --mysql-db=playground-db \ 31 | --threads=1 \ 32 | --time=60 \ 33 | run > /reports/insert_1_thread.txt 34 | 35 | sysbench insert \ 36 | --mysql-host=playground-db \ 37 | --mysql-port=3306 \ 38 | --mysql-user=root \ 39 | --mysql-password='' \ 40 | --mysql-db=playground-db \ 41 | --threads=10 \ 42 | --time=60 \ 43 | run > /reports/insert_10_threads.txt 44 | -------------------------------------------------------------------------------- /services/sysbench/reports/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | */ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /services/sysbench/tests/insert.lua: -------------------------------------------------------------------------------- 1 | if sysbench.cmdline.command == nil then 2 | error("Command is required. Supported commands: run") 3 | end 4 | 5 | sysbench.cmdline.options = { 6 | point_selects = {"Number of point SELECT queries to run", 5}, 7 | skip_trx = {"Do not use BEGIN/COMMIT; Use global auto_commit value", false} 8 | } 9 | 10 | function execute_insert() 11 | local number = sysbench.rand.uniform(1,100) 12 | local string_short = sysbench.rand.string(string.rep("@",sysbench.rand.uniform(5,5))) 13 | local string_long = sysbench.rand.string(string.rep("@",sysbench.rand.uniform(500,500))) 14 | 15 | local query = "INSERT INTO `playground-db`.`test_table_big` (`number`, `string_short`, `string_long`) VALUES ('" .. number .. "', '" .. string_short .. "', '" .. string_long .. "');" 16 | con:query(query) 17 | end 18 | 19 | -- Called by sysbench to initialize script 20 | function thread_init() 21 | 22 | -- globals for script 23 | drv = sysbench.sql.driver() 24 | con = drv:connect() 25 | end 26 | 27 | 28 | -- Called by sysbench when tests are done 29 | function thread_done() 30 | 31 | con:disconnect() 32 | end 33 | 34 | 35 | -- Called by sysbench for each execution 36 | function event() 37 | 38 | if not sysbench.opt.skip_trx then 39 | con:query("BEGIN") 40 | end 41 | 42 | execute_insert() 43 | 44 | if not sysbench.opt.skip_trx then 45 | con:query("COMMIT") 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /services/sysbench/tests/select.lua: -------------------------------------------------------------------------------- 1 | if sysbench.cmdline.command == nil then 2 | error("Command is required. Supported commands: run") 3 | end 4 | 5 | sysbench.cmdline.options = { 6 | point_selects = {"Number of point SELECT queries to run", 5}, 7 | skip_trx = {"Do not use BEGIN/COMMIT; Use global auto_commit value", false} 8 | } 9 | 10 | function execute_select() 11 | local number = sysbench.rand.uniform(1,100) 12 | local query = "SELECT * FROM test_table_big WHERE number = '" .. number .. "' ORDER BY number LIMIT 20000" 13 | con:query(query) 14 | end 15 | 16 | -- Called by sysbench to initialize script 17 | function thread_init() 18 | 19 | -- globals for script 20 | drv = sysbench.sql.driver() 21 | con = drv:connect() 22 | end 23 | 24 | 25 | -- Called by sysbench when tests are done 26 | function thread_done() 27 | 28 | con:disconnect() 29 | end 30 | 31 | 32 | -- Called by sysbench for each execution 33 | function event() 34 | 35 | if not sysbench.opt.skip_trx then 36 | con:query("BEGIN") 37 | end 38 | 39 | execute_select() 40 | 41 | if not sysbench.opt.skip_trx then 42 | con:query("COMMIT") 43 | end 44 | end 45 | --------------------------------------------------------------------------------