capturing, analyzing and optimizing mysql

102
ODTUG – June 2010 Capturing, Analyzing & Optimizing your SQL Padraig O'Sullivan - http://posulliv.com/ Ronald Bradford - http://ronaldbradford.com/

Upload: ronald-bradford

Post on 15-Jan-2015

4.427 views

Category:

Technology


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Capturing, Analyzing & Optimizing your SQL

Padraig O'Sullivan - http://posulliv.com/Ronald Bradford - http://ronaldbradford.com/

Page 2: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Capturing your SQL

Page 3: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

MySQL Provided Options

Slow Query Log

General Query Log

Binary Log

Connectors

Processlist

Engine status

Status variables

Page 4: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Other Techniques

MySQL Proxy

TCP/IP Capture

Dtrace/SystemTap

Application Management

Page 5: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Slow Query LogNot enabled by default

log-slow-queries = /path/to/file (5.0)

slow_query_log/slow_query_log_file (5.1)

Granularity of seconds

Microsecond patch by percona

Default slow time is 10 seconds

long_query_time = 2

Log output to file or table (5.1)

log_output = FILE | TABLE | BOTHhttp://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html

Page 6: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Slow Query Log Example# Time: 100518 19:34:31# User@Host: user[db] @ localhost []# Query_time: 4  Lock_time: 0  Rows_sent: 1155  Rows_examined: 1663671select distinct visitorid from log where timestamp like '20100518%' and accountid!=1 and accountid!=37 and file not like '%admin%';# Time: 100518 19:35:37# User@Host: user[db] @ localhost []# Query_time: 4  Lock_time: 0  Rows_sent: 6  Rows_examined: 1662525select distinct accountid from log where timestamp>='20100518132033' and accountid NOT IN ('0','1','37','1635');# Time: 100518 19:35:41# User@Host: user[db] @ localhost []# Query_time: 4  Lock_time: 0  Rows_sent: 2477  Rows_examined: 1664996select timestamp, file from log where timestamp>='20100518000000' and timestamp<='end' and accountid!=1 and accountid!=37 order by timestamp desc;# Time: 100518 19:35:44# User@Host: user[db] @ localhost []# Query_time: 3  Lock_time: 0  Rows_sent: 1157  Rows_examined: 1663676select distinct visitorid from log where timestamp like '20100518%' and accountid!=1 and accountid!=37 and file not like '%admin%';

Page 7: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Slow Query Table Example

mysql> select start_time, query_time, rows_sent, rows_examined, db, sql_text    ­> from mysql.slow_log;+­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+| start_time          | query_time | rows_sent | rows_examined | db     | sql_text                          |+­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+| 2010­06­14 13:43:37 | 00:03:45   |         1 |      31290045 | drupal | select count(*) from search_index | +­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+1 row in set (0.00 sec)

mysql>

Page 8: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

General Query Log

Not enabled by default

log = /path/to/file

general_log/general_log_file (5.1)

Log output to file or table (5.1)

log_output = FILE | TABLE | BOTH

Never use in production

Ideal for development, unit testing environments

http://dev.mysql.com/doc/refman/5.1/en/query-log.html

Page 9: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

General Query Log Example

26 Query SELECT * FROM wp_users WHERE user_login = 'xxxx'26 Query SELECT meta_key, meta_value FROM wp_usermeta WHERE user_id = 226 Query SELECT option_value FROM wp_options WHERE option_name = 'sidebars_widgets' LIMIT 126 Query SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 1026 Query SELECT FOUND_ROWS()26 Query SELECT t.*, tt.*, tr.object_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ('category', 'post_tag') ANDtr.object_id IN (2849, 2842, 2836, 2824, 2812, 2680, 2813, 2800, 2770, 2784) ORDER BY t.name ASC26 Query SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (2849,2842,2836,2824,2812,2680,2813,2800,2770,2784)

Output using Wordpress

Page 10: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

General Query Log Example (2)

Framework new connection

    23 Connect     user@host    23 Query       SELECT 1    23 Query       SET NAMES utf8    23 Query       SET character_set_results = NULL    23 Query       SHOW VARIABLES    23 Query       SHOW COLLATION    23 Query       SET autocommit=1    23 Query       SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED    23 Query       SET autocommit=0

Page 11: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

General Query Log Example (3)

Finding framework overhead

ROLLBACK after every SELECT

SELECT 1 – connection ping test    23 Query       select count(*) from collection where account_name = 'xxx'                    and user_id = '313'    23 Query       rollback    23 Query       select 1    23 Query       select count(*) from collection where account_name = 'xxx'                    and user_id = '346'    23 Query       rollback    23 Query       select 1    23 Query       select name,user_id,date_format(`register_time`,'%Y%m%d%H%i%S') as                    createTime   from account where name = 'xxx' and                    user_id = '346'  and `status` = '1'    23 Query       rollback    23 Query       select 1    23 Query       select max(mdate)  from received where account_name = 'xxx'                    And user_id = '346' order by mdate desc    23 Query       rollback

Page 12: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Binary Log

Not enabled by default

log-bin = /path/to/file

expire_log_days = 5

View with mysqlbinlog

http://dev.mysql.com/doc/refman/5.1/en/binary-log.html

Page 13: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Binary Log Example

# at 2461#100604 10:49:43 server id 1  end_log_pos 2632 Query thread_id=6 exec_time=0 error_code=0use blog/*!*/;SET TIMESTAMP=1275662983/*!*/;UPDATE `wp_postmeta` SET `meta_value` = '1275662983' WHERE `meta_key` = '_edit_lock' AND `post_id` = 2849/*!*/;

# at 21107#100604 10:58:49 server id 1  end_log_pos 21469 Query thread_id=62 exec_time=0 error_code=0use monitoringmysql/*!*/;SET TIMESTAMP=1275663529/*!*/;SET @@session.time_zone='SYSTEM'/*!*/;INSERT INTO wp_redirection_logs (url,sent_to,created,agent,redirection_id,ip,referrer,module_id,group_id) VALUES ('/mysql­monitoring/dbtuna',NULL,NOW(),'Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)',NULL, '67.195.114.227', NULL, 3, NULL)/*!*/;

mysqlbinlog /path/to/log-bin.000000

Page 14: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Connector/J

logSlowQueries

slowQueryThresholdMillis

SlowQueryThresholdNanos

http://dev.mysql.com/doc/refman/5.1/en/connector-j-reference-configuration-properties.html

Page 15: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Processlist

Current connection/thread

No filtering options

Ideal for locking

http://dev.mysql.com/doc/refman/5.1/en/show-processlist.html

mysql> SHOW [FULL] PROCESSLIST$ mysqladmin [­v] processlist

mysql> SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST (5.1))

Page 16: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Processlist Example

mysql [localhost] {root} ((none)) > show processlist;+­­­­­­­+­­­­­­+­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+| Id    | User | Host      | db   | Command | Time | State             | Info                                                                                                 |+­­­­­­­+­­­­­­+­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+|     7 | root | localhost | NULL | Query   |    0 | NULL              | show processlist                                                                                     || 20017 | root | localhost | oltp | Query   |    0 | creating table    | create table bench1 (a int NOT NULL,i int,s char(10),primary key (a))                                || 20020 | root | localhost | oltp | Query   |    1 | copy to tmp table | ALTER TABLE bench ADD  i919 integer,ADD  i920 integer,ADD  i921 integer,ADD  i922 integer,ADD  i923  |+­­­­­­­+­­­­­­+­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+3 rows in set (0.00 sec)

Page 17: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Processlist Example (2)

| Id   | User    | Host     | db  | Command | Time | State              | Info

