Index shotgun on mysql5.6
Upcoming SlideShare
Loading in...5
×
 

Index shotgun on mysql5.6

on

  • 3,555 views

2013/04/17 MySQL Casual Talks #4の資料です。

2013/04/17 MySQL Casual Talks #4の資料です。
当日ぐだぐだにしゃべったのよりもう少し状況の説明をしています。。遅くなりましたorz

Statistics

Views

Total Views
3,555
Views on SlideShare
1,641
Embed Views
1,914

Actions

Likes
2
Downloads
5
Comments
0

3 Embeds 1,914

http://d.hatena.ne.jp 1880
https://twitter.com 33
http://webcache.googleusercontent.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Index shotgun on mysql5.6 Index shotgun on mysql5.6 Presentation Transcript

  • Index Shotgunon MySQL 5.6(provisional)2013/04/17yoku0825Modified version 2
  • I’m yoku0825,working as DBAfor the company’s web-service.My wife’s husband, my son’s father,lovin’ MySQL and Hannari-Tofu too much.I can’t even log in to PostgreSQL and Oracle but I’m fine! :)
  • Have you read`SQL Antipatterns’?
  • `Index Shotgun’ is one of theAntipatterns described in it.
  • In Japanese.
  • (;´д`) 索引大杉
  • And I saw `Shotguned Index atour MySQL.なんとIndex_lengthがData_lengthの4倍。
  • ( ´-`).oO(標準から見て4倍が多すぎるのかどうかは判らないだけど、本の索引が本文の4倍もあったら嫌だ
  • By the way, Why is shotgunedindex Antipattern?Or "How much does it decreaseperformance?"
  • 測ってみたCPUXeon L5520 2.27GHz 1P4C8TMemory12GiB(dont know any details)StorageRAID Controller(RAID5, 8PD)read 2450MiB/s, 3950IOPSwrite 2450MiB/s, 3900IOPSext4 on LVM(noatimeしてない)my.cnf[mysqld]query-cache-type = 0loose-innodb-buffer-pool-size = 1Gloose-innodb-buffer-pool-instances = 1loose-innodb-log-file-size = 128Mloose-innodb-file-per-table = 1loose-innodb-file-format = barracuda
  • 測ってみた+--------------+------------------+------+-----+-------------------+-------+| Field | Type | Null | Key | Default | Extra |+--------------+------------------+------+-----+-------------------+-------+| num | int(10) unsigned | NO | | 0 | || md5 | varchar(32) | YES | | NULL | || sha | varchar(40) | YES | | NULL | || old_password | varchar(16) | YES | | NULL | || password | varchar(41) | YES | | NULL | || timeval | timestamp | NO | | CURRENT_TIMESTAMP | |+--------------+------------------+------+-----+-------------------+-------+1行あたり140bytes。テストデータ1000万行をひたすらINSERTする苦行。データは1.4GiB。
  • InnoDB(5.5) - INSERT duration0:00:000:07:120:14:240:21:360:28:480:36:000:43:120:50:240:57:361:04:481:12:00no key pri(4) pri(4) +1key(32)pri(4) +1key(72)pri(4) +1key(88)pri(4) +1key(129)pri(4) +3key(12)pri(4) +3key(76)pri(4) +3key(144)pri(4) +3key(160)
  • InnoDB(5.5) - size01,000,000,0002,000,000,0003,000,000,0004,000,000,0005,000,000,0006,000,000,000no key pri(4) pri(4) +1key(32)pri(4) +1key(72)pri(4) +1key(88)pri(4) +1key(129)pri(4) +3key(12)pri(4) +3key(76)pri(4) +3key(144)pri(4) +3key(160)
  • • 72byteのKey1つと合計76byteになるKey3つではそんなに変わらなさそう。• 1行140bytesしかないテーブルなので、インデックスの作成がもろにテーブル全体のサイズに影響する– 社内で出会った炸裂インデックスももともとは.ibdファイルでっかくね? からだった。
  • 散弾銃索引退治• 取り敢えず重複インデックスがあったから消した(基本)• 本当はもうちょっと削りたい。– なんか上手い具合にINDEXの使われ度合いを測れないもんかな?– Percona ServerやMariaDBには、そのインデックスを使って何行フェッチしたか統計を取るinformation_schemaが突っ込まれている。
  • pt-duplicate-key-entryPercona Toolkitの1つで、重複インデックスを検出してくれる。$ pt-duplicate-key-checker S=/usr/mysql/5.5.30/data/mysql.sock,u=tpcc,p=xxxx --database=tpcc# ######################################################################### tpcc.stock# ######################################################################### s_w_id is a left-prefix of PRIMARY# Key definitions:# KEY `s_w_id` (`s_w_id`),# PRIMARY KEY (`s_w_id`,`s_i_id`),# Column types:# `s_w_id` smallint(6) not null# `s_i_id` int(11) not null# To remove this duplicate index, execute:ALTER TABLE `tpcc`.`stock` DROP INDEX `s_w_id`;# ######################################################################### Summary of indexes# ######################################################################### Size Duplicate Indexes 2# Total Duplicate Indexes 1# Total Indexes 25http://www.percona.com/doc/percona-toolkit/2.1/pt-duplicate-key-checker.htmlまずこれを退治。
  • information_schema.INNODB_BUFFER_PAGE• 5.6.2から搭載された– 5.5.28, 5.1.66にもバックポートされてる(5.1.66はplugin-loadで食わせてやる必要がある)• InnoDB Buffer Poolにどんなページが載ってるのかがinformation_schemaからアクセスできる。– これで載ってるインデックスページ調べれば幸せになれるんじゃない? とか思った。
  • information_schema.INNODB_BUFFER_PAGE_LRU+---------------------+---------------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+---------------------+---------------------+------+-----+---------+-------+| POOL_ID | bigint(21) unsigned | NO | | 0 | || LRU_POSITION | bigint(21) unsigned | NO | | 0 | | LRUリストの位置| SPACE | bigint(21) unsigned | NO | | 0 | || PAGE_NUMBER | bigint(21) unsigned | NO | | 0 | || PAGE_TYPE | varchar(64) | YES | | NULL | | UNDO_LOG, INDEX, SYSTEMとか| FLUSH_TYPE | bigint(21) unsigned | NO | | 0 | || FIX_COUNT | bigint(21) unsigned | NO | | 0 | || IS_HASHED | varchar(3) | YES | | NULL | || NEWEST_MODIFICATION | bigint(21) unsigned | NO | | 0 | | このページを最後に更新したLSN| OLDEST_MODIFICATION | bigint(21) unsigned | NO | | 0 | | このページを最初に更新したLSN| ACCESS_TIME | bigint(21) unsigned | NO | | 0 | | 初めてバッファプールに載った時間| TABLE_NAME | varchar(1024) | YES | | NULL | || INDEX_NAME | varchar(1024) | YES | | NULL | || NUMBER_RECORDS | bigint(21) unsigned | NO | | 0 | | そのページに載っている行| DATA_SIZE | bigint(21) unsigned | NO | | 0 | | そのページに載っているByte数| COMPRESSED_SIZE | bigint(21) unsigned | NO | | 0 | || COMPRESSED | varchar(3) | YES | | NULL | || IO_FIX | varchar(64) | YES | | NULL | || IS_OLD | varchar(3) | YES | | NULL | | OLDページかどうか| FREE_PAGE_CLOCK | bigint(21) unsigned | NO | | 0 | | ページがLRUリストから落ちるとインクリメント+---------------------+---------------------+------+-----+---------+-------+
  • information_schema.INNODB_BUFFER_PAGE_LRU• とりあえず起動直後の状態をチェック。innodb_buffer_pool_size = 5M(=256ページ)mysql56> SELECT lru_position, table_name, index_name, number_records AS num, data_size, is_old, newest_modification AS LSN, access_time FROMinnodb_buffer_page_lru WHERE page_type = INDEX;+--------------+--------------------------------+-----------------------+-----+-----------+--------+-----+-------------+| lru_position | table_name | index_name | num | data_size | is_old | LSN | access_time |+--------------+--------------------------------+-----------------------+-----+-----------+--------+-----+-------------+| 210 | `SYS_IBUF_TABLE` | CLUST_IND | 0 | 0 | NO | 0 | 1153626747 || 218 | `mysql`.`innodb_index_stats` | PRIMARY | 46 | 4060 | NO | 0 | 1153626732 || 219 | `mysql`.`innodb_table_stats` | PRIMARY | 11 | 635 | NO | 0 | 1153626720 || 220 | `SYS_TABLES` | ID_IND | 20 | 613 | NO | 0 | 1153626698 || 221 | `SYS_TABLES` | CLUST_IND | 20 | 1513 | NO | 0 | 1153626661 || 222 | `SYS_COLUMNS` | CLUST_IND | 103 | 6784 | NO | 0 | 1153626696 || 223 | `SYS_DATAFILES` | SYS_DATAFILES_SPACE | 16 | 766 | NO | 0 | 1153626748 || 224 | `SYS_TABLESPACES` | SYS_TABLESPACES_SPACE | 16 | 750 | NO | 0 | 1153626748 || 225 | `SYS_INDEXES` | CLUST_IND | 25 | 1715 | NO | 0 | 1153626695 || 240 | `SYS_FIELDS` | CLUST_IND | 30 | 1274 | NO | 0 | 1153626696 || 241 | `SYS_FOREIGN` | FOR_IND | 4 | 148 | NO | 0 | 1153626696 || 242 | `SYS_FOREIGN` | ID_IND | 4 | 280 | NO | 0 | 1153626768 || 243 | `SYS_FOREIGN_COLS` | ID_IND | 4 | 246 | NO | 0 | 1153626768 || 244 | `SYS_FOREIGN` | REF_IND | 4 | 152 | NO | 0 | 1153626696 || 245 | `test`.`item` | PRIMARY | 17 | 938 | NO | 0 | 1153626777 || 247 | `mysql`.`slave_master_info` | PRIMARY | 0 | 0 | NO | 0 | 1153626963 || 250 | `mysql`.`slave_worker_info` | PRIMARY | 0 | 0 | NO | 0 | 1153626975 || 253 | `mysql`.`slave_relay_log_info` | PRIMARY | 0 | 0 | NO | 0 | 1153626984 |+--------------+--------------------------------+-----------------------+-----+-----------+--------+-----+-------------+18 rows in set (0.01 sec)– lru_positionは大きい方が最近ぽい。– そういえばmysql.slave_*はInnoDBだっけ。
  • information_schema.INNODB_BUFFER_PAGE_LRU• テーブル1つ(test.brand)スキャンしてみる。mysql56> SELECT lru_position, table_name, index_name, number_records AS num, data_size, is_old, newest_modification AS LSN, access_time FROMinnodb_buffer_page_lru WHERE page_type = INDEX;+--------------+--------------------------------+-----------------------+-----+-----------+--------+-----+-------------+| lru_position | table_name | index_name | num | data_size | is_old | LSN | access_time |+--------------+--------------------------------+-----------------------+-----+-----------+--------+-----+-------------+| 208 | `SYS_IBUF_TABLE` | CLUST_IND | 0 | 0 | NO | 0 | 1153626747 || 216 | `mysql`.`innodb_table_stats` | PRIMARY | 11 | 635 | NO | 0 | 1153626720 || 217 | `SYS_TABLES` | ID_IND | 20 | 613 | NO | 0 | 1153626698 || 218 | `SYS_DATAFILES` | SYS_DATAFILES_SPACE | 16 | 766 | NO | 0 | 1153626748 || 219 | `SYS_TABLESPACES` | SYS_TABLESPACES_SPACE | 16 | 750 | NO | 0 | 1153626748 || 234 | `test`.`item` | PRIMARY | 17 | 938 | NO | 0 | 1153626777 || 236 | `mysql`.`slave_master_info` | PRIMARY | 0 | 0 | NO | 0 | 1153626963 || 239 | `mysql`.`slave_worker_info` | PRIMARY | 0 | 0 | NO | 0 | 1153626975 || 242 | `mysql`.`slave_relay_log_info` | PRIMARY | 0 | 0 | NO | 0 | 1153626984 || 245 | `SYS_TABLES` | CLUST_IND | 20 | 1513 | NO | 0 | 1153626661 || 246 | `SYS_COLUMNS` | CLUST_IND | 103 | 6784 | NO | 0 | 1153626696 || 247 | `SYS_INDEXES` | CLUST_IND | 25 | 1715 | NO | 0 | 1153626695 || 248 | `SYS_FIELDS` | CLUST_IND | 30 | 1274 | NO | 0 | 1153626696 || 249 | `SYS_FOREIGN` | FOR_IND | 4 | 148 | NO | 0 | 1153626696 || 250 | `SYS_FOREIGN` | ID_IND | 4 | 280 | NO | 0 | 1153626768 || 251 | `SYS_FOREIGN_COLS` | ID_IND | 4 | 246 | NO | 0 | 1153626768 || 252 | `SYS_FOREIGN` | REF_IND | 4 | 152 | NO | 0 | 1153626696 || 253 | `mysql`.`innodb_index_stats` | PRIMARY | 46 | 4060 | NO | 0 | 1153626732 || 254 | `test`.`brand` | PRIMARY | 10 | 575 | NO | 0 | 1154017292 |+--------------+--------------------------------+-----------------------+-----+-----------+--------+-----+-------------+19 rows in set (0.01 sec)– lru_position 254に載ったから、やっぱりこっちがyoung側の気がする。– でもミッドポイント挿入戦略とかいうのがなかったっけ。– SELECTしただけだからnewest_modificationはからっぽ、access_timeは記録される。
  • information_schema.INNODB_BUFFER_PAGE_LRU• test.brandに1行INSERTしてみる。mysql56> SELECT lru_position, table_name, index_name, number_records AS num, data_size, is_old, newest_modification AS LSN, access_time FROMinnodb_buffer_page_lru WHERE page_type = INDEX;+--------------+--------------------------------+-----------------------+-----+-----------+--------+-----------+-------------+| lru_position | table_name | index_name | num | data_size | is_old | LSN | access_time |+--------------+--------------------------------+-----------------------+-----+-----------+--------+-----------+-------------+| 202 | `SYS_IBUF_TABLE` | CLUST_IND | 0 | 0 | NO | 0 | 1153626747 || 210 | `mysql`.`innodb_table_stats` | PRIMARY | 11 | 635 | NO | 0 | 1153626720 || 211 | `SYS_TABLES` | ID_IND | 20 | 613 | NO | 0 | 1153626698 || 212 | `SYS_DATAFILES` | SYS_DATAFILES_SPACE | 16 | 766 | NO | 0 | 1153626748 || 213 | `SYS_TABLESPACES` | SYS_TABLESPACES_SPACE | 16 | 750 | NO | 0 | 1153626748 || 228 | `test`.`item` | PRIMARY | 17 | 938 | NO | 0 | 1153626777 || 230 | `mysql`.`slave_master_info` | PRIMARY | 0 | 0 | NO | 0 | 1153626963 || 233 | `mysql`.`slave_worker_info` | PRIMARY | 0 | 0 | NO | 0 | 1153626975 || 236 | `mysql`.`slave_relay_log_info` | PRIMARY | 0 | 0 | NO | 0 | 1153626984 || 239 | `SYS_TABLES` | CLUST_IND | 20 | 1513 | NO | 0 | 1153626661 || 240 | `SYS_COLUMNS` | CLUST_IND | 103 | 6784 | NO | 0 | 1153626696 || 241 | `SYS_INDEXES` | CLUST_IND | 25 | 1715 | NO | 0 | 1153626695 || 242 | `SYS_FIELDS` | CLUST_IND | 30 | 1274 | NO | 0 | 1153626696 || 243 | `SYS_FOREIGN` | FOR_IND | 4 | 148 | NO | 0 | 1153626696 || 244 | `SYS_FOREIGN` | ID_IND | 4 | 280 | NO | 0 | 1153626768 || 245 | `SYS_FOREIGN_COLS` | ID_IND | 4 | 246 | NO | 0 | 1153626768 || 246 | `SYS_FOREIGN` | REF_IND | 4 | 152 | NO | 0 | 1153626696 || 247 | `mysql`.`innodb_index_stats` | PRIMARY | 46 | 4060 | NO | 0 | 1153626732 || 248 | `test`.`brand` | PRIMARY | 11 | 614 | NO | 319272605 | 1154017292 || 252 | `test`.`factory` | PRIMARY | 4 | 254 | NO | 0 | 1154232813 || 254 | `test`.`brand` | maker | 11 | 360 | NO | 319272654 | 1154232814 |+--------------+--------------------------------+-----------------------+-----+-----------+--------+-----------+-------------+21 rows in set (0.01 sec)– test.factoryが読み込まれたのは、FOREIGN KEYを切ってるからっぽい(FOREIGN KEYを消すと載らない)– PRIMARY INDEXとmaker INDEXがそれぞれLSNが記録されてる。
  • ということは• LSNが記録されていない(=0)のレコードはSELECTだけされてるやつだから使われているって根拠になりそう。– LNS <> 0で検索してみようか。• SELECTで特定のINDEXを使った場合はそのINDEX(とデータフェッチ用にPRIMARY KEY)だけが載るので、テーブル上の全部のインデックスがリストされている =INSERTで載ったと思えそう。– information_schema.statisticsとJOINして相関サブクエリでゴニョゴニョやろうとしたらものすごく重くなったので断念。。– information_schemaってテンポラリテーブルみたいに毎回データをストアしてるぽいので、相関サブクエリだと確かに悲惨になるよね。。
  • と思ったんですが• 本番に5.5.28(以降)が2台しかなかった。• しかもその2台(Master & Slave)はバッファプールがガラガラだった。• とりあえず、newest_modification = 0のページは無かった。。– 一度LRUリストから落ちて次に読み込まれると、newest_modificationは0に戻るのね。• あと、InnoDB Compressed使ってるのですんごくinnodb_buffer_page_lruへのアクセスが重い。• Master & Slaveで分散させてると、そのチェック結果をマージしないとダメそうだよね。。• あと、access_timeがミリ秒単位のUNIXTIMEを32bitunsignedで受け取っているので、49.7日くらいでオーバーフローする。。
  • Percona Serverのinformation_schema. INDEX_STATISTICSみたいにずぱっとどれくらい使ってるのか判るわけじゃない。mysql> SET GLOBAL userstat=on;..mysql> SELECT * FROM index_statistics;+--------------+------------+------------+-----------+| TABLE_SCHEMA | TABLE_NAME | INDEX_NAME | ROWS_READ |+--------------+------------+------------+-----------+| tpcc | item | PRIMARY | 100000 |+--------------+------------+------------+-----------+1 row in set (0.00 sec)いやこれもどのインデックス使ってないかっていう銀の弾丸じゃないけど。
  • 上手く考察する方法求む
  • By the way,
  • Where does it go “on MySQL5.6(provisional)”?
  • 5.5と5.6で比較したんですが、有意差が出ないという`比べてみた’ネタとしては最悪の結果になったので
  • Upgrading 5.6 from 5.5 hasn’t effect onshotguned indexes.
  • という結論になりました。ごめんなさいごめんなさい。
  • でもinnodb_buffer_page_lruは楽しかったです。上手いこと分析したい。
  • ご清聴ありがとうございました