Mysql數(shù)據(jù)庫調(diào)優(yōu)和性能優(yōu)化21條最佳實踐

MySQL性能優(yōu)化的21個最佳實踐

TechTarget中國原創(chuàng)內(nèi)容,原文鏈接:http://www.searchdatabase.com.cn/showcontent_38045.htm

????? 今天捞蛋,數(shù)據(jù)庫的操作越來越成為整個應用的性能瓶頸了玻孟,這點對于Web應用尤其明顯夺姑。關于數(shù)據(jù)庫的性能忍坷,這并不只是DBA才需要擔心的事蛹锰,而這更是我們程序員需要去關注的事情深胳。當我們?nèi)ピO計數(shù)據(jù)庫表結(jié)構(gòu),對操作數(shù)據(jù)庫時(尤其是查表時的SQL語句)铜犬,我們都需要注意數(shù)據(jù)操作的性能舞终。這里,我們不會講過多的SQL語句的優(yōu)化癣猾,而只是針對MySQL這一Web應用最多的數(shù)據(jù)庫敛劝。希望下面的這些優(yōu)化技巧對你有用。

1. 為查詢緩存優(yōu)化你的查詢

大多數(shù)的MySQL服務器都開啟了查詢緩存纷宇。這是提高性最有效的方法之一夸盟,而且這是被MySQL的數(shù)據(jù)庫引擎處理的。當有很多相同的查詢被執(zhí)行了多次的時候像捶,這些查詢結(jié)果會被放到一個緩存中上陕,這樣,后續(xù)的相同的查詢就不用操作表而直接訪問緩存結(jié)果了拓春。

這里最主要的問題是释簿,對于程序員來說,這個事情是很容易被忽略的硼莽。因為庶溶,我們某些查詢語句會讓MySQL不使用緩存。請看下面的示例:

上面兩條SQL語句的差別就是 CURDATE() ,MySQL的查詢緩存對這個函數(shù)不起作用偏螺。所以行疏,像 NOW() 和 RAND()

或是其它的諸如此類的SQL函數(shù)都不會開啟查詢緩存,因為這些函數(shù)的返回是會不定的易變的砖茸。所以隘擎,你所需要的就是用一個變量來代替MySQL的函數(shù),從而開啟緩存凉夯。

2. EXPLAIN 你的 SELECT 查詢

使用 EXPLAIN 關鍵字可以讓你知道MySQL是如何處理你的SQL語句的货葬。這可以幫你分析你的查詢語句或是表結(jié)構(gòu)的性能瓶頸。

EXPLAIN 的查詢結(jié)果還會告訴你你的索引主鍵被如何利用的劲够,你的數(shù)據(jù)表是如何被搜索和排序的……等等震桶,等等。

挑一個你的SELECT語句(推薦挑選那個最復雜的征绎,有多表聯(lián)接的)蹲姐,把關鍵字EXPLAIN加到前面。你可以使用phpmyadmin來做這個事人柿。然后柴墩,你會看到一張表格。下面的這個示例中凫岖,我們忘記加上了group_id索引江咳,并且有表聯(lián)接:


當我們?yōu)?group_id 字段加上索引后:


我們可以看到,前一個結(jié)果顯示搜索了 7883 行哥放,而后一個只是搜索了兩個表的 9 和 16 行歼指。查看rows列可以讓我們找到潛在的性能問題。

3. 當只要一行數(shù)據(jù)時使用 LIMIT 1

當你查詢表的有些時候甥雕,你已經(jīng)知道結(jié)果只會有一條結(jié)果踩身,但因為你可能需要去fetch游標,或是你也許會去檢查返回的記錄數(shù)社露。

在這種情況下挟阻,加上 LIMIT 1 可以增加性能。這樣一樣峭弟,MySQL數(shù)據(jù)庫引擎會在找到一條數(shù)據(jù)后停止搜索赁濒,而不是繼續(xù)往后查少下一條符合記錄的數(shù)據(jù)。

下面的示例孟害,只是為了找一下是否有“中國”的用戶,很明顯挪拟,后面的會比前面的更有效率挨务。(請注意,第一條中是Select *,第二條是Select 1)


4. 為搜索字段建索引

索引并不一定就是給主鍵或是唯一的字段谎柄。如果在你的表中丁侄,有某個字段你總要會經(jīng)常用來做搜索,那么朝巫,請為其建立索引吧鸿摇。


從上圖你可以看到那個搜索字串 “l(fā)ast_name LIKE ‘a(chǎn)%’”,一個是建了索引劈猿,一個是沒有索引拙吉,性能差了4倍左右。

另外揪荣,你應該也需要知道什么樣的搜索是不能使用正常的索引的筷黔。例如,當你需要在一篇大的文章中搜索一個詞時仗颈,如: “WHERE

post_content LIKE ‘%apple%’”佛舱,索引可能是沒有意義的。你可能需要使用MySQL全文索引

或是自己做一個索引(比如說:搜索關鍵詞或是Tag什么的)

5. 在Join表的時候使用相當類型的例挨决,并將其索引

如果你的應用程序有很多 JOIN 查詢请祖,你應該確認兩個表中Join的字段是被建過索引的。這樣脖祈,MySQL內(nèi)部會啟動為你優(yōu)化Join的SQL語句的機制肆捕。

而且,這些被用來Join的字段撒犀,應該是相同的類型的福压。例如:如果你要把 DECIMAL 字段和一個 INT 字段Join在一起,MySQL就無法使用它們的索引或舞。對于那些STRING類型荆姆,還需要有相同的字符集才行。(兩個表的字符集有可能不一樣)


6. 千萬不要 ORDER BY RAND()

想打亂返回的數(shù)據(jù)行?隨機挑一個數(shù)據(jù)?真不知道誰發(fā)明了這種用法映凳,但很多新手很喜歡這樣用胆筒。但你確不了解這樣做有多么可怕的性能問題。

