MySQL 調(diào)優(yōu)和使用必讀

作者:Bruce Dou
原文地址:https://blog.eood.cn/mysql

MYSQL 應(yīng)該是最流行了 WEB 后端數(shù)據(jù)庫。WEB 開發(fā)語言最近發(fā)展很快完慧,PHP, Ruby, Python, Java 各有特點(diǎn)仰禀,雖然 NOSQL 最近越來越多的被提到甜攀,但是相信大部分架構(gòu)師還是會(huì)選擇 MYSQL 來做數(shù)據(jù)存儲(chǔ)。

MYSQL 如此方便和穩(wěn)定阱持,以至于我們?cè)陂_發(fā) WEB 程序的時(shí)候很少想到它夭拌。即使想到優(yōu)化也是程序級(jí)別的,比如衷咽,不要寫過于消耗資源的 SQL 語句鸽扁。但是除此之外,在整個(gè)系統(tǒng)上仍然有很多可以優(yōu)化的地方镶骗。

  1. 選擇合適的存儲(chǔ)引擎: INNODB
    --
    除非你的數(shù)據(jù)表使用來做只讀或者全文檢索 (相信現(xiàn)在提到全文檢索桶现,沒人會(huì)用 MYSQL 了),你應(yīng)該默認(rèn)選擇 INNODB 鼎姊。

你自己在測試的時(shí)候可能會(huì)發(fā)現(xiàn) MYISAM 比 INNODB 速度快骡和,這是因?yàn)椋?MYISAM 只緩存索引相赁,而 INNODB 緩存數(shù)據(jù)和索引,MYISAM 不支持事務(wù)即横。但是 如果你使用 **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 為每個(gè)表分別創(chuàng)建 INNODB FILE:

innodb_file_per_table=1

這樣可以保證 ibdata1 文件不會(huì)過大,失去控制东囚。尤其是在執(zhí)行 mysqlcheck -o –all-databases 的時(shí)候跺嗽。

  1. 保證從內(nèi)存中讀取數(shù)據(jù),講數(shù)據(jù)保存在內(nèi)存中
    --
    2.1 足夠大的 innodb_buffer_pool_size

推薦將數(shù)據(jù)完全保存在 innodb_buffer_pool_size 页藻,即按存儲(chǔ)量規(guī)劃 innodb_buffer_pool_size 的容量桨嫁。這樣你可以完全從內(nèi)存中讀取數(shù)據(jù),最大限度減少磁盤操作份帐。

2.1.1 如何確定 innodb_buffer_pool_size 足夠大璃吧,數(shù)據(jù)是從內(nèi)存讀取而不是硬盤?

方法 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)

發(fā)現(xiàn) Innodb_buffer_pool_pages_free為 0废境,則說明 buffer pool 已經(jīng)被用光畜挨,需要增大 innodb_buffer_pool_size

INNODB 的其他幾個(gè)參數(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 服務(wù)器上是否有足夠內(nèi)存用來規(guī)劃

執(zhí)行 echo 1 > /proc/sys/vm/drop_caches 清除操作系統(tǒng)的文件緩存巴元,可以看到真正的內(nèi)存使用量。

2.2 數(shù)據(jù)預(yù)熱

默認(rèn)情況驮宴,只有某條數(shù)據(jù)被讀取一次逮刨,才會(huì)緩存在 innodb_buffer_pool。所以堵泽,數(shù)據(jù)庫剛剛啟動(dòng)修己,需要進(jìn)行數(shù)據(jù)預(yù)熱,將磁盤上的所有數(shù)據(jù)緩存到內(nèi)存中迎罗。數(shù)據(jù)預(yù)熱可以提高讀取速度睬愤。

對(duì)于 InnoDB 數(shù)據(jù)庫,可以用以下方法纹安,進(jìn)行數(shù)據(jù)預(yù)熱:
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ù)庫尤辱,或者整庫備份前需要預(yù)熱的時(shí)候執(zhí)行:

