MYSQL 應該是最流行了 WEB 後端數據庫。WEB 開發語言近期發展很是快,PHP, Ruby, Python, Java 各有特色,儘管 NOSQL 近期越來越多的被提到,但是相信大部分架構師仍是會選擇 MYSQL 來作數據存儲。mysql
MYSQL 如此方便和穩定。以致於咱們在開發 WEB 程序的時候很是少想到它。即便想到優化也是程序級別的,比方。不要寫過於消耗資源的 SQL 語句。但是除此以外,在整個系統上仍然有很是多可以優化的地方。ios
除非你的數據表使用來作僅僅讀或者全文檢索 (相信現在提到全文檢索,沒人會用 MYSQL 了)。你應該默認選擇 InnoDB 。sql
你本身在測試的時候可能會發現 MyISAM 比 InnoDB 速度快。這是因爲: MyISAM 僅僅緩存索引,而 InnoDB 緩存數據和索引,MyISAM 不支持事務。但是 假設你使用 innodb_flush_log_at_trx_commit = 2 可以得到接近的讀取性能 (相差百倍) 。數據庫
mysql -u [USER_NAME] -p -e "SHOW TABLES IN [DATABASE_NAME];" | tail -n +2 | xargs -I '{}' echo "ALTER TABLE {} ENGINE=InnoDB;" > alter_table.sql perl -p -i -e 's/(search_[a-z_]+ ENGINE=)InnoDB//1MyISAM/g' alter_table.sql mysql -u [USER_NAME] -p [DATABASE_NAME] < alter_table.sql
innodb_file_per_table=1
這樣可以保證 ibdata1 文件不會過大。失去控制。尤爲是在運行 mysqlcheck -o –all-databases 的時候。後端
推薦將數據全然保存在 innodb_buffer_pool_size ,即按存儲量規劃 innodb_buffer_pool_size 的容量。這樣你可以全然從內存中讀取數據。最大限度下降磁盤操做。緩存
方法 1安全
mysql> SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool_pages_%'; +----------------------------------+--------+ | Variable_name | Value | +----------------------------------+--------+ | Innodb_buffer_pool_pages_data | 129037 | | Innodb_buffer_pool_pages_dirty | 362 | | Innodb_buffer_pool_pages_flushed | 9998 | | Innodb_buffer_pool_pages_free | 0 | !!!!!!!! | Innodb_buffer_pool_pages_misc | 2035 | | Innodb_buffer_pool_pages_total | 131072 | +----------------------------------+--------+ 6 rows in set (0.00 sec)
發現 Innodb_buffer_pool_pages_free 爲 0,則說明 buffer pool 已經被用光,需要增大 innodb_buffer_pool_size架構
InnoDB 的其它幾個參數:框架
innodb_additional_mem_pool_size = 1/200 of buffer_pool innodb_max_dirty_pages_pct 80%
方法 2函數
或者用iostat -d -x -k 1 命令,查看硬盤的操做。
運行 echo 1 > /proc/sys/vm/drop_caches 清除操做系統的文件緩存。可以看到真正的內存使用量。
默認狀況,僅僅有某條數據被讀取一次,纔會緩存在 innodb_buffer_pool。因此,數據庫剛剛啓動,需要進行數據預熱,將磁盤上的所有數據緩存到內存中。
數據預熱可以提升讀取速度。
對於 InnoDB 數據庫,可以用下面方法,進行數據預熱:
1. 將下面腳本保存爲 MakeSelectQueriesToLoad.sql
SELECT DISTINCT CONCAT('SELECT ',ndxcollist,' FROM ',db,'.',tb, ' ORDER BY ',ndxcollist,';') SelectQueryToLoadCache FROM ( SELECT engine,table_schema db,table_name tb, index_name,GROUP_CONCAT(column_name ORDER BY seq_in_index) ndxcollist FROM ( SELECT B.engine,A.table_schema,A.table_name, A.index_name,A.column_name,A.seq_in_index FROM information_schema.statistics A INNER JOIN ( SELECT engine,table_schema,table_name FROM information_schema.tables WHERE engine='InnoDB' ) B USING (table_schema,table_name) WHERE B.table_schema NOT IN ('information_schema','mysql') ORDER BY table_schema,table_name,index_name,seq_in_index ) A GROUP BY table_schema,table_name,index_name ) AA ORDER BY db,tb ;
2. 運行
mysql -uroot -AN < /root/MakeSelectQueriesToLoad.sql > /root/SelectQueriesToLoad.sql
3. 每次從新啓動數據庫,或者整庫備份前需要預熱的時候運行:
mysql -uroot < /root/SelectQueriesToLoad.sql > /dev/null 2>&1
假設是專用 MYSQL server。可以禁用 SWAP,假設是共享server,肯定 innodb_buffer_pool_size 足夠大。或者使用固定的內存空間作緩存,使用 memlock 指令。
mysqlcheck -o –all-databases 會讓 ibdata1 不斷增大。真正的優化僅僅有重建數據表結構:
CREATE TABLE mydb.mytablenew LIKE mydb.mytable; INSERT INTO mydb.mytablenew SELECT * FROM mydb.mytable; ALTER TABLE mydb.mytable RENAME mydb.mytablezap; ALTER TABLE mydb.mytablenew RENAME mydb.mytable; DROP TABLE mydb.mytablezap;
但是需要注意假設用 1G 的 innodb_log_file_size 。假如server當機。需要 10 分鐘來恢復。
推薦 innodb_log_file_size 設置爲 0.25 * innodb_buffer_pool_size
這個選項和寫磁盤操做密切相關:
innodb_flush_log_at_trx_commit = 1 則每次改動寫入磁盤
innodb_flush_log_at_trx_commit = 0/2 每秒寫入磁盤
假設你的應用不涉及很是高的安全性 (金融系統),或者基礎架構足夠安全,或者 事務都很是小,都可以用 0 或者 2 來減小磁盤操做。
innodb_flush_method=O_DIRECT
RAID0 尤爲是在使用 EC2 這樣的虛擬磁盤 (EBS) 的時候,使用軟 RAID0 很重要。
SHOW CREATE TABLE db1.tb1/G
6.2 加入必要的索引
索引是提升查詢速度的惟一方法。比方搜索引擎用的倒排索引是同樣的原理。
索引的加入需要依據查詢來肯定。比方經過慢查詢日誌或者查詢日誌,或者經過 EXPLAIN 命令分析查詢。
ADD UNIQUE INDEX ADD INDEX
加入索引
ALTER TABLE users ADD UNIQUE INDEX username_ndx (username); ALTER TABLE users ADD UNIQUE INDEX username_password_ndx (username,password);
每次從新啓動server進行數據預熱
echo 「select username,password from users;」 > /var/lib/mysql/upcache.sql
加入啓動腳本到 my.cnf
[mysqld] init-file=/var/lib/mysql/upcache.sql
比方。Rails 這種框架。會本身主動加入索引。Drupal 這種框架會本身主動拆分表結構。
會在你開發的初期指明正確的方向。因此,經驗不太豐富的人一開始就追求從 0 開始構建,實際是很差的作法。
記錄所有查詢。這在用 ORM 系統或者生成查詢語句的系統很是實用。
log=/var/log/mysql.log
注意不要在生產環境用。不然會佔滿你的磁盤空間。
記錄運行時間超過 1 秒的查詢:
long_query_time=1 log-slow-queries=/var/log/mysql/log-slow-queries.log
現在基礎設施的可靠性已經很是高了,比方 EC2 差點兒不用操心server硬件當機。而且內存實在是廉價。很是easy買到幾十G內存的server,可以用內存磁盤。按期備份到磁盤。
將 MYSQL 文件夾遷移到 4G 的內存磁盤
mkdir -p /mnt/ramdisk sudo mount -t tmpfs -o size=4000M tmpfs /mnt/ramdisk/ mv /var/lib/mysql /mnt/ramdisk/mysql ln -s /tmp/ramdisk/mysql /var/lib/mysql chown mysql:mysql mysql
B-TREE 仍然是最高效的索引之中的一個,所有 MYSQL 仍然不會過期。
用 HandlerSocket 跳過 MYSQL 的 SQL 解析層。MYSQL 就真正變成了 NOSQL。