如果你真的想把返回的數(shù)據(jù)行打亂了诈豌,你有N種方法可以達到這個目的仆救。這樣使用只讓你的數(shù)據(jù)庫的性能呈指數(shù)級的下降。這里的問題是:MySQL會不得不去執(zhí)行RAND()函數(shù)(很耗CPU時間)矫渔,而且這是為了每一行記錄去記行彤蔽,然后再對其排序。就算是你用了Limit1也無濟于事(因為要排序)

下面的示例是隨機挑一條記錄


7. 避免 SELECT *

從數(shù)據(jù)庫里讀出越多的數(shù)據(jù)庙洼,那么查詢就會變得越慢顿痪。并且镊辕,如果你的數(shù)據(jù)庫服務器和WEB服務器是兩臺獨立的服務器的話,這還會增加網(wǎng)絡傳輸?shù)呢撦d蚁袭。

所以征懈,你應該養(yǎng)成一個需要什么就取什么的好的習慣。


8. 永遠為每張表設置一個ID

我們應該為數(shù)據(jù)庫里的每張表都設置一個ID做為其主鍵揩悄,而且最好的是一個INT型的(推薦使用UNSIGNED)卖哎,并設置上自動增加的AUTO_INCREMENT標志。

就算是你 users 表有一個主鍵叫 “email”的字段删性,你也別讓它成為主鍵亏娜。使用 VARCHAR 類型來當主鍵會使用得性能下降。另外镇匀,在你的程序中照藻,你應該使用表的ID來構(gòu)造你的數(shù)據(jù)結(jié)構(gòu)

而且汗侵,在MySQL數(shù)據(jù)引擎下幸缕,還有一些操作需要使用主鍵,在這些情況下晰韵,主鍵的性能和設置變得非常重要发乔,比如,集群雪猪,分區(qū)……

在這里栏尚,只有一個情況是例外,那就是“關聯(lián)表”的“外鍵”只恨,也就是說译仗,這個表的主鍵,通過若干個別的表的主鍵構(gòu)成官觅。我們把這個情況叫做“外鍵”纵菌。比如:有一個“學生表”有學生的ID,有一個“課程表”有課程ID休涤,那么咱圆,“成績表”就是“關聯(lián)表”了,其關聯(lián)了學生表和課程表功氨,在成績表中序苏,學生ID和課程ID叫“外鍵”其共同組成主鍵。

9. 使用 ENUM 而不是 VARCHAR

ENUM 類型是非辰萜啵快和緊湊的忱详。在實際上,其保存的是 TINYINT跺涤,但其外表上顯示為字符串匈睁。這樣一來管钳,用這個字段來做一些選項列表變得相當?shù)耐昝馈?/p>

如果你有一個字段,比如“性別”软舌,“國家”,“民族”牛曹,“狀態(tài)”或“部門”佛点,你知道這些字段的取值是有限而且固定的,那么黎比,你應該使用 ENUM 而不是 VARCHAR超营。

MySQL也有一個“建議”(見第十條)告訴你怎么去重新組織你的表結(jié)構(gòu)。當你有一個 VARCHAR 字段時阅虫,這個建議會告訴你把其改成 ENUM 類型演闭。使用 PROCEDURE ANALYSE() 你可以得到相關的建議。

10. 從 PROCEDURE ANALYSE() 取得建議

PROCEDURE ANALYSE() 會讓 MySQL 幫你去分析你的字段和其實際的數(shù)據(jù)颓帝,并會給你一些有用的建議米碰。只有表中有實際的數(shù)據(jù),這些建議才會變得有用购城,因為要做一些大的決定是需要有數(shù)據(jù)作為基礎的吕座。

例如,如果你創(chuàng)建了一個 INT 字段作為你的主鍵瘪板,然而并沒有太多的數(shù)據(jù)吴趴,那么,PROCEDURE

ANALYSE()會建議你把這個字段的類型改成 MEDIUMINT 侮攀÷嘀Γ或是你使用了一個 VARCHAR

字段,因為數(shù)據(jù)不多兰英,你可能會得到一個讓你把它改成 ENUM 的建議撇叁。這些建議,都是可能因為數(shù)據(jù)不夠多箭昵,所以決策做得就不夠準税朴。

在phpmyadmin里,你可以在查看表時家制,點擊 “Propose table structure” 來查看這些建議


一定要注意正林,這些只是建議,只有當你的表里的數(shù)據(jù)越來越多時颤殴,這些建議才會變得準確觅廓。一定要記住,你才是最終做決定的人涵但。

11. 盡可能的使用 NOT NULL

除非你有一個很特別的原因去使用 NULL 值杈绸,你應該總是讓你的字段保持 NOT NULL帖蔓。這看起來好像有點爭議,請往下看瞳脓。

首先塑娇,問問你自己“Empty”和“NULL”有多大的區(qū)別(如果是INT,那就是0和NULL)?如果你覺得它們之間沒有什么區(qū)別劫侧,那么你就不要使用NULL埋酬。(你知道嗎?在 Oracle 里,NULL 和 Empty 的字符串是一樣的!)

不要以為 NULL 不需要空間烧栋,其需要額外的空間写妥,并且,在你進行比較的時候审姓,你的程序會更復雜珍特。 當然,這里并不是說你就不能使用NULL了魔吐,現(xiàn)實情況是很復雜的扎筒,依然會有些情況下,你需要使用NULL值画畅。

12. Prepared Statements

Prepared Statements很像存儲過程砸琅,是一種運行在后臺的SQL語句集合,我們可以從使用 prepared statements 獲得很多好處轴踱,無論是性能問題還是安全問題症脂。

Prepared Statements

可以檢查一些你綁定好的變量,這樣可以保護你的程序不會受到“SQL注入式”攻擊淫僻。當然诱篷,你也可以手動地檢查你的這些變量,然而雳灵,手動的檢查容易出問題棕所,而且很經(jīng)常會被程序員忘了。當我們使用一些framework或是ORM的時候悯辙,這樣的問題會好一些琳省。