mysql -uroot < /root/SelectQueriesToLoad.sql > /dev/null 2>&1

2.3 不要讓數(shù)據(jù)存到 SWAP 中

如果是專用 MYSQL 服務(wù)器,可以禁用 SWAP钻蔑,如果是共享服務(wù)器,確定 innodb_buffer_pool_size 足夠大奸鸯∵湫Γ或者使用固定的內(nèi)存空間做緩存,使用 memlock 指令娄涩。

  1. 定期優(yōu)化重建數(shù)據(jù)庫
    --
    mysqlcheck -o –all-databases 會(huì)讓 ibdata1 不斷增大窗怒,真正的優(yōu)化只有重建數(shù)據(jù)表結(jié)構(gòu):
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;
  1. 減少磁盤寫入操作
    --

4.1 使用足夠大的寫入緩存

innodb_log_file_size

但是需要注意如果用 1G 的 innodb_log_file_size映跟,假如服務(wù)器當(dāng)機(jī),需要 10 分鐘來恢復(fù)扬虚。

推薦 innodb_log_file_size = 0.25 innodb_buffer_pool_size

4.2 innodb_flush_log_at_trx_commit

這個(gè)選項(xiàng)和寫磁盤操作密切相關(guān):

  • innodb_flush_log_at_trx_commit = 1 則每次修改寫入磁盤
  • innodb_flush_log_at_trx_commit = 0/2 每秒寫入磁盤

如果你的應(yīng)用不涉及很高的安全性 (金融系統(tǒng))努隙,或者基礎(chǔ)架構(gòu)足夠安全,或者事務(wù)都很小辜昵,都可以用 0 或者 2 來降低磁盤操作荸镊。

4.3 避免雙寫入緩沖

innodb_flush_method=O_DIRECT
  1. 提高磁盤讀寫速度
    --

RAID0 尤其是在使用 EC2 這種虛擬磁盤 (EBS) 的時(shí)候,使用軟 RAID0 非常重要堪置。

  1. 充分使用索引
    --

6.1 查看現(xiàn)有表結(jié)構(gòu)和索引

SHOW CREATE TABLE db1.tb1\G

6.2 添加必要的索引

索引是提高查詢速度的唯一方法躬存,比如搜索引擎用的倒排索引是一樣的原理。索引的添加需要根據(jù)查詢來確定舀锨,比如通過慢查詢?nèi)罩净蛘卟樵內(nèi)罩?或者通過 EXPLAIN 命令分析查詢岭洲。

ADD UNIQUE INDEX
ADD INDEX

6.2.1 比如,優(yōu)化用戶驗(yàn)證表:

添加索引

ALTER TABLE users ADD UNIQUE INDEX username_ndx (username);
ALTER TABLE users ADD UNIQUE INDEX username_password_ndx (username,password);

每次重啟服務(wù)器進(jìn)行數(shù)據(jù)預(yù)熱

echo “select username,password from users;” > /var/lib/mysql/upcache.sql

添加啟動(dòng)腳本到 my.cnf

[mysqld]
init-file=/var/lib/mysql/upcache.sql

6.2.2 使用自動(dòng)加索引的框架或者自動(dòng)拆分表結(jié)構(gòu)的框架

比如坎匿,Rails 這樣的框架盾剩,會(huì)自動(dòng)添加索引,Drupal 這樣的框架會(huì)自動(dòng)拆分表結(jié)構(gòu)替蔬。會(huì)在你開發(fā)的初期指明正確的方向告私。所以,經(jīng)驗(yàn)不太豐富的人一開始就追求從 0 開始構(gòu)建进栽,實(shí)際是不好的做法德挣。

  1. 分析查詢?nèi)罩竞吐樵內(nèi)罩?br> --

記錄所有查詢,這在用 ORM 系統(tǒng)或者生成查詢語句的系統(tǒng)很有用快毛。log=/var/log/mysql.log注意不要在生產(chǎn)環(huán)境用格嗅,否則會(huì)占滿你的磁盤空間。

