MYSQL 應該是最流行了 WEB 后端數(shù)據(jù)庫,。WEB 開發(fā)語言最近發(fā)展很快,,PHP, Ruby, Python, Java 各有特點,,雖然 NOSQL 最近越來越多的被提到,,但是相信大部分架構師還是會選擇 MYSQL 來做數(shù)據(jù)存儲。 MYSQL 如此方便和穩(wěn)定,,以至于我們在開發(fā) WEB 程序的時候很少想到它,。即使想到優(yōu)化也是程序級別的,比如,,不要寫過于消耗資源的 SQL 語句,。但是除此之外,在整個系統(tǒng)上仍然有很多可以優(yōu)化的地方,。 1. 選擇合適的存儲引擎: InnoDB 除非你的數(shù)據(jù)表使用來做只讀或者全文檢索 (相信現(xiàn)在提到全文檢索,,沒人會用 MYSQL 了),你應該默認選擇 InnoDB ,。 你自己在測試的時候可能會發(fā)現(xiàn) MyISAM 比 InnoDB 速度快,,這是因為: MyISAM 只緩存索引,,而 InnoDB 緩存數(shù)據(jù)和索引,MyISAM 不支持事務,。但是 如果你使用 innodb_flush_log_at_trx_commit = 2 可以獲得接近的讀取性能 (相差百倍) ,。 1.1 如何將現(xiàn)有的 MyISAM 數(shù)據(jù)庫轉(zhuǎn)換為 InnoDB: 復制代碼 代碼如下: 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 1.2 為每個表分別創(chuàng)建 InnoDB FILE: 復制代碼 代碼如下: innodb_file_per_table=1
這樣可以保證 ibdata1 文件不會過大,失去控制,。尤其是在執(zhí)行 mysqlcheck -o –all-databases 的時候,。
2. 保證從內(nèi)存中讀取數(shù)據(jù),講數(shù)據(jù)保存在內(nèi)存中 2.1 足夠大的 innodb_buffer_pool_size 推薦將數(shù)據(jù)完全保存在 innodb_buffer_pool_size ,,即按存儲量規(guī)劃 innodb_buffer_pool_size 的容量,。這樣你可以完全從內(nèi)存中讀取數(shù)據(jù),最大限度減少磁盤操作,。 2.1.1 如何確定 innodb_buffer_pool_size 足夠大,,數(shù)據(jù)是從內(nèi)存讀取而不是硬盤? 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) 發(fā)現(xiàn) Innodb_buffer_pool_pages_free 為 0,,則說明 buffer pool 已經(jīng)被用光,,需要增大 innodb_buffer_pool_size InnoDB 的其他幾個參數(shù): 復制代碼 代碼如下: innodb_additional_mem_pool_size = 1/200 of buffer_pool
innodb_max_dirty_pages_pct 80% 方法 2 或者用iostat -d -x -k 1 命令,查看硬盤的操作,。 2.1.2 服務器上是否有足夠內(nèi)存用來規(guī)劃 2.2 數(shù)據(jù)預熱 默認情況,,只有某條數(shù)據(jù)被讀取一次,,才會緩存在 innodb_buffer_pool。所以,,數(shù)據(jù)庫剛剛啟動,,需要進行數(shù)據(jù)預熱,將磁盤上的所有數(shù)據(jù)緩存到內(nèi)存中,。數(shù)據(jù)預熱可以提高讀取速度,。 對于 InnoDB 數(shù)據(jù)庫,可以用以下方法,,進行數(shù)據(jù)預熱: 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. 執(zhí)行 復制代碼 代碼如下: mysql -uroot -AN < /root/MakeSelectQueriesToLoad.sql > /root/SelectQueriesToLoad.sql 3. 每次重啟數(shù)據(jù)庫,,或者整庫備份前需要預熱的時候執(zhí)行: mysql -uroot < /root/SelectQueriesToLoad.sql > /dev/null 2>&1 2.3 不要讓數(shù)據(jù)存到 SWAP 中 如果是專用 MYSQL 服務器,可以禁用 SWAP,,如果是共享服務器,,確定 innodb_buffer_pool_size 足夠大?;蛘呤褂霉潭ǖ膬?nèi)存空間做緩存,,使用 memlock 指令。
3. 定期優(yōu)化重建數(shù)據(jù)庫 mysqlcheck -o –all-databases 會讓 ibdata1 不斷增大,,真正的優(yōu)化只有重建數(shù)據(jù)表結構: 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;
4. 減少磁盤寫入操作 4.1 使用足夠大的寫入緩存 innodb_log_file_size 但是需要注意如果用 1G 的 innodb_log_file_size ,,假如服務器當機,,需要 10 分鐘來恢復。 推薦 innodb_log_file_size 設置為 0.25 * innodb_buffer_pool_size 4.2 innodb_flush_log_at_trx_commit 這個選項和寫磁盤操作密切相關: innodb_flush_log_at_trx_commit = 1 則每次修改寫入磁盤 如果你的應用不涉及很高的安全性 (金融系統(tǒng)),,或者基礎架構足夠安全,,或者 事務都很小,都可以用 0 或者 2 來降低磁盤操作,。 4.3 避免雙寫入緩沖 復制代碼 代碼如下: innodb_flush_method=O_DIRECT
5. 提高磁盤讀寫速度 RAID0 尤其是在使用 EC2 這種虛擬磁盤 (EBS) 的時候,,使用軟 RAID0 非常重要。
6. 充分使用索引 6.1 查看現(xiàn)有表結構和索引 復制代碼 代碼如下: SHOW CREATE TABLE db1.tb1/G
6.2 添加必要的索引 索引是提高查詢速度的唯一方法,,比如搜索引擎用的倒排索引是一樣的原理,。 索引的添加需要根據(jù)查詢來確定,比如通過慢查詢?nèi)罩净蛘卟樵內(nèi)罩?或者通過 EXPLAIN 命令分析查詢,。 復制代碼 代碼如下: ADD UNIQUE INDEX ADD INDEX 6.2.1 比如,,優(yōu)化用戶驗證表: 復制代碼 代碼如下: ALTER TABLE users ADD UNIQUE INDEX username_ndx (username); ALTER TABLE users ADD UNIQUE INDEX username_password_ndx (username,password); 每次重啟服務器進行數(shù)據(jù)預熱 復制代碼 代碼如下: echo “select username,password from users;” > /var/lib/mysql/upcache.sql 添加啟動腳本到 my.cnf 復制代碼 代碼如下: [mysqld]
init-file=/var/lib/mysql/upcache.sql 6.2.2 使用自動加索引的框架或者自動拆分表結構的框架 7. 分析查詢?nèi)罩竞吐樵內(nèi)罩?/span> 記錄所有查詢,,這在用 ORM 系統(tǒng)或者生成查詢語句的系統(tǒng)很有用,。 復制代碼 代碼如下: log=/var/log/mysql.log
注意不要在生產(chǎn)環(huán)境用,,否則會占滿你的磁盤空間。 記錄執(zhí)行時間超過 1 秒的查詢: 復制代碼 代碼如下: long_query_time=1
log-slow-queries=/var/log/mysql/log-slow-queries.log 8. 激進的方法,,使用內(nèi)存磁盤 現(xiàn)在基礎設施的可靠性已經(jīng)非常高了,,比如 EC2 幾乎不用擔心服務器硬件當機。而且內(nèi)存實在是便宜,,很容易買到幾十G內(nèi)存的服務器,,可以用內(nèi)存磁盤,定期備份到磁盤,。 將 MYSQL 目錄遷移到 4G 的內(nèi)存磁盤 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 9. 用 NOSQL 的方式使用 MYSQL B-TREE 仍然是最高效的索引之一,,所有 MYSQL 仍然不會過時。 用 HandlerSocket 跳過 MYSQL 的 SQL 解析層,,MYSQL 就真正變成了 NOSQL,。 10. 其他 單條查詢最后增加 LIMIT 1,停止全表掃描,。 以上就是10個MySQL性能調(diào)優(yōu)的方法,,希望對大家的學習有所幫助。 |
|
來自: Bladexu的文庫 > 《數(shù)據(jù)庫》