在性能方面,當一個相同的查詢被使用多次的時候躲撰,這會為你帶來可觀的性能優(yōu)勢针贬。你可以給這些Prepared Statements定義一些參數(shù),而MySQL只會解析一次拢蛋。

雖然最新版本的MySQL在傳輸Prepared Statements是使用二進制形勢桦他,所以這會使得網(wǎng)絡傳輸非常有效率。

當然谆棱,也有一些情況下快压,我們需要避免使用Prepared Statements圆仔,因為其不支持查詢緩存。但據(jù)說版本5.1后支持了蔫劣。

PHP中要使用prepared statements坪郭,你可以查看其使用手冊:mysqli 擴展 或是使用數(shù)據(jù)庫抽象層,如: PDO.


13. 無緩沖的查詢

正常的情況下脉幢,當你在當你在你的腳本中執(zhí)行一個SQL語句的時候截粗,你的程序會停在那里直到?jīng)]這個SQL語句返回,然后你的程序再往下繼續(xù)執(zhí)行鸵隧。你可以使用無緩沖查詢來改變這個行為。

mysql_unbuffered_query()

發(fā)送一個SQL語句到MySQL而并不像mysql_query()一樣去自動fethch和緩存結(jié)果意推。這會相當節(jié)約很多可觀的內(nèi)存豆瘫,尤其是那些會產(chǎn)生大量結(jié)果的查詢語句,并且菊值,你不需要等到所有的結(jié)果都返回外驱,只需要第一行數(shù)據(jù)返回的時候,你就可以開始馬上開始工作于查詢結(jié)果了腻窒。

然而昵宇,這會有一些限制。因為你要么把所有行都讀走儿子,或是你要在進行下一次的查詢前調(diào)用 mysql_free_result()

清除結(jié)果瓦哎。而且, mysql_num_rows() 或 mysql_data_seek()

將無法使用柔逼。所以蒋譬,是否使用無緩沖的查詢你需要仔細考慮。

14. 把IP地址存成 UNSIGNED INT

很多程序員都會創(chuàng)建一個 VARCHAR(15)

字段來存放字符串形式的IP而不是整形的IP愉适。如果你用整形來存放犯助,只需要4個字節(jié),并且你可以有定長的字段维咸。而且剂买,這會為你帶來查詢上的優(yōu)勢,尤其是當你需要使用這樣的WHERE條件:IP

between ip1 and ip2癌蓖。

我們必需要使用UNSIGNED INT瞬哼,因為 IP地址會使用整個32位的無符號整形。

而你的查詢费坊,你可以使用 INET_ATON() 來把一個字符串IP轉(zhuǎn)成一個整形倒槐,并使用 INET_NTOA() 把一個整形轉(zhuǎn)成一個字符串IP。在PHP中附井,也有這樣的函數(shù) ip2long() 和 long2ip()讨越。


15. 固定長度的表會更快

如果表中的所有字段都是“固定長度”的两残,整個表會被認為是 “static” 或 “fixed-length”。

例如把跨,表中沒有如下類型的字段:

VARCHAR人弓,TEXT,BLOB着逐。只要你包括了其中一個這些字段崔赌,那么這個表就不是“固定長度靜態(tài)表”了,這樣耸别,MySQL

引擎會用另一種方法來處理健芭。

固定長度的表會提高性能,因為MySQL搜尋得會更快一些秀姐,因為這些固定的長度是很容易計算下一個數(shù)據(jù)的偏移量的慈迈,所以讀取的自然也會很快。而如果字段不是定長的省有,那么痒留,每一次要找下一條的話,需要程序找到主鍵蠢沿。

并且伸头,固定長度的表也更容易被緩存和重建。不過舷蟀,唯一的副作用是犀呼,固定長度的字段會浪費一些空間什猖,因為定長的字段無論你用不用矾削,他都是要分配那么多的空間肩刃。

使用“垂直分割”技術(shù)(見下一條),你可以分割你的表成為兩個一個是定長的速缨,一個則是不定長的锌妻。

16. 垂直分割

“垂直分割”是一種把數(shù)據(jù)庫中的表按列變成幾張表的方法,這樣可以降低表的復雜度和字段的數(shù)目旬牲,從而達到優(yōu)化的目的仿粹。(以前,在銀行做過項目原茅,見過一張表有100多個字段吭历,很恐怖)

示例一:在Users表中有一個字段是家庭地址,這個字段是可選字段擂橘,相比起晌区,而且你在數(shù)據(jù)庫操作的時候除了個人信息外,你并不需要經(jīng)常讀取或是改寫這個字段。那么朗若,為什么不把他放到另外一張表中呢?

這樣會讓你的表有更好的性能恼五,大家想想是不是,大量的時候哭懈,我對于用戶表來說灾馒,只有用戶ID,用戶名遣总,口令睬罗,用戶角色等會被經(jīng)常使用。小一點的表總是會有好的性能旭斥。

示例二: 你有一個叫 “l(fā)ast_login”

的字段容达,它會在每次用戶登錄時被更新。但是垂券,每次更新時會導致該表的查詢緩存被清空董饰。所以,你可以把這個字段放到另一個表中圆米,這樣就不會影響你對用戶ID,用戶名啄栓,用戶角色的不停地讀取了娄帖,因為查詢緩存會幫你增加很多性能。

另外昙楚,你需要注意的是近速,這些被分出去的字段所形成的表,你不會經(jīng)常性地去Join他們堪旧,不然的話削葱,這樣的性能會比不分割時還要差,而且淳梦,會是極數(shù)級的下降析砸。

17. 拆分大的 DELETE 或 INSERT 語句

