MySQL性能優化的細節

服務器硬件

服務器系統

數據庫存儲引擎

MyISAM:可以很好的利用內存,但不支持事務,表級鎖

InnoDB:事務級存儲引擎,完美支持行級鎖以及事務ACID特性

數據庫參數配置

數據庫表結構設計和SQL語句執行效率

SQL優化

SQL語句,如果使用了一些優化小技巧,定能達到事半功倍的效果。

技巧1  比較運算符能用 “=”就不用“<>”

“=”增加了索引的使用機率。

技巧2  明知只有一條查詢結果,那請使用 “LIMIT 1”

“LIMIT 1”可以避免全表掃描,找到對應結果就不會再繼續掃描了。

技巧3  爲列選擇合適的數據類型

能用TINYINT就不用SMALLINT,能用SMALLINT就不用INT,道理你懂的,磁盤和內存消耗越小越好嘛。

技巧4  將大的DELETE,UPDATE or INSERT 查詢變成多個小查詢

能寫一個幾十行、幾百行的SQL語句是不是顯得逼格很高?然而,爲了達到更好的性能以及更好的數據控制,你可以將他們變成多個小查詢。

技巧5  使用UNION ALL 代替 UNION,如果結果集允許重複的話

因爲 UNION ALL 不去重,效率高於 UNION。
技巧6  爲獲得相同結果集的多次執行,請保持SQL語句前後一致

這樣做的目的是爲了充分利用查詢緩衝。

比如根據地域和產品id查詢產品價格,第一次使用了:

那麼第二次同樣的查詢,請保持以上語句的一致性,比如不要將where語句裏面的id和region位置調換順序。

技巧7  儘量避免使用 “SELECT *”

如果不查詢表中所有的列,儘量避免使用 SELECT *,因爲它會進行全表掃描,不能有效利用索引,增大了數據庫服務器的負擔,以及它與應用程序客戶端之間的網絡IO開銷。

技巧8  WHERE 子句裏面的列儘量被索引

只是“儘量”哦,並不是說所有的列。因地制宜,根據實際情況進行調整,因爲有時索引太多也會降低性能。

技巧9  JOIN 子句裏面的列儘量被索引

同樣只是“儘量”哦,並不是說所有的列。

技巧10  ORDER BY 的列儘量被索引

ORDER BY的列如果被索引,性能也會更好。

技巧11  使用 LIMIT 實現分頁邏輯

不僅提高了性能,同時減少了不必要的數據庫和應用間的網絡傳輸。

技巧12  使用 EXPLAIN 關鍵字去查看執行計劃

EXPLAIN 可以檢查索引使用情況以及掃描的行。

使 用 EXPLAIN 關鍵字可以讓你知道MySQL是如何處理你的SQL語句的。這可以幫你分析你的查詢語句或是表
結構的性能瓶頸。EXPLAIN 的查詢結果還會告訴你你的索引主鍵被如何利用的,你的數據表是如何被搜索和排序的…
…等等,等等。挑一個你的SELECT語句(推薦挑選那個最複雜的,有 多表聯接的),把關鍵字EXPLAIN加到前面。你
可以使用phpmyadmin來做這個事。

 

 爲查詢緩存優化你的查詢

        大 多數的MySQL服務器都開啓了查詢緩存。這是提高性最有效的方法之一,而且這是被MySQL的數據庫引擎處
理的。當有很多相同的查詢被執行了多次的時 候,這些查詢結果會被放到一個緩存中,這樣,後續的相同的查詢就不
用操作表而直接訪問緩存結果了。這裏最主要的問題是,對於程序員來說,這個事情是很容易 被忽略的。因爲,我們
某些查詢語句會讓MySQL不使用緩存。請看下面的示例:

// 查詢緩存不開啓
$r = mysql_query("SELECT username FROM user WHERE signup_date >= CURDATE()");
 
// 開啓查詢緩存
$today = date("Y-m-d");
$r = mysql_query("SELECT username FROM user WHERE signup_date >= '$today'");
        上面兩條SQL語句的差別就是 CURDATE() ,MySQL的查詢緩存對這個函數不起作用。所以,像 NOW() 和
RAND() 或是其它的諸如此類的SQL函數都不會開啓查詢緩存,因爲這些函數的返回是會不定的易變的。所以,你所需
要的就是用一個變量來代替MySQL的函數,從而 開啓緩存。

    使 用 EXPLAIN 關鍵字可以讓你知道MySQL是如何處理你的SQL語句的。這可以幫你分析你的查詢語句或是表
結構的性能瓶頸。EXPLAIN 的查詢結果還會告訴你你的索引主鍵被如何利用的,你的數據表是如何被搜索和排序的…
…等等,等等。挑一個你的SELECT語句(推薦挑選那個最複雜的,有 多表聯接的),把關鍵字EXPLAIN加到前面。你
可以使用phpmyadmin來做這個事。


爲搜索字段建索引

        索引並不一定就是給主鍵或是唯一的字段。如果在你的表中,有某個字段你總要會經常用來做搜索,那麼,
請爲其建立索引吧。

