


版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、MySQL 性能優(yōu)化的最佳 20+條經(jīng)驗今天,數(shù)據(jù)庫的操作越來越成為整個應(yīng)用的性能瓶頸了,這點對于 Web 應(yīng)用尤其明顯。關(guān)于數(shù)據(jù)庫的性能,這并不只是 DBA 才需要擔(dān)心的事,而這更是我們程序員需要去關(guān)注的事情。當(dāng)我們?nèi)ピO(shè)計數(shù)據(jù)庫表結(jié)構(gòu),對操作數(shù)據(jù)庫時(尤其是查表時的 SQL 語句),我們都需要注意數(shù)據(jù)操作的性能。這里,我們講過多的 SQL 語句的優(yōu)化,而只是MySQL 這一 Web應(yīng)用最多的數(shù)據(jù)庫。希望下面的這些優(yōu)化技巧對你有用。1. 為緩存優(yōu)化你的大多數(shù)的 MySQL 服務(wù)器都開啟了緩存。這是提高性最有效的方法之一,而且這是被 MySQL的數(shù)據(jù)庫引擎處理的。當(dāng)有很多相同的被執(zhí)行了多次的時候
2、,這些結(jié)果會被放到一個緩存中,這樣,后續(xù)的相同的就不用操作表而直接緩存結(jié)果了。這里最主要的問題是,對于程序員來說,這個事情是很容易被忽略的。因為,我們某些語句會讓 MySQL 不使用緩存。請看下面的示例:上面兩條 SQL 語句的差別就是 CURDATE() ,MySQL 的緩存對這個函數(shù)不起作用。所以,像 NOW() 和 RAND() 或是其它的諸如此類的 SQL 函數(shù)都開啟緩存,因為這些函數(shù)的返回是會不定的易變的。所以,你所需要的就是用一個變量來代替 MySQL 的函數(shù),從而開啟緩存。2. EXPLAIN 你的 SELECT使用 EXPLAIN 關(guān)鍵字可以讓你知道 MySQL 是如何處理你的
3、 SQL 語句的。這可以幫你分析你的語句或是表結(jié)構(gòu)的性能瓶頸。EXPLAIN 的結(jié)果還會告訴你你的索引主鍵被如何利用的,你的數(shù)據(jù)表是如何被搜索和排序的等等,等等。挑一個你的 SELECT 語句(推薦挑選那個最復(fù)雜的,有多表聯(lián)接的),把關(guān)鍵字 EXPLAIN 加到前面。你可以使用 phpmyadmin 來做這個事。然后,你會看到一張表格。下面的這個示例中,我們忘記加上了 group_id 索引,并且有表聯(lián)接:當(dāng)我們?yōu)?group_id 字段加上索引后:我們可以看到,前一個結(jié)果顯示搜索了 7883 行,而后一個只是搜索了兩個表的 9 和 16行。查看 rows 列可以讓我們找到潛在的性能問題。3.
4、 當(dāng)只當(dāng)你數(shù)據(jù)時使用 LIMIT 1表的有些時候,你已經(jīng)知道結(jié)果只會有一條結(jié)果,但因為你可能需要去 fetch 游標(biāo),或是你也許會去檢查返回的數(shù)。在這種情,加上 LIMIT 1 可以增加性能。這樣一樣,MySQL 數(shù)據(jù)庫引擎會在找到一條數(shù)據(jù)后停止搜索,而不是繼續(xù)往后下一條符合的數(shù)據(jù)。下面的示例,只是為了找一下是否有“中國”的用戶,很明顯,后面的會比前面的更有效率。(請注意,第一條中是 Select *,第二條是 Select 1)4. 為搜索字段建索引索引并不一定就是給主鍵或是唯一的字段。如果在你的表中,有某個字段你總要會經(jīng)常用來做搜索,那么,請為其建立索引吧。從上圖你可以看到那個搜索字串 “
5、last_name LIKE a%”,一個是建了索引,一個是沒有索引,性能差了 4 倍左右。另外,你應(yīng)該也需要知道什么樣的搜索是不能使用正常的索引的。例如,當(dāng)你需要在一篇大的文章中搜索一個詞時,如: “WHERE post_content LIKE %apple%”,索引可能是沒有意義的。你可能需要使用 MySQL 全文索引 或是是 Tag 什么的)5. 在 Join 表的時候使用相當(dāng)類型的例,并將其索引做一個索引(比如說:搜索或如果你的應(yīng)用程序有很多 JOIN,你應(yīng)該確認(rèn)兩個表中 Join 的字段是被建過索引的。這樣,MySQL 內(nèi)部會啟動為你優(yōu)化 Join 的 SQL 語句的機(jī)制。而且,這
6、些被用來 Join 的字段,應(yīng)該是相同的類型的。例如:如果你要把 DECIMAL 字段和一個 INT 字段 Join 在一起,MySQL 就無法使用它們的索引。對于那些 STRING 類型,還需要有相同的字符集才行。(兩個表的字符集有可能不一樣)6. 千萬不要 ORDER BY RAND()想打亂返回的數(shù)據(jù)行?隨機(jī)挑一個數(shù)據(jù)?真不知道誰發(fā)明了這種用法,但很多新手很喜歡這樣用。但你確不了解這樣做有多么可怕的性能問題。如果你真的想把返回的數(shù)據(jù)行打亂了,你有 N 種方法可以達(dá)到這個目的。這樣使用只讓你的數(shù)據(jù)庫的性能呈指數(shù)級的下降。這里的問題是:MySQL 會不得不去執(zhí)行 RAND()函數(shù)(很耗CPU
7、 時間),而且這是為了每一行無濟(jì)于事(因為要排序)下面的示例是隨機(jī)挑一條去記行,然后再對其排序。就算是你用了 Limit 1 也7. 避免 SELECT *從數(shù)據(jù)讀出越多的數(shù)據(jù),那么就會變得越慢。并且,如果你的數(shù)據(jù)庫服務(wù)器和 WEB服務(wù)器是兩立的服務(wù)器的話,這還會增加網(wǎng)絡(luò)傳輸?shù)呢?fù)載。所以,你應(yīng)該養(yǎng)成一個需要什么就取什么的好的習(xí)慣。8. 永遠(yuǎn)為每張表設(shè)置一個 ID我們應(yīng)該為數(shù)據(jù)的每張表都設(shè)置一個 ID 做為其主鍵,而且最好的是一個 INT 型的(推薦使用 UNSIGNED),并設(shè)置上自動增加的 AUTO_INCREMENT 標(biāo)志。就算是你 users 表有一個主鍵叫 “”的字段,你也別讓它成為主
8、鍵。使用 VARCHAR類型來當(dāng)主鍵會使用得性能下降。另外,在你的據(jù)結(jié)構(gòu)。,你應(yīng)該使用表的 ID 來構(gòu)造你的數(shù)而且,在 MySQL 數(shù)據(jù)引擎下,還有一些操作需要使用主鍵,在這些情置變得非常重要,比如,集群,分區(qū),主鍵的性能和設(shè)在這里,只有一個情況是例外,那就是“關(guān)聯(lián)表”的“外鍵”,也就是說,這個表的主鍵,通過若干個別的表的主鍵。我們把這個情況叫做“外鍵”。比一個“學(xué)生表”有學(xué)生的 ID,有一個“課程表”有課程 ID,那么,“成績表”就是“關(guān)聯(lián)表”了,其關(guān)聯(lián)了學(xué)生表和課程表,在成績表中,學(xué)生 ID 和課程ID 叫“外鍵”其共同組成主鍵。9. 使用 ENUM 而不是 VARCHARENUM 類型是
9、非??旌途o湊的。在實際上,其保存的是 TINYINT,但其外表上顯示為字符串。這樣一來,用這個字段來做一些選項列表變得相當(dāng)?shù)耐昝?。如果你有一個字段,比如“”,“”,“”,“狀態(tài)”或“部門”,你知道這些字段的取值是有限而且固定的,那么,你應(yīng)該使用 ENUM 而不是 VARCHAR。MySQL 也有一個“建議”(見第十條)告訴你怎么去重新組織你的表結(jié)構(gòu)。當(dāng)你有一個VARCHAR 字段時,這個建議會告訴你把其改成 ENUM 類型。使用 PROCEDURE ANALYSE() 你可以得到相關(guān)的建議。10. 從 PROCEDURE ANALYSE() 取得建議PROCEDURE ANALYSE() 會讓
10、 MySQL 幫你去分析你的字段和其實際的數(shù)據(jù),并會給你一些有用的建議。只有表中有實際的數(shù)據(jù),這些建議才會變得有用,因為要做一些大的決定是需要有數(shù)據(jù)作為基礎(chǔ)的。例如,如果你創(chuàng)建了一個 INT 字段作為你的主鍵,然而并沒有太多的數(shù)據(jù),那么,PROCEDURE ANALYSE()會建議你把這個字段的類型改成 MEDIUMINT 。或是你使用了一個 VARCHAR 字段, 因為數(shù)據(jù)不多,你可能會得到一個讓你把它改成 ENUM 的建議。這些建議,都是可能因為數(shù)據(jù)不夠多,所以決策做得就不夠準(zhǔn)。在 phpmyadmin 里,你可以在查看表時,點擊 “Propose table structure” 來查看
11、這些建議一定要注意,這些只是建議,只有當(dāng)你的表里的數(shù)據(jù)越來越多時,這些建議才會變得準(zhǔn)確。一定要記住,你才是最終做決定的人。11. 盡可能的使用 NOT NULL除非你有一個很特別的去使用 NULL 值,你應(yīng)該總是讓你的字段保持 NOT NULL。這看起來好像有點爭議,請往下看。首先,問問你“Empty”和“NULL”有多大的區(qū)別(如果是 INT,那就是 0 和 NULL)?如果你覺得它們之間沒有什么區(qū)別,那么你就不要使用 NULL。(NULL 和 Empty 的字符串是一樣的!)?在 Oracle 里,不要以為 NULL 不需要空間,其需要額外的空間,并且,在你進(jìn)行比較的時候,你的更復(fù)雜。 當(dāng)
12、然,這里并不是說你就不能使用 NULL 了,現(xiàn)實情況是很復(fù)雜的,依然會有些情,你需要使用 NULL 值。下面摘自 MySQL的文檔:12. Prepared StatementsPrepared Statements 很像過程,是一種運(yùn)行在的 SQL 語句集合,我們可以從使用prepared statements 獲得很多好處,無論是性能問題還是安全問題。Prepared Statements 可以檢查一些你綁定好的變量,這樣可以保護(hù)你的程序受到“SQL 注入式”。當(dāng)然,你也可以手動地檢查你的這些變量,然而,手動的檢查容易出問題,而且很經(jīng)常會被程序員忘了。當(dāng)我們使用一些 framework 或
13、是 ORM 的時候,這樣的問題會好一些。在性能方面,當(dāng)一個相同的被使用多次的時候,這會為你帶來可觀的性能優(yōu)勢。你可以給這些 Prepared Statements 定義一些參數(shù),而 MySQL 只會一次。雖然最新版本的 MySQL 在傳輸 Prepared Statements 是使用二進(jìn)制形勢,所以這會使得網(wǎng)絡(luò)傳輸非常有效率。當(dāng)然,也有一些情,我們需要避免使用 Prepared Statements,因為其不支持緩存。但據(jù)說版本 5.1 后支持了。在 PHP 中要使用 prepared statements,你可以查看其使用手冊:mysqli 擴(kuò)展 或是使用數(shù)據(jù)庫抽象層,如: PDO.13.
14、 無緩沖的正常的情,當(dāng)你在當(dāng)你在你的中執(zhí)行一個 SQL 語句的時候,你的停在那里直來改變這個到?jīng)]這個 SQL 語句返回,然后你的程序再往下繼續(xù)執(zhí)行。你可以使用無緩沖行為。關(guān)于這個事情,在 PHP 的文檔中有一個非常不錯的說明:mysql_unbuffered_query() 函數(shù):上面那句話翻譯過來是說,mysql_unbuffered_query()一個 SQL 語句到 MySQL 而并不像 mysql_query()一樣去自動 fethch 和緩存結(jié)果。這會相當(dāng)節(jié)約很多可觀的內(nèi)存,尤其是那些會產(chǎn)生大量結(jié)果的語句,并且,你不需要等到所有的結(jié)果都返回,只需要第一行數(shù)據(jù)返回的時候,你就可以開始馬
15、上開始工作于結(jié)果了。然而,這會有一些限制。因為你要么把所有行都讀走,或是你要在進(jìn)行下一次的前調(diào)用mysql_free_result() 清除結(jié)果。而且, mysql_num_rows() 或 mysql_data_seek() 將無法使用。所以,是否使用無緩沖的14. 把 IP 地址存成 UNSIGNED INT你需要仔細(xì)考慮。很多程序員都會創(chuàng)建一個 VARCHAR(15) 字段來存放字符串形式的 IP 而不是整形的 IP。如果你用整形來存放,只需要 4 個字節(jié),并且你可以有定長的字段。而且,這會為你帶來上的優(yōu)勢,尤其是當(dāng)你需要使用這樣的 WHERE 條件:IP between ip1 and
16、 ip2。我們必需要使用 UNSIGNED INT,因為 IP 地址會使用整個 32 位的無符號整形。而你的, 你可以使用 INET_ATON() 來把一個字符串 IP 轉(zhuǎn)成一個整形, 并使用INET_NTOA() 把一個整形轉(zhuǎn)成一個字符串 IP。在 PHP 中,也有這樣的函數(shù) ip2long() 和long2ip()。15. 固定長度的表會更快如果表中的所有字段都是“ 固定長度” 的, 整個表會被認(rèn)為是 “static” 或“fixed-length”。 例如,表中沒有如下類型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一個這些字段,那么這個表就不是“固定長度靜態(tài)表”了,這
17、樣,MySQL 引擎會用另法來處理。固定長度的表會提高性能,因為 MySQL 搜尋得會更快一些,因為這些固定的長度是很容易計算下一個數(shù)據(jù)的偏移量的,所以的自然也會很快。而如果字段不是定長的,那么,每一次要找下一條的話,需要程序找到主鍵。并且,固定長度的表也更容易被緩存和重建。不過,唯一的副作用是,固定長度的字段會浪費(fèi)一些空間,因為定長的字段無論你用不用,他都是要分配那么多的空間。使用“垂直分割”技術(shù)(見下一條),你可以分割你的表成為兩個一個是定長的,一個則是不定長的。16. 垂直分割“垂直分割”是一種把數(shù)據(jù)庫中的表按列變成幾張表的方法,這樣可以降低表的復(fù)雜度和字段的數(shù)目,從而達(dá)到優(yōu)化的目的。(
18、以前,在做過項目,見過一張表有 100 多個字段,很)示例一:在 Users 表中有一個字段是家庭地址,這個字段是可選字段,相比起,而且你在數(shù)據(jù)庫操作的時候除了個人信息外,你并不需要經(jīng)?;蚴歉膶戇@個字段。那么,為什么不把他放到另外一張表中呢? 這樣會讓你的表有更好的性能,大家想想是不是,大量的時候,我對于用戶表來說,只有用戶 ID,用戶名,口令,用戶總是會有好的性能。等會被經(jīng)常使用。小一點的表示例二: 你有一個叫 “l(fā)ast_login” 的字段,它會在每次用戶登錄時被更新。但是,每次更新時會導(dǎo)致該表的緩存被清空。所以,你可以把這個字段放到另一個表中,這樣就影響你對用戶 ID,用戶名,用戶性能
19、。的不停地了,因為緩存會幫你增加很多另外,你需要注意的是,這些被分出去的字段所形成的表,你經(jīng)常性地去 Join 他們,不然的話,這樣的性能會比不分割時還要差,而且,會是極數(shù)級的下降。17. 拆分大的 DELETE 或 INSERT 語句如果你需要在一個的上去執(zhí)行一個大的 DELETE 或 INSERT,你需要非常小心,要避免你的操作讓你的整個別的操作都進(jìn)不來了。停止相應(yīng)。因為這兩個操作是會鎖表的,表一鎖住了,Apache 會有很多的子進(jìn)程或線程。所以,其工作起來相當(dāng)有效率,而我們的服務(wù)器也不希望有太多的子進(jìn)程,線程和數(shù)據(jù)庫,這是極大的占服務(wù)器的事情,尤其是內(nèi)存。如果你的表鎖上一段時間,比如 3
20、0 秒鐘,那么對于一個有很高量的站點來說,這30 秒所積累的進(jìn)程/線程,數(shù)據(jù)庫,打開的文件數(shù),可能不僅僅會讓你泊 WEB 服務(wù)Crash,還可能會讓你的整臺服務(wù)器馬上掛了。所以,如果你有一個大的處理,你定你一定把其拆分,使用 LIMIT 條件是一個好的方法。下面是一個示例:18. 越小的列會越快對于大多數(shù)的數(shù)據(jù)庫引擎來說,硬盤操作可能是最會對這種情況非常有幫助,因為這減少了對硬盤的的瓶頸。所以,。的數(shù)據(jù)變得緊湊參看 MySQL 的文檔 Storage Requirements 查看所有的數(shù)據(jù)類型。如果一個表只會有幾列罷了(比如說字典表,配置表),那么,我們就沒有理由使用 INT 來做主鍵,使用
21、 MEDIUMINT, SMALLINT 或是更小的 TINYINT 會更錄時間,使用 DATE 要比 DATETIME 好得多。一些。如果你不需要記當(dāng)然,你也需要留夠足夠的擴(kuò)展空間,不然,你日后來干這個事,你會死的很難看,參看Slashdot 的例子(2009 年 11 月 06 日),一個簡單的 ALTER TABLE 語句花了 3 個多小時, 因為里面有一千六百萬條數(shù)據(jù)。19. 選擇正確的引擎在 MySQL 中有兩個引擎 MyISAM 和 InnoDB,每個引擎都有利有弊??釟ひ郧拔恼翸ySQL: InnoDB 還是 MyISAM?討論和這個事情。MyISAM 適合于一些需要大量的應(yīng)用,但其對于有大量寫操作并不是很好。甚至你只是需要 update 一個字段,整個表都會被鎖起來,而別的進(jìn)程,就算是讀進(jìn)程都無法操作直到讀操作完成。另外,MyISAM 對于 SELECT COUNT(*) 這類的計算是超快無比的。InnoDB 的趨勢會是一個非常復(fù)雜的引擎,對于一些小的應(yīng)用,它會比 MyISAM 還慢。他是它支持“行鎖” ,于是在
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 電腦專賣店企業(yè)制定與實施新質(zhì)生產(chǎn)力項目商業(yè)計劃書
- 親子益智游戲館企業(yè)制定與實施新質(zhì)生產(chǎn)力項目商業(yè)計劃書
- 新型HPO多功能聚乙烯薄膜項目可行性研究報告模板-備案拿地
- 護(hù)理院年度計劃范文5
- 四年級上冊數(shù)學(xué)(人教)習(xí)題課件九 總復(fù)習(xí)第8課時 圖形與幾何1
- Module3-Reading-and-Vocabulary-公開課課件(一)
- 西方經(jīng)濟(jì)學(xué)-馬工程重點教材-第11章
- 安然的績效考核的問題
- 2025至2030年中國面部美容巾行業(yè)投資前景及策略咨詢報告
- 2024屆安徽省沿淮教育聯(lián)盟重點達(dá)標(biāo)名校中考數(shù)學(xué)仿真試卷含解析
- 氣瓶的使用操作規(guī)程
- 江蘇南京市北京東路小學(xué)四年級數(shù)學(xué)下冊期末復(fù)習(xí)試卷(二)及答案
- 浙江中考生物知識點大全
- 金屬非金屬礦山安全標(biāo)準(zhǔn)化講義
- 一人力資源轉(zhuǎn)型和價值
- 機(jī)房設(shè)備安裝工程及移動通信工程施工工藝圖解
- 國內(nèi)生態(tài)工業(yè)園區(qū)發(fā)展分析
- YY/T 0292.1-1997醫(yī)用診斷X射線輻射防護(hù)器具第1部分:材料衰減性能的測定
- LY/T 1697-2017飾面木質(zhì)墻板
- GB/T 97.1-2002平墊圈A級
- GB/T 5121.27-2008銅及銅合金化學(xué)分析方法第27部分:電感耦合等離子體原子發(fā)射光譜法
評論
0/150
提交評論