如果你需要在一個在線的網(wǎng)站上去執(zhí)行一個大的 DELETE 或 INSERT 查詢,你需要非常小心爆袍,要避免你的操作讓你的整個網(wǎng)站停止相應首繁。因為這兩個操作是會鎖表的,表一鎖住了陨囊,別的操作都進不來了弦疮。

Apache 會有很多的子進程或線程。所以蜘醋,其工作起來相當有效率胁塞,而我們的服務器也不希望有太多的子進程,線程和數(shù)據(jù)庫鏈接,這是極大的占服務器資源的事情啸罢,尤其是內(nèi)存编检。

如果你把你的表鎖上一段時間,比如30秒鐘伺糠,那么對于一個有很高訪問量的站點來說蒙谓,這30秒所積累的訪問進程/線程,數(shù)據(jù)庫鏈接训桶,打開的文件數(shù)累驮,可能不僅僅會讓你泊WEB服務Crash,還可能會讓你的整臺服務器馬上掛了舵揭。

所以谤专,如果你有一個大的處理,你定你一定把其拆分午绳,使用 LIMIT 條件是一個好的方法置侍。下面是一個示例:


18. 越小的列會越快

對于大多數(shù)的數(shù)據(jù)庫引擎來說,硬盤操作可能是最重大的瓶頸拦焚。所以蜡坊,把你的數(shù)據(jù)變得緊湊會對這種情況非常有幫助,因為這減少了對硬盤的訪問赎败。

參看 MySQL 的文檔 Storage Requirements 查看所有的數(shù)據(jù)類型秕衙。

如果一個表只會有幾列罷了(比如說字典表,配置表)僵刮,那么据忘,我們就沒有理由使用 INT 來做主鍵,使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 會更經(jīng)濟一些搞糕。如果你不需要記錄時間勇吊,使用 DATE 要比 DATETIME 好得多。

當然窍仰,你也需要留夠足夠的擴展空間汉规,不然,你日后來干這個事驹吮,你會死的很難看鲫忍,參看Slashdot的例子(2009年11月06日),一個簡單的ALTER TABLE語句花了3個多小時钥屈,因為里面有一千六百萬條數(shù)據(jù)悟民。

19. 選擇正確的存儲引擎

在 MySQL 中有兩個存儲引擎 MyISAM 和 InnoDB,每個引擎都有利有弊篷就∩淇鳎酷殼以前文章《MySQL: InnoDB 還是 MyISAM?》討論和這個事情近忙。

MyISAM

適合于一些需要大量查詢的應用,但其對于有大量寫操作并不是很好智润。甚至你只是需要update一個字段及舍,整個表都會被鎖起來,而別的進程窟绷,就算是讀進程都無法操作直到讀操作完成锯玛。另外,MyISAM

對于 SELECT COUNT(*) 這類的計算是超快無比的兼蜈。

InnoDB 的趨勢會是一個非常復雜的存儲引擎攘残,對于一些小的應用,它會比 MyISAM 還慢为狸。他是它支持“行鎖” 歼郭,于是在寫操作比較多的時候,會更優(yōu)秀辐棒。并且病曾,他還支持更多的高級應用,比如:事務漾根。

下面是MySQL的手冊

target=”_blank”MyISAM Storage Engine

InnoDB Storage Engine

20. 使用一個對象關系映射器(Object Relational Mapper)

使用 ORM (Object Relational Mapper)泰涂,你能夠獲得可靠的性能增漲。一個ORM可以做的所有事情辐怕,也能被手動的編寫出來逼蒙。但是,這需要一個高級專家秘蛇。

ORM 的最重要的是“Lazy Loading”,也就是說顶考,只有在需要的去取值的時候才會去真正的去做赁还。但你也需要小心這種機制的副作用,因為這很有可能會因為要去創(chuàng)建很多很多小的查詢反而會降低性能驹沿。

ORM 還可以把你的SQL語句打包成一個事務艘策,這會比單獨執(zhí)行他們快得多得多。

目前渊季,個人最喜歡的PHP的ORM是:Doctrine朋蔫。

21. 小心“永久鏈接”

“永久鏈接”的目的是用來減少重新創(chuàng)建MySQL鏈接的次數(shù)。當一個鏈接被創(chuàng)建了却汉,它會永遠處在連接的狀態(tài)驯妄,就算是數(shù)據(jù)庫操作已經(jīng)結(jié)束了。而且合砂,自從我們的Apache開始重用它的子進程后——也就是說青扔,下一次的HTTP請求會重用Apache的子進程,并重用相同的

MySQL 鏈接。

PHP手冊:mysql_pconnect()

在理論上來說微猖,這聽起來非常的不錯谈息。但是從個人經(jīng)驗(也是大多數(shù)人的)上來說,這個功能制造出來的麻煩事更多凛剥。因為侠仇,你只有有限的鏈接數(shù),內(nèi)存問題犁珠,文件句柄數(shù)逻炊,等等。

而且盲憎,Apache 運行在極端并行的環(huán)境中嗅骄,會創(chuàng)建很多很多的了進程。這就是為什么這種“永久鏈接”的機制工作地不好的原因饼疙。在你決定要使用“永久鏈接”之前溺森,你需要好好地考慮一下你的整個系統(tǒng)的架構(gòu)。

TechTarget中國原創(chuàng)內(nèi)容窑眯,原文鏈接:http://www.searchdatabase.com.cn/showcontent_38045.htm




本文來源于網(wǎng)絡緊供學習

作者:andyao

原文link: http://andyao.iteye.com/admin/show/144033

轉(zhuǎn)載請留名

1. 簡介

在Web應用程序體系架構(gòu)中屏积,數(shù)據(jù)持久層(通常是一個關系數(shù)據(jù)庫)是關鍵的核心部分,它對系統(tǒng)的性能有非常重要的影響磅甩。MySQL是目前使用最多的開源數(shù)據(jù)庫炊林,但是MySQL數(shù)據(jù)庫的默認設置性能非常的差,僅僅是一個玩具數(shù)據(jù)庫卷要。因此在產(chǎn)品中使用MySQL數(shù)據(jù)庫必須進行必要的優(yōu)化渣聚。

