1. 選擇合適的存儲引擎: InnoDB
除非你的數據表使用來做僅僅讀或者全文檢索 (相信如今提到全文檢索,沒人會用 MYSQL 了)。你應該默認選擇 InnoDB 。
你自己在測試的時候可能會發現 MyISAM 比 InnoDB 速度快。這是由于: MyISAM 僅僅緩存索引,而 InnoDB 緩存數據和索引,MyISAM 不支持事務。可是 假設你使用 innodb_flush_log_at_trx_commit = 2 能夠獲得接近的讀取性能 (相差百倍) 。
1.1 怎樣將現有的 MyISAM 數據庫轉換為 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]?<p><strong><span style="font-size: 16px;">1.2 為每一個表分別創建 InnoDB FILE:</span></strong><strong><span style="font-size: 16px;"></span></strong><br></p><pre class="brush:sql;toolbar:false">innodb_file_per_table=1
這樣能夠保證 ibdata1 文件不會過大。失去控制。尤其是在運行 mysqlcheck -o –all-databases 的時候。
2. 保證從內存中讀取數據。講數據保存在內存中
2.1 足夠大的 innodb_buffer_pool_size
推薦將數據全然保存在 innodb_buffer_pool_size ,即按存儲量規劃 innodb_buffer_pool_size 的容量。這樣你能夠全然從內存中讀取數據。最大限度降低磁盤操作。
2.1.1 怎樣確定 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 命令,查看硬盤的操作。
2.1.2 server上是否有足夠內存用來規劃
運行 echo 1 > /proc/sys/vm/drop_caches 清除操作系統的文件緩存。能夠看到真正的內存使用量。
2.2 數據預熱
默認情況,僅僅有某條數據被讀取一次,才會緩存在 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/SelectQueriesToLoad.sql
3. 每次重新啟動數據庫,或者整庫備份前須要預熱的時候運行:
mysql?-uroot??/dev/null?2>&1
2.3 不要讓數據存到 SWAP 中
假設是專用 MYSQL server。能夠禁用 SWAP,假設是共享server,確定 innodb_buffer_pool_size 足夠大。或者使用固定的內存空間做緩存,使用 memlock 指令。
3. 定期優化重建數據庫
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;
4. 降低磁盤寫入操作
4.1 使用足夠大的寫入緩存 innodb_log_file_size
可是須要注意假設用 1G 的 innodb_log_file_size 。假如server當機。須要 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 則每次改動寫入磁盤
innodb_flush_log_at_trx_commit = 0/2 每秒寫入磁盤
假設你的應用不涉及非常高的安全性 (金融系統),或者基礎架構足夠安全,或者 事務都非常小,都能夠用 0 或者 2 來減少磁盤操作。
4.3 避免雙寫入緩沖
innodb_flush_method=O_DIRECT
5. 提高磁盤讀寫速度
RAID0 尤其是在使用 EC2 這樣的虛擬磁盤 (EBS) 的時候,使用軟 RAID0 很重要。
6. 充分使用索引
6.1 查看現有表結構和索引
SHOW?CREATE?TABLE?db1.tb1/G
6.2 加入必要的索引
索引是提高查詢速度的唯一方法。比方搜索引擎用的倒排索引是一樣的原理。
索引的加入須要依據查詢來確定。比方通過慢查詢日志或者查詢日志,或者通過 EXPLAIN 命令分析查詢。
ADD?UNIQUE?INDEX ADD?INDEX
6.2.1 比方,優化用戶驗證表:
加入索引
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
6.2.2 使用自己主動加索引的框架或者自己主動拆分表結構的框架
比方。Rails 這種框架。會自己主動加入索引。Drupal 這種框架會自己主動拆分表結構。
會在你開發的初期指明正確的方向。所以,經驗不太豐富的人一開始就追求從 0 開始構建,實際是不好的做法。
7. 分析查詢日志和慢查詢日志
記錄全部查詢。這在用 ORM 系統或者生成查詢語句的系統非常實用。
log=/var/log/mysql.log
注意不要在生產環境用。否則會占滿你的磁盤空間。
記錄運行時間超過 1 秒的查詢:
long_query_time=1 log-slow-queries=/var/log/mysql/log-slow-queries.log
8. 激進的方法。使用內存磁盤
如今基礎設施的可靠性已經非常高了,比方 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
9. 用 nosql 的方式使用 MYSQL
B-TREE 仍然是最高效的索引之中的一個,全部 MYSQL 仍然不會過時。
用 HandlerSocket 跳過 MYSQL 的 SQL 解析層。MYSQL 就真正變成了 NOSQL。
10. 其它
●單條查詢最后添加 LIMIT 1,停止全表掃描。
●將非”索引”數據分離,比方將大篇文章分離存儲,不影響其它自己主動查詢。
●不用 MYSQL 內置的函數。由于內置函數不會建立查詢緩存。
●php 的建立連接速度很快,全部能夠不用連接池。否則可能會造成超過連接數。當然不用連接池 PHP 程序也可能將
●連接數占滿比方用了 @ignore_user_abort(TRUE);
●使用 IP 而不是域名做數據庫路徑。避免 DNS 解析問題