| 2692 | app_usr | db:44376 | db1 | Query   |    3 | Sending data       | SELECT ...| 2805 | app_usr | db:44703 | db1 | Query   |    0 | statistics         | SELECT ... FOR UPDATE| 2829 | app_usr | db:44812 | db1 | Query   |    0 | init               | UPDATE ...| 2845 | app_usr | db:44866 | db1 | Sleep   |    2 |                    | NULL                  | 2846 | app_usr | db:44866 | db1 | Sleep   |    2 |                    | NULL  | 2915 | app_usr | db:56751 | db1 | Query   |    0 | Updating           | UPDATE ...| 2847 | app_usr | db:44868 | db1 | Query   |    0 | query end          | SELECT * FROM ...| 2928 | app_usr | db:56792 | db1 | Query   |    0 | logging slow query | INSERT INTO ...

Page 18: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Engine Status

Provides engine specific information

Vendor implemented

InnoDB

Running threads

Last deadlock

Last foreign key error

Other engine types include

NDB, PBXT, TOKUDB

Page 19: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Engine Status

mysql> SHOW ENGINE INNODB STATUS;

http://dev.mysql.com/doc/refman/5.1/en/show-engine.html

Page 20: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Engine Status Example­­­­­­­­­­­­TRANSACTIONS­­­­­­­­­­­­Trx id counter 0 480206585Purge done for trx's n:o < 0 480205682 undo n:o < 0 0History list length 5LIST OF TRANSACTIONS FOR EACH SESSION:­­­TRANSACTION 0 0, not started, process no 27230, OS thread id 1182685536MySQL thread id 427, query id 123563  10.8.160.241 dbaSHOW ENGINE INNODB STATUS­­­TRANSACTION 0 0, not started, process no 27230, OS thread id 1169639776MySQL thread id 44, query id 123445  10.8.160.241 dba­­­TRANSACTION 0 480206305, ACTIVE 67 sec, process no 27230, OS thread id 1192270176mysql tables in use 1, locked 11 lock struct(s), heap size 368, 0 row lock(s), undo log entries 1MySQL thread id 370, query id 123171  10.120.229.37 user query endINSERT INTO `table` ....­­­TRANSACTION 0 480206290, ACTIVE 70 sec, process no 27230, OS thread id 1178159456mysql tables in use 1, locked 11 lock struct(s), heap size 368, 0 row lock(s), undo log entries 1MySQL thread id 372, query id 123150  10.120.229.37 user query endINSERT INTO `table` ....­­­TRANSACTION 0 480206289, ACTIVE 70 sec, process no 27230, OS thread id 1178425696mysql tables in use 1, locked 11 lock struct(s), heap size 368, 0 row lock(s), undo log entries 1MySQL thread id 373, query id 123149  10.120.229.37 user query endINSERT INTO `table` ........

Page 21: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Engine Status Example (2)------------------------LATEST DETECTED DEADLOCK------------------------090624 14:32:18*** (1) TRANSACTION:TRANSACTION 0 39639074, ACTIVE 0 sec, process no 27807, OS thread id 1176562016 insertingmysql tables in use 1, locked 1LOCK WAIT 7 lock struct(s), heap size 1216MySQL thread id 1225, query id 4695283 10.120.19.204 db updateINSERT INTO table VALUES(254381,638,1,57)*** (1) WAITING FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space id 0 page no 6371457 n bits 248 index `PRIMARY` of table `db/table` trx id 0 39639074 lock_mode X insert intention waitingRecord lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;;

*** (2) TRANSACTION:TRANSACTION 0 39639079, ACTIVE 0 sec, process no 27807, OS thread id 1179224416 inserting, thread declared inside InnoDB 500mysql tables in use 1, locked 17 lock struct(s), heap size 1216MySQL thread id 1229, query id 4695295 prodgos23.eao.abn-iad.ea.com 10.120.19.204 madden_2010 updateINSERT INTO table VALUES(254382,746,1,57)*** (2) HOLDS THE LOCK(S):RECORD LOCKS space id 0 page no 6371457 n bits 248 index `PRIMARY` of table `madden_2010_franchise_xbl2/franchise_draft_board` trx id 0 39639079 lock_mode XRecord lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space id 0 page no 6371457 n bits 248 index `PRIMARY` of table `db/table` trx id 0 39639079 lock_mode X insert intention waitingRecord lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;;

*** WE ROLL BACK TRANSACTION (2)

Page 22: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Status Variables

Shows incrementing internal counters

Volume of SQL

Read/Write ratio

Page 23: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Status Variables

mysql> SHOW GLOBAL STATUS;

$ mysqladmin extended­status

mysql> SELECT * FROM GLOBAL_STATUS (5.1)

http://dev.mysql.com/doc/refman/5.1/en/show-status.html

Page 24: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Status Variables Example

| Com_select                        | 553971     |

| Com_insert                        | 64068      || Com_insert_select                 | 6521       |

| Com_update                        | 190627     || Com_update_multi                  | 4809       |

| Com_delete                        | 95197      || Com_delete_multi                  | 1408       |

| Com_replace                       | 1549       || Com_replace_select                | 0          |

Page 25: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Status Variables Example (2)

| Bytes_received                    | 635778091  || Bytes_sent                        | 4207810294 |

| Threads_connected                 | 22         || Threads_running                   | 3          |

Throughput

| Bytes_received                    | 635778091  || Bytes_sent                        | 4207810294 |

Load

| Threads_connected                 | 22         || Threads_running                   | 3          |

Server Running

| Uptime                            | 5951       |

Page 26: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Status Variables Example (3)

●$ mysqladmin ­u ­p ­r ­s 1 extended status | grep ­v “| 0”

+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­+| Variable_name                     | Value      |+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­+| Bytes_received                    | 8888       || Bytes_sent                        | 151482     || Com_select                        | 114        || Com_show_status                   | 1          || Created_tmp_tables                | 2          || Handler_read_key                  | 194        || Handler_read_next                 | 273        || Handler_read_rnd                  | 165        || Handler_read_rnd_next             | 47416      || Handler_write                     | 289        || Key_read_requests                 | 1555       || Questions                         | 116        || Select_range                      | 23         || Select_scan                       | 3          || Sort_rows                         | 165        || Sort_scan                         | 3          || Table_locks_immediate             | 115        || Threads_connected                 | ­1         || Threads_running                   | ­1         || Uptime                            | 1          || Uptime_since_flush_status         | 1          |+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­+

Page 27: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

MySQL Proxy

Included histogram.lua

Gives read/write breakdown per table

Shows top executing queries by frequency

Shows max and avg execution time

http://dev.mysql.com/doc/refman/5.1/en/mysql-proxy.html

https://launchpad.net/mysql-proxy

http://ronaldbradford.com/blog/sql-query-analysis-with-mysql-proxy-2009-09-02/

Page 28: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

MySQL Proxy Examplemysql> select * from histogram.tables; +­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­+ | table                        | reads | writes | +­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­+ | schema1.dotCommLookup        |   991 |      0 | | schema2xxxxxx.dotCommClient  |     6 |      0 | | schema2xxxxxx.ReleaseNumbers |     3 |      6 | | schema2xxxxxx.PAYCYCLE       |     1 |      0 | | schema1.dotCommClient        |  1505 |      0 | | schema1.Job                  |   131 |      0 | | schema2xxxxxx.CondMod        |     0 |     28 | | schema2xxxxxx.SPINFO         |     3 |      0 | | schema1.Poll                 |  1184 |    633 | | schema2xxxxxx.LaborSchedules |     0 |     96 | | schema1.JobRequest           |   192 |      0 | | schema1.PollTasks            |   454 |   1048 | | schema1.Tasks                |  1048 |      0 | | schema1.auth                 |   141 |     59 | | schema2xxxxxx.dotComm        |     2 |      0 | | schema2xxxxxx.MenuItem       |     0 |   2446 | | schema1.Location             |    19 |    118 | | schema2xxxxxx.CONCASH        |     2 |      0 | | schema1.dotComm              |   156 |      0 | | schema1.Client               |    47 |      0 | +­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­+ 20 rows in set (0.00 sec)

Page 29: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