優(yōu)化是一個復雜的任務,本文描述MySQL相關的數(shù)據(jù)庫設計和查詢優(yōu)化僧叉,服務器端優(yōu)化奕枝,存儲引擎優(yōu)化。

2. 數(shù)據(jù)庫設計和查詢優(yōu)化

在MySQL Server性能調(diào)優(yōu)中瓶堕,首先要考慮的就是Database Schema設計隘道,這一點是非常重要的。一個糟糕的Schema設計即使在性能調(diào)優(yōu)的MySQL Server上運行郎笆,也會表現(xiàn)出很差的性能谭梗;和Schema相似,查詢語句的設計也會影響MySQL的性能宛蚓,應該避免寫出低效的SQL查詢激捏。這一節(jié)將詳細討論這兩方面的優(yōu)化。

2.1 Schema Design

Schema的優(yōu)化取決于將要運行什么樣的query凄吏,不同的query會有不同的Schema優(yōu)化方案缩幸。2.2節(jié)將介紹Query Design的優(yōu)化壹置。Schema設計同樣受到預期數(shù)據(jù)集大小的影響。Schema設計時主要考慮:標準化表谊,數(shù)據(jù)類型钞护,索引。

2.1.1 標準化

標準化是在數(shù)據(jù)庫中組織數(shù)據(jù)的過程爆办。其中包括难咕,根據(jù)設計規(guī)則創(chuàng)建表并在這些表間建立關系;通過取消冗余度與不一致相關性距辆,該設計規(guī)則可以同時保護數(shù)據(jù)并提高數(shù)據(jù)的靈活性余佃。通常數(shù)據(jù)庫標準化是讓數(shù)據(jù)庫設計符合某一級別的范式,通常滿足第三范式即可跨算。也有第四范式(也稱為 Boyce Codd范式爆土,BCNF))與第五范式存在,但是在實際設計中很少考慮诸蚕。忽視這些規(guī)則可能使得數(shù)據(jù)庫的設計不太完美步势,但這不應影響功能。

標準化的特點:

1) 所有的“對象”都在它自己的table中背犯,沒有冗余坏瘩。

2) 數(shù)據(jù)庫通常由E-R圖生成。

3) 簡潔漠魏,更新屬性通常只需要更新很少的記錄倔矾。

4) Join操作比較耗時。

5) Select柱锹,sort優(yōu)化措施比較少哪自。

6) 適用于OLTP應用。

非標準化的特點:

1) 在一張表中存儲很多數(shù)據(jù)禁熏,數(shù)據(jù)冗余壤巷。

2) 更新數(shù)據(jù)開銷很大,更新一個屬性可能會更新很多表匹层,很多記錄隙笆。

3) 在刪除數(shù)據(jù)是有可能丟失數(shù)據(jù)锌蓄。

4) Select升筏,order有很多優(yōu)化的選擇。

5) 適用于DSS應用瘸爽。

標準化和非標準化都有各自的優(yōu)缺點您访,通常在一個數(shù)據(jù)庫設計中可以混合使用,一部分表格標準化剪决,一部分表格保留一些冗余數(shù)據(jù):

1) 對OLTP使用標準化灵汪,對DSS使用非標準化

2) 使用物化視圖檀训。MySQL不直接支持該數(shù)據(jù)庫特性,但是可以用MyISAM表代替享言。

3) 冗余一些數(shù)據(jù)在表格中峻凫,例如將ref_id和name存在同一張表中。但是要注意更新問題览露。

4) 對于一些簡單的對象荧琼,直接使用value作為建。例如IP address等

5) Reference by PRIMARY/UNIQUE KEY差牛。MySQL可以優(yōu)化這種操作命锄,例如:

java 代碼

select city_name

from city,state

where state_id=state.id and state.code=‘CA’” converted to “select city_name from city where state_id=12

2.1.2 數(shù)據(jù)類型

最基本的優(yōu)化之一就是使表在磁盤上占據(jù)的空間盡可能小。這能帶來性能非常大的提升偏化,因為數(shù)據(jù)小脐恩,磁盤讀入較快,并且在查詢過程中表內(nèi)容被處理所占用的內(nèi)存更少侦讨。同時驶冒,在更小的列上建索引,索引也會占用更少的資源搭伤。

可以使用下面的技術(shù)可以使表的性能更好并且使存儲空間最兄辉酢:

1) 使用正確合適的類型,不要將數(shù)字存儲為字符串怜俐。

2) 盡可能地使用最有效(最小)的數(shù)據(jù)類型身堡。MySQL有很多節(jié)省磁盤空間和內(nèi)存的專業(yè)化類型。

3) 盡可能使用較小的整數(shù)類型使表更小拍鲤。例如贴谎,MEDIUMINT經(jīng)常比INT好一些,因為MEDIUMINT列使用的空間要少25%季稳。

4) 如果可能擅这,聲明列為NOT NULL。它使任何事情更快而且每列可以節(jié)省一位景鼠。注意如果在應用程序中確實需要NULL仲翎,應該毫無疑問使用它,只是避免 默認地在所有列上有它铛漓。

5) 對于MyISAM表溯香,如果沒有任何變長列(VARCHAR、TEXT或BLOB列)浓恶,使用固定尺寸的記錄格式玫坛。這比較快但是不幸地可能會浪費一些空間。即使你已經(jīng)用CREATE選項讓VARCHAR列ROW_FORMAT=fixed包晰,也可以提示想使用固定長度的行湿镀。

6) 使用sample character set炕吸,例如latin1。盡量少使用utf-8勉痴,因為utf-8占用的空間是latin1的3倍赫模。可以在不需要使用utf-8的字段上面使用latin1蒸矛,例如mail嘴瓤,url等。

