淺析MySQL數據碎片的產生
原創(chuàng)【51CTO獨家譯文】本文淺析MySQL數據碎片的產生:定義,時間及成因。
MySQL列表,包括MyISAM和InnoDB這兩種最常見的類型,而根據經驗來說,其碎片的產生及消除都是隨機的。碎片會在你的表格中留下明顯的空白,而這會給列表掃描工作帶來相當大的困擾。對你的列表進行優(yōu)化,這樣會使列表的全面及分區(qū)掃描工作進行得更有效率。
碎片——實例
MySQL具有相當多不同種類的存儲引擎來實現列表中的數據存儲功能。每當MySQL從你的列表中刪除了一行內容,該段空間就會被留空。而在一段時間內的大量刪除操作,會使這種留空的空間變得比存儲列表內容所使用的空間更大。當MySQL對數據進行掃描時,它掃描的對象實際是列表的容量需求上限,也就是數據被寫入的區(qū)域中處于峰值位置的部分。如果進行新的插入操作,MySQL將嘗試利用這些留空的區(qū)域,但仍然無法將其徹底占用。
這種額外的破碎的存儲空間在讀取效率方面比正常占用的空間要低得多。讓我們看一個實例。
我們將創(chuàng)建一個數據庫(有時也稱其為大綱)及一個測試用的列表:
- (root@localhost) [test]> create database frag_test;
- Query OK, 1 row affected (0.03 sec)
- (root@localhost) [test]> use frag_test;
- Database changed
- (root@localhost) [frag_test]> create table frag_test (c1 varchar(64));
- Query OK, 0 rows affected (0.05 sec)
現在讓我們在列表中加入如下幾行:
- (root@localhost) [frag_test]> insert into frag_test values ('this is row 1');
- Query OK, 1 row affected (0.01 sec)
- (root@localhost) [frag_test]> insert into frag_test values ('this is row 2');
- Query OK, 1 row affected (0.00 sec)
- (root@localhost) [frag_test]> insert into frag_test values ('this is row 3');
- Query OK, 1 row affected (0.00 sec)
現在我們進行碎片查看:
- (root@localhost) [frag_test]> show table status from frag_test\G;
- *************************** 1. row ***************************
- Name: frag_test
- Engine: MyISAM
- Version: 10
- Row_format: Dynamic
- Rows: 3
- Avg_row_length: 20
- Data_length: 60
- Max_data_length: 281474976710655
- Index_length: 1024
- Data_free: 0
- Auto_increment: NULL
- Create_time: 2011-02-23 14:55:27
- Update_time: 2011-02-23 15:06:55
- Check_time: NULL
- Collation: latin1_swedish_ci
- Checksum: NULL
- Create_options:
- Comment:
- 1 row in set (0.00 sec)
現在我們刪除一行,并再次檢測:
- (root@localhost) [frag_test]> delete from frag_test where c1 = 'this is row 2';
- Query OK, 1 row affected (0.00 sec)
- (root@localhost) [frag_test]> show table status from frag_test\G;
- *************************** 1. row ***************************
- Name: frag_test
- Engine: MyISAM
- Version: 10
- Row_format: Dynamic
- Rows: 2
- Avg_row_length: 20
- Data_length: 60
- Max_data_length: 281474976710655
- Index_length: 1024
- Data_free: 20
- Auto_increment: NULL
- Create_time: 2011-02-23 14:55:27
- Update_time: 2011-02-23 15:07:49
- Check_time: NULL
- Collation: latin1_swedish_ci
- Checksum: NULL
- Create_options:
- Comment:
- 1 row in set (0.00 sec)
需要注意的是,“data_free”一欄顯示出了我們刪除第二行后所產生的留空空間。想象一下如果你有兩萬行指令的話,結果是什么樣的。以此推算,它們將耗費四十萬字節(jié)的存儲空間?,F在如果你將兩萬條命令行刪到只剩一行,列表中有用的內容將只占二十字節(jié),但MySQL在讀取中會仍然將其視同于一個容量為四十萬字節(jié)的列表進行處理,并且除二十字節(jié)以外,其它空間都被白白浪費了。
清理碎片
幸運的是一旦你鎖定了這一問題,MySQL提供了一種簡便的修正方法。這就是所謂的優(yōu)化列表,具體內容如下:
- (root@localhost) [frag_test]> optimize table frag_test;
- +---------------------+----------+----------+----------+
- | Table | Op | Msg_type | Msg_text |
- +---------------------+----------+----------+----------+
- | frag_test.frag_test | optimize | status | OK |
- +---------------------+----------+----------+----------+
- 1 row in set (0.00 sec)
- (root@localhost) [frag_test]> show table status from frag_test\G;
- *************************** 1. row ***************************
- Name: frag_test
- Engine: MyISAM
- Version: 10
- Row_format: Dynamic
- Rows: 2
- Avg_row_length: 20
- Data_length: 40
- Max_data_length: 281474976710655
- Index_length: 1024
- Data_free: 0
- Auto_increment: NULL
- Create_time: 2011-02-23 14:55:27
- Update_time: 2011-02-23 15:11:05
- Check_time: 2011-02-23 15:11:05
- Collation: latin1_swedish_ci
- Checksum: NULL
- Create_options:
- Comment:
- 1 row in set (0.00 sec)
性能考量
“優(yōu)化列表”功能在進行中會對整個列表進行鎖定。對于小型列表,這一功能的效果非常好,因為整個列表的讀取和修改速度都會很快。但對于那些體積巨大的列表來說,這一過程將消耗很長時間,并且其間會中斷或減少可用的應用程序數量。怎么辦?
再一次,MySQL幸運地提供了一項堪稱偉大的功能,名為“主-主復制”。在這種配置之下,你的后臺數據庫實際上成為兩個單獨的數據庫,一個主動可調用的,一個被動可調整的。這兩個數據庫在各方面來說都是完全相同的。要實現各種在線操作——包括“優(yōu)化列表”操作——只需在你的被動數據庫中即可進行。這將不會對你的應用程序造成絲毫影響。一旦優(yōu)化操作完成,主、被動數據庫將互相轉換,以便應用程序直接指向二號數據庫,對還未進行優(yōu)化的主動數據庫部分自動開始優(yōu)化工作。
這時,兩套數據庫的角色已經互換,而應用程序也將順利指向二號數據庫,執(zhí)行與在一號數據庫上相同的列表優(yōu)化。而現在主動已經轉換為被動,因此不會中斷主要任務處理。
其它命令
顯示你數據庫中存在碎片的全部列表:
- (root@localhost) [(none)]> select table_schema, table_name, data_free, engine from information_schema.tables where table_schema not in ('information_schema', 'mysql') and data_free > 0;
- +--------------+-----------------------------+-----------+--------+
- | table_schema | table_name | data_free | engine |
- +--------------+-----------------------------+-----------+--------+
- | aitc | wp_comments | 346536 | MyISAM |
- | aitc | wp_options | 64308 | MyISAM |
- | aitc | wp_postmeta | 124 | MyISAM |
- | cactidb | poller_item | 160 | MyISAM |
- | cactidb | poller_output | 384 | MyISAM |
- | drupal | sessions | 30976 | MyISAM |
- | drupal | users | 92 | MyISAM |
- | drupal | variable | 20 | MyISAM |
- | gg | wp_comments | 232 | MyISAM |
- | gg | wp_options | 696 | MyISAM |
- | gg | wp_postmeta | 560 | MyISAM |
- | ihi | wp_comments | 536 | MyISAM |
- | ihi | wp_options | 444 | MyISAM |
- | ihi | wp_postmeta | 288 | MyISAM |
- | ihi | wp_redirection_items | 1292 | MyISAM |
- | ihi | wp_redirection_logs | 140352 | MyISAM |
- | nds | wp_comments | 4704 | MyISAM |
- | nds | wp_options | 150580 | MyISAM |
- | nds | wp_postmeta | 76 | MyISAM |
- | oos | wp_comments | 317124 | MyISAM |
- | oos | wp_options | 88196 | MyISAM |
- | oos | wp_postmeta | 76 | MyISAM |
- | phplist | phplist_listuser | 252 | MyISAM |
- | phplist | phplist_sendprocess | 52 | MyISAM |
- | phplist | phplist_user_user | 32248 | MyISAM |
- | phplist | phplist_user_user_attribute | 120 | MyISAM |
- | phplist | phplist_user_user_history | 288 | MyISAM |
- | phplist | phplist_usermessage | 1428 | MyISAM |
- | pn_nds | nuke_session_info | 12916 | MyISAM |
- | psa | exp_event | 10024 | MyISAM |
- | test | active_sessions | 30144 | MyISAM |
- +--------------+-----------------------------+-----------+--------+
- 31 rows in set (0.26 sec)
如果你更改了某個列表的存儲引擎,你也應該對這一列表進行碎片清理。這是因為MySQL的工作原理導致其必須讀取整個列表,然后利用新的存儲引擎將內容寫回磁盤,而在此過程中碎片所在的位置及影響到的數據都對執(zhí)行效率造成了嚴重的不良影響。
上述情況如下所示:
- (root@localhost) [frag_test]> alter table frag_test engine = innodb;
- Query OK, 2 rows affected (0.17 sec)
- Records: 2 Duplicates: 0 Warnings: 0
- (root@localhost) [frag_test]> show table status from frag_test
- -> \G;
- *************************** 1. row ***************************
- Name: frag_test
- Engine: InnoDB
- Version: 10
- Row_format: Compact
- Rows: 2
- Avg_row_length: 8192
- Data_length: 16384
- Max_data_length: 0
- Index_length: 0
- Data_free: 0
- Auto_increment: NULL
- Create_time: 2011-02-23 15:41:12
- Update_time: NULL
- Check_time: NULL
- Collation: latin1_swedish_ci
- Checksum: NULL
- Create_options:
- Comment: InnoDB free: 7168 kB
- 1 row in set (0.00 sec)
結論
如果你發(fā)現一些列表中包含了大量的數據留空現象,那么對其進行優(yōu)化是絕對值得的,因為這一過程會大大提升列表的讀取性能及應用表現。
原文地址:http://www.databasejournal.com/features/mysql/article.php/3927871/article.htm
【編輯推薦】