MySQL Proxy Example (2)mysql> select * from histogram.queries; *************************** 8. row ***************************          query: SELECT `type` , COUNT( * ) AS `count` FROM `schema1` . `table1` `a` WHERE `clientID` = ? AND `bocDate` = ? AND `locationID` IN( ? ) GROUP BY ? ORDER BY ?          count: 8 max_query_time: 12932 avg_query_time: 4154.125 *************************** 35. row ***************************          query: SELECT `empl_first_nam` , `empl_last_nam` , `empl_mid_initial` FROM `schema2` . `table2` WHERE `clientID` = ? AND `empl_ssn` = ? AND `locationID` = ? LIMIT ?          count: 84 max_query_time: 61974 avg_query_time: 2501.3095238095 *************************** 305. row ***************************          query: INSERT INTO `schema3` . `table3` SET `eventTime` = NOW( ) , `event` = ? , `userID` = ? , `details` = ?          count: 59 max_query_time: 433610 avg_query_time: 38760.983050847 *************************** 302. row ***************************          query: SELECT * FROM `table4` WHERE `jobID` = ? AND `taskID` = ?          count: 1056 max_query_time: 17564 avg_query_time: 672.67708333333

Page 30: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

TCP/IP Capture

Captures network packets

http://www.tcpdump.org/tcpdump_man.html

Page 31: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

TCP/IP Example