2.1.3 索引

所有MySQL列類型可以被索引莉钙。對相關列使用索引是提高SELECT操作性能的最佳途徑廓脆。使用索引應該注意以下幾點:

1) MySQL只會使用前綴,例如key(a, b) …where b=5 將使用不到索引磁玉。

2) 要選擇性的使用索引停忿。在變化很少的列上使用索引并不是很好,例如性別列蚊伞。

3) 在Unique列上定義Unique index席赂。

4) 避免建立使用不到的索引。

5) 在Btree index中(InnoDB使用Btree)时迫,可以在需要排序的列上建立索引颅停。

6) 避免重復的索引。

7) 避免在已有索引的前綴上建立索引掠拳。例如:如果存在index(a癞揉,b)則去掉index(a)。

8) 控制單個索引的長度溺欧。使用key(name(8))在數(shù)據(jù)的前面幾個字符建立索引喊熟。

9) 越是短的鍵值越好,最好使用integer姐刁。

10) 在查詢中要使用到索引(使用explain查看)芥牌,可以減少讀磁盤的次數(shù),加速讀取數(shù)據(jù)聂使。

11) 相近的鍵值比隨機好壁拉。Auto_increment就比uuid好。

12) Optimize table可以壓縮和排序index柏靶,注意不要頻繁運行弃理。

13) Analyze table可以更新數(shù)據(jù)。

2.2 Designing queries

查詢語句的優(yōu)化是一個Case by case的問題宿礁,不同的sql有不同的優(yōu)化方案案铺,在這里我只列出一些通用的技巧蔬芥。

1) 在有index的情況下梆靖,盡量保證查詢使用了正確的index控汉。可以使用EXPLAIN select …查看結(jié)果返吻,分析查詢姑子。

2) 查詢時使用匹配的類型。例如select * from a where id=5测僵, 如果這里id是字符類型街佑,同時有index,這條查詢則使用不到index捍靠,會做全表掃描沐旨,速度會很慢。正確的應該是 … where id=”5” 榨婆,加上引號表明類型是字符磁携。

3) 使用--log-slow-queries –long-query-time=2查看查詢比較慢的語句。然后使用explain分析查詢良风,做出優(yōu)化谊迄。

3. 服務器端優(yōu)化3.1 MySQL安裝

MySQL有很多發(fā)行版本,最好使用MySQL AB發(fā)布的二進制版本烟央。也可以下載源代碼進行編譯安裝统诺,但是編譯器和類庫的一些bug可能會使編譯完成的MySQL存在潛在的問題。

如果安裝MySQL的服務器使用的是Intel公司的處理器疑俭,可以使用intel c++編譯的版本粮呢,在LinuxWorld2005的一篇PPT中提到,使用intel C++編譯器編譯的MySQL查詢速度比正常版本快30%左右钞艇。Intel c++編譯版本可以在MySQL官方網(wǎng)站下載鬼贱。

3.2 服務器設置優(yōu)化

MySQL默認的設置性能很差,所以要做一些參數(shù)的調(diào)整香璃。這一節(jié)介紹一些通用的參數(shù)調(diào)整这难,不涉及具體的存儲引擎(主要指MyISAM,InnoDB葡秒,相關優(yōu)化在4中介紹)姻乓。

--character-set:如果是單一語言使用簡單的character set例如latin1。盡量少用Utf-8眯牧,utf-8占用空間較多蹋岩。

--memlock:鎖定MySQL只能運行在內(nèi)存中,避免swapping学少,但是如果內(nèi)存不夠時有可能出現(xiàn)錯誤剪个。

--max_allowed_packet:要足夠大,以適應比較大的SQL查詢版确,對性能沒有太大影響扣囊,主要是避免出現(xiàn)packet錯誤乎折。

--max_connections:server允許的最大連接。太大的話會出現(xiàn)out of memory侵歇。

--table_cache:MySQL在同一時間保持打開的table的數(shù)量骂澄。打開table開銷比較大。一般設置為512惕虑。

--query_cache_size: 用于緩存查詢的內(nèi)存大小坟冲。

--datadir:mysql存放數(shù)據(jù)的根目錄,和安裝文件分開在不同的磁盤可以提高一點性能溃蔫。

4. 存儲引擎優(yōu)化

MySQL支持不同的存儲引擎健提,主要使用的有MyISAM和InnoDB。

4.1 MyISAM

MyISAM管理非事務表伟叛。它提供高速存儲和檢索矩桂,以及全文搜索能力。MyISAM在所有MySQL配置里被支持痪伦,它是默認的存儲引擎侄榴,除非配置MySQL默認使用另外一個引擎。

4.1.1 MyISAM特性

4.1.1.1 MyISAM Properties

1) 不支持事務网沾,宕機會破壞表

2) 使用較小的內(nèi)存和磁盤空間

3) 基于表的鎖癞蚕,并發(fā)更新數(shù)據(jù)會出現(xiàn)嚴重性能問題

4) MySQL只緩存Index,數(shù)據(jù)由OS緩存

4.1.1.2 Typical MyISAM usages

1) 日志系統(tǒng)

2) 只讀或者絕大部分是讀操作的應用

3) 全表掃描

4) 批量導入數(shù)據(jù)

5) 沒有事務的低并發(fā)讀/寫

4.1.2 MyISAM優(yōu)化要點

1) 聲明列為NOT NULL辉哥,可以減少磁盤存儲桦山。

2) 使用optimize table做碎片整理,回收空閑空間醋旦。注意僅僅在非常大的數(shù)據(jù)變化后運行恒水。

3) Deleting/updating/adding大量數(shù)據(jù)的時候禁止使用index。使用ALTER TABLE t DISABLE KEYS饲齐。

4) 設置myisam_max_[extra]_sort_file_size足夠大钉凌,可以顯著提高repair table的速度。

4.1.3 MyISAM Table Locks