記錄執(zhí)行時(shí)間超過 1 秒的查詢

long_query_time=1
log-slow-queries=/var/log/mysql/log-slow-queries.log
  1. 激進(jìn)的方法唠帝,使用內(nèi)存磁盤
    --

現(xiàn)在基礎(chǔ)設(shè)施的可靠性已經(jīng)非常高了屯掖,比如 EC2 幾乎不用擔(dān)心服務(wù)器硬件當(dāng)機(jī)。而且內(nèi)存實(shí)在是便宜襟衰,很容易買到幾十G內(nèi)存的服務(wù)器贴铜,可以用內(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
  1. 用 NOSQL 的方式使用 MYSQL
    --

B-TREE 仍然是最高效的索引之一绍坝,所有 MYSQL 仍然不會(huì)過時(shí)。
用 HandlerSocket 跳過 MYSQL 的 SQL 解析層苔悦,MYSQL 就真正變成了 NOSQL轩褐。

  1. 其他
    --
  • 單條查詢最后增加 LIMIT 1,停止全表掃描玖详。
  • 將非”索引”數(shù)據(jù)分離把介,比如將大篇文章分離存儲(chǔ)勤讽,不影響其他自動(dòng)查詢。
  • 不用 MYSQL 內(nèi)置的函數(shù)拗踢,因?yàn)閮?nèi)置函數(shù)不會(huì)建立查詢緩存脚牍。
  • PHP 的建立連接速度非常快巢墅,所有可以不用連接池诸狭,否則可能會(huì)造成超過連接數(shù)。當(dāng)然不用連接池 PHP 程序也可能將連接數(shù)占滿比如用了 @ignore_user_abort(TRUE);
  • 使用 IP 而不是域名做數(shù)據(jù)庫路徑砂缩,避免 DNS 解析問題作谚。
  1. 結(jié)束
    --
    你會(huì)發(fā)現(xiàn)優(yōu)化后,數(shù)據(jù)庫的性能提高幾倍到幾百倍庵芭。所以 MYSQL 基本還是可以適用大部分場景的應(yīng)用的妹懒。優(yōu)化現(xiàn)有系統(tǒng)的成本比系統(tǒng)重構(gòu)或者遷移到 NOSQL 低很多。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末双吆,一起剝皮案震驚了整個(gè)濱河市眨唬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌好乐,老刑警劉巖匾竿,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蔚万,居然都是意外死亡岭妖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門反璃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昵慌,“玉大人,你說我怎么就攤上這事淮蜈≌剩” “怎么了?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵梧田,是天一觀的道長淳蔼。 經(jīng)常有香客問我,道長裁眯,這世上最難降的妖魔是什么鹉梨? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮穿稳,結(jié)果婚禮上存皂,老公的妹妹穿的比我還像新娘。我一直安慰自己司草,他們只是感情好艰垂,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著埋虹,像睡著了一般猜憎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上搔课,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天胰柑,我揣著相機(jī)與錄音,去河邊找鬼爬泥。 笑死柬讨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的袍啡。 我是一名探鬼主播踩官,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼境输!你這毒婦竟也來了蔗牡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤嗅剖,失蹤者是張志新(化名)和其女友劉穎辩越,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體信粮,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黔攒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了强缘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片督惰。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖欺旧,靈堂內(nèi)的尸體忽然破棺而出姑丑,到底是詐尸還是另有隱情,我是刑警寧澤辞友,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布栅哀,位于F島的核電站,受9級(jí)特大地震影響称龙,放射性物質(zhì)發(fā)生泄漏留拾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一鲫尊、第九天 我趴在偏房一處隱蔽的房頂上張望痴柔。 院中可真熱鬧,春花似錦疫向、人聲如沸咳蔚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谈火。三九已至侈询,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間糯耍,已是汗流浹背扔字。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留温技,地道東北人革为。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像舵鳞,于是被迫代替她去往敵國和親震檩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容