2010­05­18 19:08:09.291455 IP 999.67.245.14.3338 > 999.174.90.144.3306: tcp 00x0000:  4500 0030 fdd0 4000 7106 e466 4b43 f50e  [email protected]:  8cae 5a90 0d0a 0cea e1cd 4d71 0000 0000  ..Z.......Mq....0x0020:  7002 ffff 125c 0000 0204 05b4 0101 0402  p....\..........2010­05­18 19:08:09.291519 IP 999.174.90.144.3306 > 999.67.245.14.3338: tcp 00x0000:  4500 0030 0000 4000 4006 1338 8cae 5a90  E..0..@[email protected]:  4b43 f50e 0cea 0d0a 69af 73bf e1cd 4d72  KC......i.s...Mr0x0020:  7012 16d0 1e0c 0000 0204 05b4 0101 0402  p...............2010­05­18 19:08:09.316990 IP 999.67.245.14.3338 > 999.174.90.144.3306: tcp 00x0000:  4500 0028 fdd1 4000 7106 e46d 4b43 f50e  E..([email protected]:  8cae 5a90 0d0a 0cea e1cd 4d72 69af 73c0  ..Z.......Mri.s.0x0020:  5010 ffff 61a0 0000                      P...a...2010­05­18 19:08:09.322483 IP 999.174.90.144.3306 > 999.67.245.14.3338: tcp 670x0000:  4508 006b 7eed 4000 4006 9407 8cae 5a90  E..k~.@[email protected]:  4b43 f50e 0cea 0d0a 69af 73c0 e1cd 4d72  KC......i.s...Mr0x0020:  5018 16d0 574b 0000 3f00 0000 0a35 2e30  P...WK..?....5.00x0030:  2e35 3161 2d63 6f6d 6d75 6e69 7479 0036  .51a­community.60x0040:  9800 0057 7462 6f28 732f 2e00 2ca2 0802  ...Wtbo(s/..,...0x0050:  0000 0000 0000 0000 0000 0000 0000 386f  ..............8o0x0060:  4858 615f 3838 5274 7055 00              HXa_88RtpU.

tcpdump -i any -s 65535 -x -nn -q -tttt port 3306

Page 32: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

DTrace/SystemTap

Observability technologies

Enable the behavior of running systems and applications to be investigated

Zero probe effect when not enabled

http://www.sun.com/bigadmin/content/dtrace/index.jsp

http://sourceware.org/systemtap/

Page 33: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

SystemTap Example# stap query_trace.sty /home/posulliv/repos/mysql/mysql-5.5.2-m2/5.5.2/libexec/mysqldselect @@version_comment limit 1Total: 287us Locks: 0us Engine: 0us Network: 6us Filesort: 0usselect USER()Total: 127us Locks: 0us Engine: 0us Network: 6us Filesort: 0usSELECT DATABASE()Total: 562us Locks: 0us Engine: 0us Network: 21us Filesort: 0usshow databasesTotal: 642us Locks: 0us Engine: 5us Network: 6us Filesort: 0usshow tablesTotal: 1148us Locks: 0us Engine: 6us Network: 6us Filesort: 0usshow tablesTotal: 6201us Locks: 0us Engine: 19us Network: 23us Filesort: 0usSELECT DATABASE()Total: 564us Locks: 0us Engine: 0us Network: 21us Filesort: 0usshow databasesTotal: 81us Locks: 0us Engine: 5us Network: 6us Filesort: 0usshow tablesTotal: 293us Locks: 0us Engine: 5us Network: 6us Filesort: 0usselect * from t1Total: 1202us Locks: 32us Engine: 20us Network: 23us Filesort: 0usselect * from t1 where a = 1Total: 1134us Locks: 30us Engine: 56us Network: 21us Filesort: 0usselect * from t1 order by a descTotal: 4727us Locks: 26us Engine: 20us Network: 22us Filesort: 3182usinsert into t1 values (3, 'tomas')Total: 3406us Locks: 146us Engine: 858us Network: 30us Filesort: 0usselect * from t1 order by a descTotal: 1340us Locks: 27us Engine: 20us Network: 21us Filesort: 228us^C

Page 34: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Analyzing your SQL

Page 35: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Bulk Analysis Tools

Your eyes

Maatkit

mk-query-digest

Page 36: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Slow Query Log

mk-query-digest --type slowlog /path/to/slow.log

Best practice to roll/analyze daily

http://ronaldbradford.com/blog/the-correct-approach-to-rolling-mysql-logs-2010-02-22/

Page 37: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Slow Query Analysis Example●$ mk­query­digest ­­type slowlog /var/log/mysql/slow.log●

# Query 1: 0.00 QPS, 2.74x concurrency, ID 0x036A4959F0EBB3BD at byte ­1 _#              pct   total     min     max     avg     95%  stddev  median# Count          1     395# Exec time     28 478528s     11s   4733s   1211s   4168s   1431s    511s# Lock time     20  31777s       0   2769s     80s    685s    291s       0# Rows sent      0   3.86k      10      10      10      10       0      10# Rows exam      3 193.22M 500.73k 500.96k 500.90k 485.50k       0 485.50k# Users                  1  xxx# Hosts                  5 app5.xxxxx... (128), app1.xxxx... (85)... 3 more# Databases              1  xxxx# Time range 2009­05­18 10:23:18 to 2009­05­20 10:50:14# bytes          0 184.67k     476     479  478.73  463.90       0  463.90# Query_time distribution#   1us#  10us# 100us#   1ms#  10ms# 100ms#    1s#  10s+  ################################################################

Page 38: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Slow Query Analysis Example

# Tables#    SHOW TABLE STATUS FROM `xxxx` LIKE 'gg'\G#    SHOW CREATE TABLE `xxxx`.`gg`\G#    SHOW TABLE STATUS FROM `xxxx ` LIKE 'gr'\G#    SHOW CREATE TABLE `xxxx `.`gr`\G#    SHOW TABLE STATUS FROM `xxxx ` LIKE 'tt'\G#    SHOW CREATE TABLE `xxxx `.`tt`\G# EXPLAINSELECT tt.*,        (SELECT COUNT(*) FROM gg WHERE gg.tt_user_id = tt.id) AS g_c,        (SELECT COUNT(*) FROM  WHERE gr.tt_user_id = tt.id ) AS r_c        FROM tt AS tt        WHERE 1 AND tt.user_type = 'CUSTOMER'        GROUP BY tt.id HAVING g_c > 1 OR r_c > 1        ORDER BY tt.id desc, g_c DESC , r_c DESC        LIMIT 10 OFFSET 0\G

Page 39: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

General Query Log●$ mk­query­digest ­­type genlog ­­report­format profile /opt/mysql_sandboxes/latest/data/msandbox.log

# 2.4s user time, 40ms system time, 37.40M rss, 78.70M vsz# Current date: Fri Jun 11 14:17:22 2010# Files: /opt/mysql_sandboxes/latest/data/msandbox.log# Overall: 17.11k total, 2.64k unique, 0.71 QPS, 0x concurrency __________#                    total     min     max     avg     95%  stddev  median# Exec time              0       0       0       0       0       0       0# Time range        2010­06­11 07:35:44 to 2010­06­11 14:17:01# bytes            793.75k      11  26.50k   47.52   54.21  295.84   38.53

# Profile# Rank Query ID           Response time    Calls R/Call   Item# ==== ================== ================ ===== ======== ================#    1 0xC9EEB2D51C356A33     0.0000  0.0%  3622   0.0000 SET#    2 0x6C099B0B73EA7633     0.0000  0.0%   608   0.0000 USE#    3 0xAC5C18B304F9DE87     0.0000  0.0%   595   0.0000 SELECT#    4 0x30FE5C2032672827     0.0000  0.0%   595   0.0000 SHOW TABLE STATUS#    5 0x1D7CBA0BE5BAA758     0.0000  0.0%   595   0.0000 SHOW TRIGGERS#    6 0xAEA9A980826923AF     0.0000  0.0%   595   0.0000 SET#    7 0x10AB55EA465447D0     0.0000  0.0%   565   0.0000 ADMIN FIELD#    8 0x5D51E5F01B88B79E     0.0000  0.0%   522   0.0000 ADMIN CONNECT#    9 0xAA353644DE4C4CB4     0.0000  0.0%   438   0.0000 ADMIN QUIT#   10 0xE3A3649C5FAC418D     0.0000  0.0%   410   0.0000 SELECT#   11 0x28FC5B5D583E2DA6     0.0000  0.0%   402   0.0000 SHOW STATUS#   12 0x3AEAAD0E15D725B5     0.0000  0.0%   107   0.0000 SET#   13 0x3607184B9D9C3A96     0.0000  0.0%   107   0.0000 SELECT#   14 0x44001A2E53C1AB70     0.0000  0.0%   107   0.0000 SET#   15 0xA2750AF24EA2AEE6     0.0000  0.0%   107   0.0000 SHOW COLLATION#   16 0x38B3D80280BBFA2A     0.0000  0.0%   107   0.0000 SET#   17 0xC69B6ED2C47380A4     0.0000  0.0%   107   0.0000 SHOW VARIABLES#   18 0xE4CF7146873CCC28     0.0000  0.0%   107   0.0000 SET#   19 0x5CBA2034458B5BC9     0.0000  0.0%    95   0.0000 SHOW DATABASES#   20 0x2DE40AAFA6F4B715     0.0000  0.0%    46   0.0000 INSERT SELECT TEMP.task

Page 40: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

General Query Log Analysis$ mk­query­digest ­­type genlog /opt/mysql_sandboxes/latest/data/msandbox.log

# Query 20: 0 QPS, 0x concurrency, ID 0x2DE40AAFA6F4B715 at byte 56687 ___# This item is included in the report because it matches ­­limit.#              pct   total     min     max     avg     95%  stddev  median# Count          0      46# Exec time      0       0       0       0       0       0       0       0# Databases              1 anonymous# Time range 2010­06­11 09:33:04 to 2010­06­11 09:33:04# bytes          3  25.72k     404   1.12k  572.57  833.10  157.30  511.45# Query_time distribution#   1us#  10us# 100us#   1ms#  10ms# 100ms#    1s#  10s+# Tables#    SHOW TABLE STATUS FROM `TEMP` LIKE 'task'\G#    SHOW CREATE TABLE `TEMP`.`task`\Ginsert into TEMP.task(    task_type,     state,     user_table_schema,     user_table_table, user_table_depth,     artifact_schema,     artifact_table,     command ) values(    'GenerateFinalBySort',    'waiting',    'drupal',    'node_revisions',    '0',    'TEMP',    'node_revisions$final',    'create table `TEMP`.`node_revisions$final`(`nid` int, `vid` int, `uid` int, `title` varchar(255), `body` longtext, `teaser` longtext, `log` longtext, `timestamp` int, `format` int) select `nid`, `vid`, `uid`, `title`, `body`, `teaser`, `log`, `timestamp`, `format` from `drupal`.`node_revisions` order by `vid`')\G

Page 41: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Binary Log

mysql> SHOW GLOBAL VARIABLES LIKE 'log_bin';mysql> SHOW MASTER STATUS;mysql> SHOW MASTER LOGS;

Page 42: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Aggregating Binlog Output

  33389 update e_acc  17680 insert into r_b  17680 insert into e_rec  14332 insert into rcv_c  13543 update e_rec  10805 update loc   3339 insert into r_att   2781 insert into o_att

 mysqlbinlog /path/to/mysql­bin.000999 |  \   grep ­i ­e "^update" ­e "^insert" ­e "^delete" ­e "^replace" ­e "^alter"  | \   cut ­c1­100 | tr '[A­Z]' '[a­z]' |  \   sed ­e "s/\t/ /g;s/\`//g;s/(.*$//;s/ set .*$//;s/ as .*$//" | \   sed ­e "s/ where .*$//" |  \   sort | uniq ­c | sort ­nr  

Page 43: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Maatkit$ mysqlbinlog /opt/mysql_sandboxes/latest/data/msandbox.000001 \> | ./mk­query­digest ­­type binlog ­­report­format profile# Profile# Rank Query ID           Response time    Calls R/Call   Item# ==== ================== ================ ===== ======== ================#    1 0xBE1EAF34D33DE48B     0.0000  0.0%     3   0.0000 CREATE TABLE coitest_?k.customers `bulkload`.`customers$final`#    2 0x0A44B866EBFF94FC     0.0000  0.0%     3   0.0000 DROP#    3 0x7B747B0DEABCA018     0.0000  0.0%     3   0.0000 CREATE TABLE coitest_?k.orders `bulkload`.`orders$final`#    4 0xB4E2D6D6475B00FF     0.0000  0.0%     3   0.0000 DROP#    5 0xF5DAC1762A3DE61F     0.0000  0.0%     3   0.0000 DROP#    6 0x42EF521F930E2DB7     0.0000  0.0%     3   0.0000 CREATE TABLE coitest_?k.orders `bulkload`.`orders$parent`#    7 0xE4D87F83229BB741     0.0000  0.0%    18   0.0000 UPDATE bulkload.task#    8 0x5A7960FD3F39E5F8     0.0000  0.0%     3   0.0000 CREATE TABLE bulkload.progress#    9 0x813031B8BBC3B329     0.0000  0.0% 60141   0.0000 COMMIT#   10 0x854DE5DBCC259DFB     0.0000  0.0% 30000   0.0000 INSERT bulkload.items$parent#   11 0x3FBD919BC7E69704     0.0000  0.0%    87   0.0000 INSERT bulkload.progress#   12 0xE50052BA71B4D17C     0.0000  0.0%     3   0.0000 DROP TABLE if#   13 0xD645DADD65C8DD01     0.0000  0.0%    18   0.0000 INSERT SELECT bulkload.task#   14 0x5B6EB50967F9BAB8     0.0000  0.0%    18   0.0000 UPDATE bulkload.task#   15 0x277902B2380B46B4     0.0000  0.0%     1   0.0000 DROP#   16 0x15174D089E600489     0.0000  0.0%     3   0.0000 CREATE TABLE bulkload.task#   17 0x6F1EE7DAFC74D9AF     0.0000  0.0%     3   0.0000 CREATE TABLE coitest_?k.items `bulkload`.`items$child`#   18 0x85FFF5AA78E5FF6A     0.0000  0.0% 60141   0.0000 BEGIN#   19 0x9EE6FD43C5546BA1     0.0000  0.0%     3   0.0000 CREATE TABLE bulkload.items$parent `bulkload`.`items$parent`#   20 0x51DCCB95FA917A6F     0.0000  0.0%     3   0.0000 DROP TABLE if

Page 44: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Status variables Analysis

Gathering global status per time interval

Reporting options

statpack

http://ronaldbradford.com/blog/using-statpack-with-show-status-2009-06-18/

Page 45: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

statpack Example

====================================================================================================              Uptime: 17 days 17 hours 22 mins Snapshot Period 1: 59 minute interval====================================================================================================                    Variable Delta/Percentage      Per Second   Total=================================================================================...

====================================================================================================                                         Statement Activity====================================================================================================

                     SELECT:       13,503,876                 3,798.56            4,298,170,239 (94.25%)                     INSERT:           91,101                    25.63               25,327,062 (0.56%)                     UPDATE:          782,004                   219.97              220,640,296 (4.84%)                     DELETE:            9,674                     2.72                2,485,643 (0.05%)                     COMMIT:           46,422                    13.06               13,700,478 (0.30%)                   ROLLBACK:                0                     0.00                       13 (0.00%)

...

====================================================================================================                                          Temporary Space====================================================================================================

  tmp_table_size Efficiency:           2.10%         Memory Temp Tables:           26,467                     7.45                9,335,030           Disk Temp Tables:           25,951                     7.30                9,138,705                 Temp Files:                2                     0.00                      601

Page 46: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

TCP/IP Dump Analysis

Non-intrusive

Close to full sample

Near realtime

$ tcpdump ­i eth0 port 3306 ­s 65535 ­x \> ­n ­q ­tttt ­c 1000 > tcpdump.out$ cat tcpdump.out | mk­query­digest ­­type tcpdump

Page 47: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

TCP/IP Dump Summary# 4.1s user time, 85.9ms system time, 17.85M rss, 18.46M vsz# Overall: 1.99k total, 86 unique, 321.13 QPS, 0.21x concurrency _________#                    total     min     max     avg     95%  stddev  median# Exec time             1s    39us    70ms   649us   839us     4ms   152us# Time range        2010­03­30 17:52:42.569092 to 2010­03­30 17:52:48.772254# bytes            186.80k      13   1.61k   96.03  166.51  196.84   40.45# Rows affe             59       0       2    0.03       0    0.18       0# Warning c              5       0       2    0.00       0    0.07       0#   4% (98)   No_index_used

# Profile# Rank Query ID           Response time    Calls R/Call   Item# ==== ================== ================ ===== ======== ================#    3 0xC9ECBBF2C88C2336     0.0875  7.5%   568   0.0002 SELECT r_c#    4 0x448E4AEB7E02AF72     0.0785  6.7%   566   0.0001 SELECT r_t#    5 0xCF3A86CFCC509800     0.0596  5.1%     5   0.0119 SELECT h_c_i#    6 0x8D86ED007917BCE6     0.0480  4.1%   131   0.0004 SELECT loc#    7 0xDB8614598CD1ED36     0.0416  3.6%     1   0.0416 SELECT lml r#    8 0x9BA140CF9CE950C8     0.0316  2.7%     1   0.0316 SELECT bsc#    9 0x633F85619F198C33     0.0219  1.9%    23   0.0010 SELECT hlm mt #   10 0xADCCD37E265C8300     0.0197  1.7%    79   0.0002 SELECT h_l_l

Page 48: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

TCP/IP Dump Query Review# Query 6: 23.02 QPS, 0.01x concurrency, ID 0x8D86ED007917BCE6 at byte ­2# This item is included in the report because it matches ­­limit.#              pct   total     min     max     avg     95%  stddev  median# Count          6     131# Exec time      3    48ms   160us     5ms   366us   690us   477us   247us# Hosts                  5 10.0.0.77 (86), 10.0.0.36 (21), 10.0.0.79 (20)... 2 more# Time range 2010­03­30 17:52:43.034021 to 2010­03­30 17:52:48.724815# bytes          8  15.93k     123     125  124.54  124.25       1  124.25# Errors                 1    none# Rows affe      0       0       0       0       0       0       0       0# Warning c      0       0       0       0       0       0       0       0# Query_time distribution#   1us#  10us# 100us  #################################################################   1ms  ###  10ms# 100ms#    1s#  10s+# Tables#    SHOW TABLE STATUS LIKE 'loc'\G#    SHOW CREATE TABLE `loc`\G# EXPLAINSELECT l.* FROM loc p, loc l WHERE p.id=2090 AND l.lft BETWEEN p.lft AND p.rgt AND l.depth=p.depth+1 ORDER BY l.lft\G

Page 49: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

mycheckpoint

SQL orientated monitoring utility for MySQL

Measures various metrics

Stores measurements in database

Metrics can be accessed through SQL

Can generate HTML reports and Google charts easily

http://code.openark.org/forge/mycheckpoint/documentation

Page 50: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

SQL Analysis Tools

EXPLAIN

mk-visual-explain

SHOW CREATE TABLE

SHOW INDEXES

SHOW TABLE STATUS

I_S Table/Index size

SHOW SESSION STATUS

SHOW PROFILE

Page 51: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Explain

Returns information on query plan

Query not actually executed (unless query contains sub-query)

1 row in output per table

EXPLAIN EXTENDED shows query actually executed

http://dev.mysql.com/doc/refman/5.1/en/explain.html

Page 52: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Explain Examples

mysql> explain select 1;+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­+|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used | +­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­+1 row in set (0.00 sec)

mysql> explain select 1\G*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: NULL         type: NULLpossible_keys: NULL          key: NULL      key_len: NULL          ref: NULL         rows: NULL        Extra: No tables used1 row in set (0.00 sec)

mysql>

Page 53: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Explain Examples

mysql> explain    ­> select     ­>   avg(length(w.variables)) / 1048576    ­> from     ­>   watchdog w    ­> \G*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: w         type: ALLpossible_keys: NULL          key: NULL      key_len: NULL          ref: NULL         rows: 69248        Extra: 1 row in set (0.00 sec)

mysql>

Page 54: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

mk-visual-explain

Reverse engineers explain output from MySQL

Formats MySQL explain output as a left-deep tree

Can take piped input or can process explain plans from input file

http://www.maatkit.org/doc/mk-visual-explain.html

Page 55: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

mk-visual-explain Examples

Filesort+­ TEMPORARY   table          temporary(b,r)   +­ JOIN      +­ Distinct/Not­Exists      |  +­ Filter with WHERE      |     +­ Index lookup      |        key            r­>PRIMARY      |        possible_keys  PRIMARY      |        key_len        292      |        ref            drupal.b.module,drupal.b.delta      |        rows           3      +­ Filter with WHERE         +­ Bookmark lookup            +­ Table            |  table          b            |  possible_keys  tmd,list            +­ Index lookup               key            b­>tmd               possible_keys  tmd,list               key_len        194               ref            con

echo "explain SELECT DISTINCT b.* FROM blocks b LEFT JOIN blocks_roles r ON b.module = r.module AND b.delta = r.delta WHERE b.theme = 'garland' AND b.status = 1 AND (r.rid IN (2) OR r.rid IS NULL) ORDER BY b.region, b.weight, b.module" | \mysql ­u root drupal | \mk­visual­explain

Page 56: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Show Create Table

Shows full definition

Includes all keys

Shows storage engine

http://dev.mysql.com/doc/refman/5.1/en/show-create-table.html

SHOW CREATE TABLE [schema.]tablename

Page 57: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Show Create Table Example

mysql> SHOW CREATE TABLE wp_postmeta\G*************************** 1. row ***************************       Table: wp_postmetaCreate Table: CREATE TABLE `wp_postmeta` (  `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,  `post_id` bigint(20) unsigned NOT NULL DEFAULT '0',  `meta_key` varchar(255) DEFAULT NULL,  `meta_value` longtext,  PRIMARY KEY (`meta_id`),  KEY `post_id` (`post_id`),  KEY `meta_key` (`meta_key`)) ENGINE=MyISAM AUTO_INCREMENT=1745 DEFAULT CHARSET=utf81 row in set (0.00 sec)

Page 58: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Show Indexes

Provides cardinality

http://dev.mysql.com/doc/refman/5.1/en/show-index.html

SHOW INDEX[ES] [FROM|IN] [schema.]tablename

Page 59: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Show Index Example

mysql> SHOW INDEXES FROM wp_postmeta;+­­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­­­­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­+­­­­­­+­­­­­­­­­­­­+| Table       | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | +­­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­­­­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­+­­­­­­+­­­­­­­­­­­­+| wp_postmeta |          0 | PRIMARY  |            1 | meta_id     | A         |        1351 |     NULL | NULL   |      | BTREE      |    | wp_postmeta |          1 | post_id  |            1 | post_id     | A         |         450 |     NULL | NULL   |      | BTREE      |    | wp_postmeta |          1 | meta_key |            1 | meta_key    | A         |           7 |     NULL | NULL   | YES  | BTREE      |    +­­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­­­­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­+­­­­­­+­­­­­­­­­­­­+

Page 60: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Table Status

SHOW TABLE STATUS [IN schema] LIKE 'tablename'

http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html

Page 61: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Table Status Example

mysql> SHOW TABLE STATUS LIKE 'wp_postmeta'\G*************************** 1. row ***************************           Name: wp_postmeta         Engine: MyISAM        Version: 10     Row_format: Dynamic           Rows: 1351 Avg_row_length: 46    Data_length: 62960Max_data_length: 281474976710655   Index_length: 58368      Data_free: 76 Auto_increment: 1745    Create_time: 2009­09­08 09:57:51    Update_time: 2010­06­04 15:06:47     Check_time: 2010­06­01 11:12:54      Collation: utf8_general_ci       Checksum: NULL Create_options:         Comment: 1 row in set (0.00 sec)

Page 62: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Information Schema

INFORMATION_SCHEMA

TABLES

COLUMNS

Meta data

Simple view of DBA_TABLES/COLUMNS

http://dev.mysql.com/doc/refman/5.1/en/information-schema.html

Page 63: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Information Schema Example

SELECT   table_schema,         table_name,         engine,         row_format,          table_rows,          avg_row_length,         (data_length+index_length)/1024/1024 as total_mb,          (data_length)/1024/1024 as data_mb,          (index_length)/1024/1024 as index_mb,         CURDATE() AS todayFROM     information_schema.tables WHERE    table_schema=DATABASE()ORDER BY 7 DESC;

http://ronaldbradford.com/mysql-dba/#perschema

Page 64: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Information Schema Example

+­­­­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­+­­­­­­­­­­­­­­+­­­­­­­­­­­­­­+| table_name       | engine | row_format | table_rows | avg_row_length | total_mb     | data_mb      | index_mb     |+­­­­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­+­­­­­­­­­­­­­­+­­­­­­­­­­­­­­+| xxxxxxx          | InnoDB | Compact    |    1778523 |            314 | 658.39062500 | 533.84375000 | 124.54687500 || xxxxxxxxx        | InnoDB | Compact    |     553266 |            846 | 472.25000000 | 446.75000000 |  25.50000000 || xxxxxxx          | InnoDB | Compact    |     435892 |            884 | 392.25000000 | 367.81250000 |  24.43750000 || xxxxxxxxxxxxxx   | InnoDB | Compact    |    1106547 |             65 | 133.26562500 |  68.59375000 |  64.67187500 || xxxxxxxxxxxxxxxx | InnoDB | Compact    |      58281 |            531 |  30.34375000 |  29.51562500 |   0.82812500 || xxxxxxxxxx       | InnoDB | Compact    |      68721 |            298 |  28.12500000 |  19.54687500 |   8.57812500 |

...

Page 65: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Show Session Status

MySQL Internal counters

http://dev.mysql.com/doc/refman/5.1/en/show-status.html

Page 66: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Show Session Status ExampleSHOW SESSION STATUS LIKE 'Created%';+­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­+| Variable_name           | Value |+­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­+| Created_tmp_disk_tables | 1     | | Created_tmp_files       | 5     | | Created_tmp_tables      | 3     | +­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­+

SHOW SESSION STATUS LIKE 'Created%';+­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­+| Variable_name           | Value |+­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­+| Created_tmp_disk_tables | 2     | | Created_tmp_files       | 5     | | Created_tmp_tables      | 3     | +­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­+

SELECT ...;

Page 67: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Show Profile

Provides internal message calls

Descriptions not always accurate

http://dev.mysql.com/doc/refman/5.1/en/show-profiles.html

SET PROFILING = 1;SHOW PROFILES;SHOW PROFILE [FOR QUERY n];

Page 68: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Show Profile Example

mysql> SHOW PROFILES\G*************************** 1. row ***************************Query_ID: 1Duration: 0.00081600   Query: SELECT t.*, tt.*, tr.object_id FROM wp_terms               AS t INNER JOIN wp_term_taxonomy AS tt ON               tt.term_id = t.term_id INNER JOIN               wp_term_relationships AS tr ON                tr.term_taxonomy_id = tt.term_taxonomy_id               WHERE tt.taxonomy IN              ('category', 'post_tag') AND               tr.object_id IN (2487)               ORDER BY t.name ASC

Page 69: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Show Profile Example (2)mysql> SHOW PROFILE SOURCE FOR QUERY 1;+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­­­+| Status                         | Duration | Source_function  | Source_file   | Source_line |+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­­­+| starting                       | 0.000049 | NULL             | NULL          |        NULL || checking query cache for query | 0.000074 | unknown function | sql_cache.cc  |        1446 || Opening tables                 | 0.000013 | unknown function | sql_base.cc   |        4495 || System lock                    | 0.000005 | unknown function | lock.cc       |         258 || Table lock                     | 0.000032 | unknown function | lock.cc       |         269 || init                           | 0.000038 | unknown function | sql_select.cc |        2484 || optimizing                     | 0.000014 | unknown function | sql_select.cc |         820 || statistics                     | 0.000135 | unknown function | sql_select.cc |        1011 || preparing                      | 0.000017 | unknown function | sql_select.cc |        1033 || Creating tmp table             | 0.000155 | unknown function | sql_select.cc |        1524 || executing                      | 0.000002 | unknown function | sql_select.cc |        1755 || Copying to tmp table           | 0.000142 | unknown function | sql_select.cc |        1902 || Sorting result                 | 0.000026 | unknown function | sql_select.cc |        2176 || Sending data                   | 0.000051 | unknown function | sql_select.cc |        2309 || end                            | 0.000002 | unknown function | sql_select.cc |        2530 || removing tmp table             | 0.000063 | unknown function | sql_select.cc |       10776 || end                            | 0.000003 | unknown function | sql_select.cc |       10801 || query end                      | 0.000002 | unknown function | sql_parse.cc  |        4978 || freeing items                  | 0.000017 | unknown function | sql_parse.cc  |        6004 || storing result in query cache  | 0.000005 | unknown function | sql_cache.cc  |         983 || logging slow query             | 0.000001 | unknown function | sql_parse.cc  |        1679 || cleaning up                    | 0.000002 | unknown function | sql_parse.cc  |        1647 |+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­­­+22 rows in set (0.00 sec)

Page 70: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Show Profile Example (3)

mysql> SHOW PROFILES;+­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­|        1 | 0.00084800 | SELECT t.*, tt.*, tr.object_id FROM wp_terms AS t ...|        2 | 0.00006000 | SELECT t.*, tt.*, tr.object_id FROM wp_terms AS t ....+­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­2 rows in set (0.00 sec)

mysql> SHOW PROFILE SOURCE FOR QUERY 2;+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­+­­­­­­­­­­­­­+| starting                       | 0.000034 | NULL             | NULL         |        NULL || checking query cache for query | 0.000008 | unknown function | sql_cache.cc |        1446 || checking privileges on cached  | 0.000004 | unknown function | sql_cache.cc |        1534 || sending cached result to clien | 0.000010 | unknown function | sql_cache.cc |        1629 || logging slow query             | 0.000002 | unknown function | sql_parse.cc |        1679 || cleaning up                    | 0.000002 | unknown function | sql_parse.cc |        1647 |+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­+­­­­­­­­­­­­­+

Page 71: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Optimizing your SQL

Page 72: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

About the MySQL Optimizer

Cost based optimizer

No way to pin QEP

One index per table rule (with exceptions)

The lack of good hints

No statistics granularity

No parallelismhttp://forge.mysql.com/wiki/How_does_the_MySQL_Optimizer_workhttp://forge.mysql.com/wiki/How_does_the_MySQL_Optimizer_work

Page 73: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

SQL Optimization Goals

Identify the best indexes

Reduce unnecessary data access

Minimize kernel internals

Page 74: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Explain Signs

No index used

Large rows

Excessive possible indexes

SQL for composite/covering indexes

Using Temporary

Using filesort

Derived tables

Page 75: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

MySQL Index Types

Column indexes

Composite indexes

Covering indexes

Partial indexes

Spatial indexes

Fulltext indexes

Clustered indexes

Hash indexeshttp://ronaldbradford.com/blog/understanding-different-mysql-index-implementations-2009-07-22/http://ronaldbradford.com/blog/understanding-different-mysql-index-implementations-2009-07-22/

Page 76: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Column Index – Sub-optimal Design

CREATE TABLE `content` (  `ContentID` int(11) NOT NULL auto_increment,....  `Promo` tinyint(1) NOT NULL,  `Theme` float NOT NULL,  `ForDelete` tinyint(1) NOT NULL,  PRIMARY KEY  (`ContentID`),  KEY `CategoryID` (`CategoryID`),  KEY `Verified` (`Verified`),  KEY `FileName` (`FileName`(10)),  KEY `FileDuration` (`FileDuration`),  KEY `Votes` (`Votes`),  KEY `FileDir` (`FileDir`),  KEY `ForDelete` (`ForDelete`),  KEY `UserID` (`UserID`),  KEY `Type` (`Type`),  KEY `CategoryType` (`CategoryType`),  KEY `DateAdded` (`DateAdded`)) 

Page 77: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Composite Indexes Example

CREATE TABLE relationship (  relation_id bigint NOT NULL auto_increment,  type_id bigint default NULL,  user_1 bigint NOT NULL,  user_2 bigint NOT NULL,...  PRIMARY KEY  (relation_id),  KEY user_1 (user_1),  KEY user_2 (user_2),);

Page 78: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Composite Indexes

explain SELECT user_2 FROM relationship WHERE user_1 = '1580980221' AND user_2 IN (508534334,521894993);+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­+| id | select_type | table         | type  | possible_keys | key    | key_len | ref  | rows | Extra       |+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­+|  1 | SIMPLE      | relationship  | range | user_1,user_2 | user_2 | 8       | NULL |    2 | Using where | +­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­+

ALTER TABLE relationship DROP INDEX user_2, ADD INDEX user_2 (user_2, user_1);

+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­+| id | select_type | table         | type  | possible_keys | key    | key_len | ref  | rows | Extra                   |+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­+|  1 | SIMPLE      | relationship  | range | user_1,user_2 | user_2 | 16      | NULL |    2 | Using where;Using Index | +­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­+

Page 79: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Covering Indexes ExampleCREATE TABLE logging (  source_addr int(10) unsigned NOT NULL,  source_port int(9) unsigned NOT NULL,  destn_addr int(10) unsigned NOT NULL,  destn_port int(9) unsigned NOT NULL,  protocol int(9) unsigned NOT NULL,  log_time int(11) unsigned NOT NULL,  size int(11) unsigned NOT NULL,  KEY log_time (log_time),  KEY size (size),  KEY source_port (src_port),  KEY destn_port (destn_port),  KEY source_addr (source_addr),  KEY destn_addr (dstn_addr)) ENGINE=MyISAM;

Page 80: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Covering Indexes

SELECT source_port, SUM(size) FROM logging WHERE log_time BETWEEN 1 AND 2 GROUP BY source_port ORDER BY SUM(size) DESC LIMIT 0,20+­­­­+­­­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+| id | select_type | table   | type  | possible_keys | key  | key_len | ref  | rows  | Extra                                        |+­­­­+­­­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+|  1 | SIMPLE      | logging | range | log_time      | log_t| 4       | NULL | 69997 | Using where; Using temporary; Using filesort | +­­­­+­­­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+

By changing the index we achieve an index only scan.

ALTER TABLE loggingDROP INDEX log_time, DROP INDEX source_port,ADD INDEX (log_time, source_port, size );

+­­­­+­­­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+| id | select_type | table   | type  | possible_keys | key  | key_len | ref  | rows  | Extra                                                     |+­­­­+­­­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+|  1 | SIMPLE      | logging | range | log_time      | log_t| 4       | NULL | 69977 | Using where; Using index; Using temporary; Using filesort | +­­­­+­­­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+

Page 81: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Partial IndexesCREATE TABLE parts( ...  brand_id INT UNSIGNED NOT NULL,  part_number VARCHAR(30) NOT NULL,  manufacturer_name VARCHAR(100) NOT NULL,...  INDEX (brand_id, part_number,manufacturer_name))

ALTER TABLE parts DROP INDEX brand_id,ADD KEY (brand_id,         interchange_part_number,         manufacturer_name(8));

Reduced Index size by 30%.

Page 82: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

QEP – Using Filesort

EXPLAIN SELECT itemid FROM items WHERE productid=999 GROUP BY itemid;+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­+| id | select_type | table | type | possible_keys | key       | key_len | ref   | rows | Extra                       |+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­+|  1 | SIMPLE      | items | ref  | productid     | productid | 4       | const |    1 | Using where; Using filesortUsing filesort | +­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­+1 row in set (0.00 sec)

EXPLAIN SELECT DISTINCTDISTINCT itemid FROM items WHERE productid=999+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­+| id | select_type | table | type | possible_keys | key       | key_len | ref   | rows | Extra |+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­+|  1 | SIMPLE      | items | ref  | productid     | productid | 4       | const |    1 |       | +­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­+

Page 83: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

QEP – Using Filesort

mysql> show profile source for query 1;+­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­­­+| Status             | Duration | Source_function       | Source_file   | Source_line |+­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­­­+| (initialization)   | 0.000003 | open_tables           | sql_base.cc   |        ...| preparing          | 0.000021 | exec                  | sql_select.cc |        1594 | | executing          | 0.000005 | exec                  | sql_select.cc |        1990 | | Sorting result     | 0.000121 | exec                  | sql_select.cc |        2114 | | Sending data       | 0.000033 | mysql_select          | sql_select.cc |        2318 | | end                | 0.000007 | mysql_execute_command | sql_parse.cc  |        5141 | | query end          | 0.000005 | mysql_parse           | sql_parse.cc  |        6142 | ...

Page 84: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

MySQL Index Sizes

NULL columns

Bigint vs int

InnoDB secondary index PK value

Page 85: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

NULL Index Columns

CREATE TABLE child(  child_id INT UNSIGNED NOT NULL,  parent_id INT UNSIGNED,PRIMARY KEY(child_id),INDEX(parent_id));

mysql> explain select * from child where parent_id=42;+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­+| id | select_type | table | type | possible_keys | key       | key_len | ref   | rows | Extra       |+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­+|  1 | SIMPLE      | child | ref  | parent_id     | parent_id | 5       | const |    1 | Using where |+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­+

Page 86: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

NULL Index Columns (2)

mysql> SELECT parent_id FROM CHILD PROCEDURE ANALYSE(5,2000)\G*************************** 1. row ***************************             Field_name: odtug.CHILD.parent_id              Min_value: 1              Max_value: 13             Min_length: 1             Max_length: 2       Empties_or_zeros: 0                  Nulls: 0Avg_value_or_avg_length: 7.0000                    Std: 3.7417      Optimal_fieldtype: TINYINT(2) UNSIGNED NOT NULL1 row in set (0.00 sec)

Page 87: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

NULL Index Columns (3)

ALTER TABLE child MODIFY parent_id INT UNSIGNED NOT NULL;

+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­+| id | select_type | table | type | possible_keys | key       | key_len | ref   | rows | Extra |+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­+|  1 | SIMPLE      | child | ref  | parent_id     | parent_id | 4       | const |    1 |       |+­­­­+­­­­­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­+­­­­­­+­­­­­­­+

Page 88: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

BIGINT vs INTexplain SELECT user_2 FROM relationship WHERE user_1 = '1580980221' AND user_2 IN (508534334,521894993); 

+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­+| id | select_type | table         | type  | possible_keys | key    | key_len | ref  | rows | Extra                   |+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­+|  1 | SIMPLE      | relationship  | range | user_1,user_2 | user_2 | 16      | NULL |    2 | Using where;Using Index | +­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­+

ALTER TABLE relationship MODIFY user_1 INT NOT NULL, MODIFY user_2 INT NOT NULL);

explain SELECT user_2 FROM relationship WHERE user_1 = '1580980221' AND user_2 IN (508534334,521894993); 

+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­+| id | select_type | table         | type  | possible_keys | key    | key_len | ref  | rows | Extra                   |+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­+|  1 | SIMPLE      | relationship  | range | user_1,user_2 | user_2 | 8       | NULL |    2 | Using where;Using Index | +­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­+

Page 89: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

MySQL Index Sizes

NULL columns

Bigint vs int

InnoDB secondary index PK value

Page 90: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

When Indexes Don't HelpCREATE TABLE `items` (  `itemid` int(11) NOT NULL auto_increment,  `productid` int(11) NOT NULL default '0',...  `itemlive` enum('true','false') NOT NULL default 'true',...  PRIMARY KEY  (`itemid`),  KEY `productid` (`productid`)KEY `productid` (`productid`),  KEY `packaging_cost` (`packaging_cost`))

Page 91: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

When Indexes Don't Help

EXPLAINSELECT DISTINCT(categories.categoryid) FROM categories, category_product, itemsWHERE categories.categoryname!='' AND categories.categoryid=category_product.categoryidAND category_product.productid=items.productidAND category_product.productid=items.productid AND items.itemlive='true'; 

+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+| id | select_type | table            | type   | possible_keys        | key       | key_len | ref                                | rows | Extra                        |+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+|  1 | SIMPLE      | items            | ALL    | productid            | NULLNULL      | NULL    | NULL                               | 2906 | Using where; Using temporary | |  1 | SIMPLE      | category_product | ref    | categoryid,productid | productid | 4       | baris5.items.productid             |    1 |                              | |  1 | SIMPLE      | categories       | eq_ref | PRIMARY              | PRIMARY   | 4       | baris5.category_product.categoryid |    1 | Using where                  | +­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+3 rows in set (0.00 sec)

Page 92: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

When Indexes Don't Help

Adding an index can reduce this full table scan

mysql> alter table items drop index productid, add index (productid,itemlive);

+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+| id | select_type | table            | type   | possible_keys        | key       | key_len | ref                                | rows | Extra                                     |+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+|  1 | SIMPLE      | items            | index  | productid            | productid | 5       | NULL                               | 2180 | Using where; Using index; Using temporary | |  1 | SIMPLE      | category_product | ref    | categoryid,productid | productid | 4       | ronald.items.productid             |    1 |                                           | |  1 | SIMPLE      | categories       | eq_ref | PRIMARY              | PRIMARY   | 4       | baris5.category_product.categoryid |    1 | Using where                               | +­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­+­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+

Page 93: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Optimizing SQL for Locking

DML is a blocking statement for MyISAM

Long running cleanup scripts

3+ minutes to run SELECT

DELETE FROM fts_datacacheWHERE productid NOT IN (SELECT productidFROM xcart_products_categoriesWHERE categoryid IN (297,1356,1366,1361,1202,...)GROUP BY productid

Page 94: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Optimizing SQL for Locking

Rewriting statement into 2 statements can reduce locking time to ~10 ms

CREATE TEMPORARY TABLE delete_cache (productid INT NOT NULL, primary key (productid)) ENGINE=MEMORYSELECT DISTINCT productidFROM retailbl_xcart.xcart_products_categoriesWHERE categoryid IN (297,1356,1366,1361,1202,...);

DELETE FROM fts_datacacheWHERE productid NOT IN (SELECT productid FROM delete_cache);

Page 95: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Don't Forget UpdateUPDATE T SET STATE = 'MISFIRED' WHERE (STATE = 'WAITING' OR STATE = 'WAITING') AND NEXT_FIRE_TIME < 263352299544

EXPLAIN SELECT NAME,STATEFROM TWHERE (STATE = 'WAITING' OR STATE = 'WAITING') AND NEXT_FIRE_TIME < 263350625813;

+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­+| id | select_type | table         | type | possible_keys | key  | key_len | ref  | rows | Extra       |+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­+|  1 | SIMPLE      | QRTZ_TRIGGERS | ALL  | NULL          | NULL | NULL    | NULL | 1185 | Using where |+­­­­+­­­­­­­­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­­­­­­­+­­­­­­+­­­­­­­­­+­­­­­­+­­­­­­+­­­­­­­­­­­­­+

Page 96: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Remove Duplicate IndexesCREATE TABLE `accounts` (  `accountid` int(11) NOT NULL auto_increment,...  `retail_date` date NOT NULL,  `customer_survey` tinyint(1) NOT NULL default '1',  PRIMARY KEY  (`accountid`),    KEY `accountid` (`accountid`)KEY `accountid` (`accountid`));

CREATE TABLE `vehicle_applications` (

 PRIMARY KEY  (`id`),  KEY `mcp_index` (`product_id`,`make`,`model`,`year`),  KEY `status_idx` (`status`),  KEY `sid_idx` (`status_identifier`),    KEY `product_id_idx` (`product_id`),KEY `product_id_idx` (`product_id`),)

Page 97: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

The Most Optimal SQL is the SQL You

Can Eliminate

Page 98: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Eliminating SQL – Example 1

SELECT pages_id,        pages_livestats_code,        pages_title,        pages_parent,        pages_exhibid,        pages_theme,        pages_accession_num FROM pages WHERE pages_id = 0

Following executed 6,000 times in 5 min period

0 is an invalid pages_id

Page 99: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Eliminating SQL – Example 2

5 Query   SELECT *  FROM `artist`5 Query   SELECT *  FROM `artist`5 Query   SELECT *  FROM `artist`5 Query   SELECT *  FROM `artist`5 Query   SELECT *  FROM `artist`5 Query   SELECT *  FROM `artist` WHERE (ArtistID = 196 )5 Query   SELECT *  FROM `artist` WHERE (ArtistID = 2188)5 Query   SELECT *  FROM `artist`5 Query   SELECT *  FROM `artist`5 Query   SELECT *  FROM `artist`

Following executed on single page load

Page 100: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Eliminating SQL – Example 3

Row at a time (RAT) processing

SELECT * FROM activities_theme WHERE theme_parent_id=0SELECT * FROM activities_theme WHERE theme_parent_id=1SELECT * FROM activities_theme WHERE theme_parent_id=2SELECT * FROM activities_theme WHERE theme_parent_id=11SELECT * FROM activities_theme WHERE theme_parent_id=16

Chunk at a time (CAT) processing

SELECT * FROM   activities_theme WHERE  theme_parent_id in  (0,1,2,11,16) 

Page 101: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Conclusion

Page 102: Capturing, Analyzing and Optimizing MySQL

ODTUG – June 2010

Capture/Analysis/Optimization

Improvement is a reoccurring process

Ideally you should analyze all SQL

Changes in data size and result set size over time can affect SQL performance