1) 避免并發(fā)insert捂人,update御雕。

2) 可以使用insert delayed,但是有可能丟失數(shù)據(jù)滥搭。

3) 優(yōu)化查詢語句酸纲。

4) 水平分區(qū)。

5) 垂直分區(qū)瑟匆。

6) 如果都不起作用闽坡,使用InnoDB。

4.1.4 MyISAM Key Cache

1) 設置key_buffer_size variable。MyISAN最主要的cache設置疾嗅,用于緩存MyISAM表格的index數(shù)據(jù)外厂,該參數(shù)只對MyISAM有影響。通常在只使用MyISAM的Server中設置25-33%的內(nèi)存大小宪迟。

2) 可以使用幾個不同的Key Caches(對一些hot data)。

a) SET GLOBAL test.key_buffer_size=512*1024;

b) CACHE INDEX t1.i1, t2.i1, t3 IN test;

2) Preload index到Cache中可以提高查詢速度交惯。因為preloading index是順序的次泽,所以非常快席爽。

a) LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES意荤;

4.2 InnoDB

InnoDB給MySQL提供了具有提交,回滾和崩潰恢復能力的事務安全(ACID兼容)存儲引擎只锻。InnoDB提供row level lock玖像,并且也在SELECT語句提供一個Oracle風格一致的非鎖定讀。這些特色增加了多用戶部署和性能齐饮。沒有在InnoDB中擴大鎖定的需要捐寥,因為在InnoDB中row level lock適合非常小的空間。InnoDB也支持FOREIGN KEY約束祖驱。在SQL查詢中握恳,你可以自由地將InnoDB類型的表與其它MySQL的表的類型混合起來,甚至在同一個查詢中也可以混合捺僻。

InnoDB是為在處理巨大數(shù)據(jù)量時獲得最大性能而設計的乡洼。它的CPU使用效率非常高。

InnoDB存儲引擎已經(jīng)完全與MySQL服務器整合匕坯,InnoDB存儲引擎為在內(nèi)存中緩存數(shù)據(jù)和索引而維持它自己的緩沖池束昵。 InnoDB存儲它的表&索引在一個表空間中,表空間可以包含數(shù)個文件(或原始磁盤分區(qū))葛峻。這與MyISAM表不同锹雏,比如在MyISAM表中每個表被存在分離的文件中。InnoDB 表可以是任何大小术奖,即使在文件尺寸被限制為2GB的操作系統(tǒng)上逼侦。

許多需要高性能的大型數(shù)據(jù)庫站點上使用了InnoDB引擎。著名的Internet新聞站點Slashdot.org運行在InnoDB上腰耙。 Mytrix, Inc.在InnoDB上存儲超過1TB的數(shù)據(jù)榛丢,還有一些其它站點在InnoDB上處理平均每秒800次插入/更新的負荷。

4.2.1 InnoDB特性

4.2.1.1 InnoDB Properties

1) 支持事務挺庞,ACID晰赞,外鍵。

2) Row level locks。

3) 支持不同的隔離級別掖鱼。

4) 和MyISAM相比需要較多的內(nèi)存和磁盤空間然走。

5) 沒有鍵壓縮。

6) 數(shù)據(jù)和索引都緩存在內(nèi)存hash表中戏挡。

4.2.1.2 InnoDB Good For

1) 需要事務的應用芍瑞。

2) 高并發(fā)的應用。

3) 自動恢復褐墅。

4) 較快速的基于主鍵的操作拆檬。

4.2.2 InnoDB優(yōu)化要點

1) 盡量使用short,integer的主鍵妥凳。

2) Load/Insert數(shù)據(jù)時按主鍵順序竟贯。如果數(shù)據(jù)沒有按主鍵排序,先排序然后再進行數(shù)據(jù)庫操作逝钥。

3) 在Load數(shù)據(jù)是為設置SET UNIQUE_CHECKS=0屑那,SET FOREIGN_KEY_CHECKS=0,可以避免外鍵和唯一性約束檢查的開銷艘款。

4) 使用prefix keys持际。因為InnoDB沒有key壓縮功能弓颈。

4.2.3 InnoDB服務器端設定

innodb_buffer_pool_size:這是InnoDB最重要的設置杖剪,對InnoDB性能有決定性的影響菱肖。默認的設置只有8M焰雕,所以默認的數(shù)據(jù)庫設置下面InnoDB性能很差段只。在只有InnoDB存儲引擎的數(shù)據(jù)庫服務器上面炭序,可以設置60-80%的內(nèi)存卧蜓。更精確一點妓蛮,在內(nèi)存容量允許的情況下面設置比InnoDB tablespaces大10%的內(nèi)存大小空繁。

innodb_data_file_path:指定表數(shù)據(jù)和索引存儲的空間殿衰,可以是一個或者多個文件。最后一個數(shù)據(jù)文件必須是自動擴充的盛泡,也只有最后一個文件允許自動擴充闷祥。這樣,當空間用完后傲诵,自動擴充數(shù)據(jù)文件就會自動增長(以8MB為單位)以容納額外的數(shù)據(jù)凯砍。例如: innodb_data_file_path=/disk1/ibdata1:900M;/disk2/ibdata2:50M:autoextend兩個數(shù)據(jù)文件放在不同的磁盤上。數(shù)據(jù)首先放在ibdata1中拴竹,當達到900M以后悟衩,數(shù)據(jù)就放在ibdata2中。一旦達到50MB栓拜,ibdata2將以8MB為單位自動增長座泳。如果磁盤滿了惠昔,需要在另外的磁盤上面增加一個數(shù)據(jù)文件。

innodb_autoextend_increment: 默認是8M, 如果一次insert數(shù)據(jù)量比較多的話, 可以適當增加.

innodb_data_home_dir:放置表空間數(shù)據(jù)的目錄挑势,默認在mysql的數(shù)據(jù)目錄镇防,設置到和MySQL安裝文件不同的分區(qū)可以提高性能。