在Join表的時候使用相當類型的例,並將其索引

        如 果你的應用程序有很多 JOIN 查詢,你應該確認兩個表中Join的字段是被建過索引的。這樣,MySQL內部會啓動爲你優化Join的SQL語句的機制。而且,這些被用來Join的字 段,應該是相同的類型的。例如:如果你要把 DECIMAL 字段和一個 INT 字段Join在一起,MySQL就無法使用它們的索引。對於那些STRING類型,還需要有相同的字符集才行。(兩個表的字符集有可能不一樣)

 永遠爲每張表設置一個ID

        我 們應該爲數據庫裏的每張表都設置一個ID做爲其主鍵,而且最好的是一個INT型的(推薦使用UNSIGNED),並設置上自動增加的 AUTO_INCREMENT標誌。就算是你 users 表有一個主鍵叫 “email”的字段,你也別讓它成爲主鍵。使用 VARCHAR 類型來當主鍵會使用得性能下降。另外,在你的程序中,你應該使用表的ID來構造你的數據結構。而且,在MySQL數據引擎下,還有一些操作需要使用主鍵, 在這些情況下,主鍵的性能和設置變得非常重要,比如,集羣,分區……

        在 這裏,只有一個情況是例外,那就是“關聯表”的“外鍵”,也就是說,這個表的主鍵,通過若干個別的表的主鍵構成。我們把這個情況叫做“外鍵”。比如:有一 個“學生表”有學生的ID,有一個“課程表”有課程ID,那麼,“成績表”就是“關聯表”了,其關聯了學生表和課程表,在成績表中,學生ID和課程ID叫 “外鍵”其共同組成主鍵。


使用 ENUM 而不是 VARCHAR

        ENUM 類型是非常快和緊湊的。在實際上,其保存的是 TINYINT,但其外表上顯示爲字符串。這樣一來,用這個字段來做一些選項列表變得相當的完美。如果你有一個字段,比如“性別”,“國家”,“民族”, “狀態”或“部門”,你知道這些字段的取值是有限而且固定的,那麼,你應該使用 ENUM 而不是 VARCHAR。MySQL也有一個“建議”(見第十條)告訴你怎麼去重新組織你的表結構。當你有一個 VARCHAR 字段時,這個建議會告訴你把其改成 ENUM 類型。使用 PROCEDURE ANALYSE() 你可以得到相關的建議。

從 PROCEDURE ANALYSE() 取得建議

        PROCEDURE ANALYSE() 會讓 MySQL 幫你去分析你的字段和其實際的數據,並會給你一些有用的建議。只有表中有實際的數據,這些建議纔會變得有用,因爲要做一些大的決定是需要有數據作爲基礎 的。例如,如果你創建了一個 INT 字段作爲你的主鍵,然而並沒有太多的數據,那麼,PROCEDURE ANALYSE()會建議你把這個字段的類型改成 MEDIUMINT 。或是你使用了一個 VARCHAR 字段,因爲數據不多,你可能會得到一個讓你把它改成 ENUM 的建議。這些建議,都是可能因爲數據不夠多,所以決策做得就不夠準。在phpmyadmin裏,你可以在查看錶時,點擊 “Propose table structure” 來查看這些建議一定要注意,這些只是建議,只有當你的表裏的數據越來越多時,這些建議纔會變得準確。一定要記住,你纔是最終做決定的人。

A. 儘可能的使用 NOT NULL

        除 非你有一個很特別的原因去使用 NULL 值,你應該總是讓你的字段保持 NOT NULL。這看起來好像有點爭議,請往下看。首先,問問你自己“Empty”和“NULL”有多大的區別(如果是INT,那就是0和NULL)?如果你覺 得它們之間沒有什麼區別,那麼你就不要使用NULL。(你知道嗎?在 Oracle 裏,NULL 和 Empty 的字符串是一樣的!) 不要以爲 NULL 不需要空間,其需要額外的空間,並且,在你進行比較的時候,你的程序會更復雜。 當然,這裏並不是說你就不能使用NULL了,現實情況是很複雜的,依然會有些情況下,你需要使用NULL值。下面摘自MySQL自己的文檔:

“NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”

B. Prepared Statements

        Prepared Statements很像存儲過程,是一種運行在後臺的SQL語句集合,我們可以從使用 prepared statements 獲得很多好處,無論是性能問題還是安全問題。Prepared Statements 可以檢查一些你綁定好的變量,這樣可以保護你的程序不會受到“SQL注入式”攻擊。當然,你也可以手動地檢查你的這些變量,然而,手動的檢查容易出問題, 而且很經常會被程序員忘了。當我們使用一些framework或是ORM的時候,這樣的問題會好一些。在性能方面,當一個相同的查詢被使用多次的時候,這 會爲你帶來可觀的性能優勢。你可以給這些Prepared Statements定義一些參數,而MySQL只會解析一次。雖然最新版本的MySQL在傳輸Prepared Statements是使用二進制形勢,所以這會使得網絡傳輸非常有效率。當然,也有一些情況下,我們需要避免使用Prepared Statements,因爲其不支持查詢緩存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章