innodb_log_file_size:該參數(shù)決定了recovery speed潮饱。太大的話recovery就會比較慢来氧,太小了影響查詢性能,一般取256M可以兼顧性能和recovery的速度

香拉。

innodb_log_buffer_size:磁盤速度是很慢的啦扬,直接將log寫道磁盤會影響InnoDB的性能,該參數(shù)設定了log buffer的大小缕溉,一般4M考传。如果有大的blob操作吃型,可以適當增大证鸥。

innodb_flush_logs_at_trx_commit=2: 該參數(shù)設定了事務提交時內(nèi)存中l(wèi)og信息的處理。

1) =1時勤晚,在每個事務提交時枉层,日志緩沖被寫到日志文件,對日志文件做到磁盤操作的刷新赐写。Truly ACID鸟蜡。速度慢。

2) =2時挺邀,在每個事務提交時揉忘,日志緩沖被寫到文件,但不對日志文件做到磁盤操作的刷新端铛。只有操作系統(tǒng)崩潰或掉電才會刪除最后一秒的事務泣矛,不然不會丟失事務。

3) =0時禾蚕, 日志緩沖每秒一次地被寫到日志文件您朽,并且對日志文件做到磁盤操作的刷新。任何mysqld進程的崩潰會刪除崩潰前最后一秒的事務

innodb_file_per_table:可以存儲每個InnoDB表和它的索引在它自己的文件中换淆。

transaction-isolation=READ-COMITTED: 如果應用程序可以運行在READ-COMMITED隔離級別哗总,做此設定會有一定的性能提升。

innodb_flush_method: 設置InnoDB同步IO的方式:

1) Default – 使用fsync()倍试。

2) O_SYNC 以sync模式打開文件讯屈,通常比較慢。

3) O_DIRECT县习,在Linux上使用Direct IO耻煤【咦常可以顯著提高速度,特別是在RAID系統(tǒng)上哈蝇。避免額外的數(shù)據(jù)復制和double buffering(mysql buffering 和OS buffering)棺妓。

innodb_thread_concurrency: InnoDB kernel最大的線程數(shù)。

1) 最少設置為(num_disks+num_cpus)*2炮赦。

2) 可以通過設置成1000來禁止這個限制

5. 緩存

緩存有很多種怜跑,為應用程序加上適當?shù)木彺娌呗詴@著提高應用程序的性能。由于應用緩存是一個比較大的話題吠勘,所以這一部分還需要進一步調(diào)研性芬。

6. Reference

1) http://www.mysqlperformanceblog.com/

2) Advanced MySQL Performance Optimization, Peter Zaitsev, Tobias Asplund, MySQL Users Conference 2005

3) Improving MySQL Server Performance with Intel C++ Compiler,Peter Zaitsev剧防,Linux World 2005

4) MySQL Performance Optimization, Peter Zaitsev, Percona Ltd, OPEN SOURCE DATABASE CONFERENCE 2006

5) MySQL Server Settings Tuning, Peter Zaitsev, co-founder, Percona Ltd, 2007

6) MySQL Reference Manual


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末植锉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子峭拘,更是在濱河造成了極大的恐慌俊庇,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,207評論 6 521
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸡挠,死亡現(xiàn)場離奇詭異辉饱,居然都是意外死亡,警方通過查閱死者的電腦和手機拣展,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,455評論 3 400
  • 文/潘曉璐 我一進店門彭沼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人备埃,你說我怎么就攤上這事姓惑。” “怎么了按脚?”我有些...
    開封第一講書人閱讀 170,031評論 0 366
  • 文/不壞的土叔 我叫張陵于毙,是天一觀的道長。 經(jīng)常有香客問我乘寒,道長望众,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,334評論 1 300
  • 正文 為了忘掉前任伞辛,我火速辦了婚禮烂翰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蚤氏。我一直安慰自己甘耿,他們只是感情好,可當我...
    茶點故事閱讀 69,322評論 6 398
  • 文/花漫 我一把揭開白布竿滨。 她就那樣靜靜地躺著佳恬,像睡著了一般捏境。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毁葱,一...
    開封第一講書人閱讀 52,895評論 1 314
  • 那天垫言,我揣著相機與錄音,去河邊找鬼倾剿。 笑死筷频,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的前痘。 我是一名探鬼主播凛捏,決...
    沈念sama閱讀 41,300評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼芹缔!你這毒婦竟也來了坯癣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,264評論 0 277
  • 序言:老撾萬榮一對情侶失蹤最欠,失蹤者是張志新(化名)和其女友劉穎示罗,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窒所,經(jīng)...
    沈念sama閱讀 46,784評論 1 321
  • 正文 獨居荒郊野嶺守林人離奇死亡鹉勒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,870評論 3 343
  • 正文 我和宋清朗相戀三年帆锋,在試婚紗的時候發(fā)現(xiàn)自己被綠了吵取。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,989評論 1 354
  • 序言:一個原本活蹦亂跳的男人離奇死亡锯厢,死狀恐怖皮官,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情实辑,我是刑警寧澤捺氢,帶...
    沈念sama閱讀 36,649評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站剪撬,受9級特大地震影響摄乒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜残黑,卻給世界環(huán)境...
    茶點故事閱讀 42,331評論 3 336
  • 文/蒙蒙 一馍佑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧梨水,春花似錦拭荤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,814評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旦委。三九已至,卻和暖如春雏亚,著一層夾襖步出監(jiān)牢的瞬間缨硝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,940評論 1 275
  • 我被黑心中介騙來泰國打工罢低, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留追葡,地道東北人。 一個月前我還...
    沈念sama閱讀 49,452評論 3 379
  • 正文 我出身青樓奕短,卻偏偏與公主長得像宜肉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子翎碑,可洞房花燭夜當晚...
    茶點故事閱讀 45,995評論 2 361

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