MySQL优化学习总结
生活随笔
收集整理的這篇文章主要介紹了
MySQL优化学习总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
MySQL 性能優化的最佳20多條經驗分享
http://www.jb51.net/article/24392.htm今天,數據庫的操作越來越成為整個應用的性能瓶頸了,這點對于Web應用尤其明顯。關于數據庫的性能,這并不只是DBA才需要擔心的事,而這更是我們程序員需要去關注的事情。
..當我們去設計數據庫表結構,對操作數據庫時(尤其是查表時的SQL語句),我們都需要注意數據操作的性能。這里,我們不會講過多的SQL語句的優化,而只是針對MySQL這一Web應用最多的數據庫。希望下面的這些優化技巧對你有用。?
1. 為查詢緩存優化你的查詢?
大多數的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的函數,從而開啟緩存。?
2. EXPLAIN 你的 SELECT 查詢?
使用 EXPLAIN 關鍵字可以讓你知道MySQL是如何處理你的SQL語句的。這可以幫你分析你的查詢語句或是表結構的性能瓶頸。?
EXPLAIN 的查詢結果還會告訴你你的索引主鍵被如何利用的,你的數據表是如何被搜索和排序的……等等,等等。?
挑一個你的SELECT語句(推薦挑選那個最復雜的,有多表聯接的),把關鍵字EXPLAIN加到前面。你可以使用phpmyadmin來做這個事。然后,你會看到一張表格。下面的這個示例中,我們忘記加上了group_id索引,并且有表聯接:
當我們為 group_id 字段加上索引后:
我們可以看到,前一個結果顯示搜索了 7883 行,而后一個只是搜索了兩個表的 9 和 16 行。查看rows列可以讓我們找到潛在的性能問題。?
3. 當只要一行數據時使用 LIMIT 1?
當你查詢表的有些時候,你已經知道結果只會有一條結果,但因為你可能需要去fetch游標,或是你也許會去檢查返回的記錄數。?
在這種情況下,加上 LIMIT 1 可以增加性能。這樣一樣,MySQL數據庫引擎會在找到一條數據后停止搜索,而不是繼續往后查少下一條符合記錄的數據。?
下面的示例,只是為了找一下是否有“中國”的用戶,很明顯,后面的會比前面的更有效率。(請注意,第一條中是Select *,第二條是Select 1)?
復制代碼 代碼如下:
// 沒有效率的:?
$r = mysql_query("SELECT * FROM user WHERE country = 'China'");?
if (mysql_num_rows($r) > 0) {?
// ...?
}?
// 有效率的:?
$r = mysql_query("SELECT 1 FROM user WHERE country = 'China' LIMIT 1");?
if (mysql_num_rows($r) > 0) {?
// ...?
}
4. 為搜索字段建索引?
索引并不一定就是給主鍵或是唯一的字段。如果在你的表中,有某個字段你總要會經常用來做搜索,那么,請為其建立索引吧。
從上圖你可以看到那個搜索字串 “last_name LIKE ‘a%'”,一個是建了索引,一個是沒有索引,性能差了4倍左右。?
另外,你應該也需要知道什么樣的搜索是不能使用正常的索引的。例如,當你需要在一篇大的文章中搜索一個詞時,如: “WHERE post_content LIKE ‘%apple%'”,索引可能是沒有意義的。你可能需要使用MySQL全文索引 或是自己做一個索引(比如說:搜索關鍵詞或是Tag什么的)?
5. 在Join表的時候使用相當類型的例,并將其索引?
如果你的應用程序有很多 JOIN 查詢,你應該確認兩個表中Join的字段是被建過索引的。這樣,MySQL內部會啟動為你優化Join的SQL語句的機制。?
而且,這些被用來Join的字段,應該是相同的類型的。例如:如果你要把 DECIMAL 字段和一個 INT 字段Join在一起,MySQL就無法使用它們的索引。對于那些STRING類型,還需要有相同的字符集才行。(兩個表的字符集有可能不一樣)?
復制代碼 代碼如下:
// 在state中查找company?
$r = mysql_query("SELECT company_name FROM users?
LEFT JOIN companies ON (users.state = companies.state)?
WHERE users.id = $user_id");?
// 兩個 state 字段應該是被建過索引的,而且應該是相當的類型,相同的字符集。
6. 千萬不要 ORDER BY RAND()?
想打亂返回的數據行?隨機挑一個數據?真不知道誰發明了這種用法,但很多新手很喜歡這樣用。但你確不了解這樣做有多么可怕的性能問題。?
如果你真的想把返回的數據行打亂了,你有N種方法可以達到這個目的。這樣使用只讓你的數據庫的性能呈指數級的下降。這里的問題是:MySQL會不得不去執行RAND()函數(很耗CPU時間),而且這是為了每一行記錄去記行,然后再對其排序。就算是你用了Limit 1也無濟于事(因為要排序)?
下面的示例是隨機挑一條記錄?
復制代碼 代碼如下:
// 千萬不要這樣做:?
$r = mysql_query("SELECT username FROM user ORDER BY RAND() LIMIT 1");?
// 這要會更好:?
$r = mysql_query("SELECT count(*) FROM user");?
$d = mysql_fetch_row($r);?
$rand = mt_rand(0,$d[0] - 1);?
$r = mysql_query("SELECT username FROM user LIMIT $rand, 1");
7. 避免 SELECT *?
從數據庫里讀出越多的數據,那么查詢就會變得越慢。并且,如果你的數據庫服務器和WEB服務器是兩臺獨立的服務器的話,這還會增加網絡傳輸的負載。?
所以,你應該養成一個需要什么就取什么的好的習慣。?
復制代碼 代碼如下:
// 不推薦 $r = mysql_query("SELECT * FROM user WHERE user_id = 1"); $d = mysql_fetch_assoc($r); echo "Welcome {$d['username']}"; // 推薦 $r = mysql_query("SELECT username FROM user WHERE user_id = 1"); $d = mysql_fetch_assoc($r); echo "Welcome {$d['username']}";
8. 永遠為每張表設置一個ID?
我們應該為數據庫里的每張表都設置一個ID做為其主鍵,而且最好的是一個INT型的(推薦使用UNSIGNED),并設置上自動增加的 AUTO_INCREMENT標志。?
就算是你 users 表有一個主鍵叫 “email”的字段,你也別讓它成為主鍵。使用 VARCHAR 類型來當主鍵會使用得性能下降。另外,在你的程序中,你應該使用表的ID來構造你的數據結構。?
而且,在MySQL數據引擎下,還有一些操作需要使用主鍵,在這些情況下,主鍵的性能和設置變得非常重要,比如,集群,分區……?
在這里,只有一個情況是例外,那就是“關聯表”的“外鍵”,也就是說,這個表的主鍵,通過若干個別的表的主鍵構成。我們把這個情況叫做“外鍵”。比如:有一個“學生表”有學生的ID,有一個“課程表”有課程ID,那么,“成績表”就是“關聯表”了,其關聯了學生表和課程表,在成績表中,學生ID和課程ID叫“外鍵”其共同組成主鍵。?
9. 使用 ENUM 而不是 VARCHAR?
ENUM 類型是非常快和緊湊的。在實際上,其保存的是 TINYINT,但其外表上顯示為字符串。這樣一來,用這個字段來做一些選項列表變得相當的完美。?
如果你有一個字段,比如“性別”,“國家”,“民族”,“狀態”或“部門”,你知道這些字段的取值是有限而且固定的,那么,你應該使用 ENUM 而不是 VARCHAR。?
MySQL也有一個“建議”(見第十條)告訴你怎么去重新組織你的表結構。當你有一個 VARCHAR 字段時,這個建議會告訴你把其改成 ENUM 類型。使用 PROCEDURE ANALYSE() 你可以得到相關的建議。?
10. 從 PROCEDURE ANALYSE() 取得建議?
PROCEDURE ANALYSE() 會讓 MySQL 幫你去分析你的字段和其實際的數據,并會給你一些有用的建議。只有表中有實際的數據,這些建議才會變得有用,因為要做一些大的決定是需要有數據作為基礎的。?
例如,如果你創建了一個 INT 字段作為你的主鍵,然而并沒有太多的數據,那么,PROCEDURE ANALYSE()會建議你把這個字段的類型改成 MEDIUMINT 。或是你使用了一個 VARCHAR 字段,因為數據不多,你可能會得到一個讓你把它改成 ENUM 的建議。這些建議,都是可能因為數據不夠多,所以決策做得就不夠準。?
在phpmyadmin里,你可以在查看表時,點擊 “Propose table structure” 來查看這些建議
一定要注意,這些只是建議,只有當你的表里的數據越來越多時,這些建議才會變得準確。一定要記住,你才是最終做決定的人。?
11. 盡可能的使用 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.”?
12. Prepared Statements?
Prepared Statements很像存儲過程,是一種運行在后臺的SQL語句集合,我們可以從使用 prepared statements 獲得很多好處,無論是性能問題還是安全問題。?
Prepared Statements 可以檢查一些你綁定好的變量,這樣可以保護你的程序不會受到“SQL注入式”攻擊。當然,你也可以手動地檢查你的這些變量,然而,手動的檢查容易出問題,而且很經常會被程序員忘了。當我們使用一些framework或是ORM的時候,這樣的問題會好一些。?
在性能方面,當一個相同的查詢被使用多次的時候,這會為你帶來可觀的性能優勢。你可以給這些Prepared Statements定義一些參數,而MySQL只會解析一次。?
雖然最新版本的MySQL在傳輸Prepared Statements是使用二進制形勢,所以這會使得網絡傳輸非常有效率。?
當然,也有一些情況下,我們需要避免使用Prepared Statements,因為其不支持查詢緩存。但據說版本5.1后支持了。?
在PHP中要使用prepared statements,你可以查看其使用手冊:mysqli 擴展 或是使用數據庫抽象層,如: PDO.?
復制代碼 代碼如下:
// 創建 prepared statement?
if ($stmt = $mysqli->prepare("SELECT username FROM user WHERE state=?")) {?
// 綁定參數?
$stmt->bind_param("s", $state);?
// 執行?
$stmt->execute();?
// 綁定結果?
$stmt->bind_result($username);?
// 移動游標?
$stmt->fetch();?
printf("%s is from %s\n", $username, $state);?
$stmt->close();?
}
13. 無緩沖的查詢?
正常的情況下,當你在當你在你的腳本中執行一個SQL語句的時候,你的程序會停在那里直到沒這個SQL語句返回,然后你的程序再往下繼續執行。你可以使用無緩沖查詢來改變這個行為。?
關于這個事情,在PHP的文檔中有一個非常不錯的說明: mysql_unbuffered_query() 函數:?
“mysql_unbuffered_query() sends the SQL query query to MySQL without automatically fetching and buffering the result rows as mysql_query() does. This saves a considerable amount of memory with SQL queries that produce large result sets, and you can start working on the result set immediately after the first row has been retrieved as you don't have to wait until the complete SQL query has been performed.”?
上面那句話翻譯過來是說,mysql_unbuffered_query() 發送一個SQL語句到MySQL而并不像mysql_query()一樣去自動fethch和緩存結果。這會相當節約很多可觀的內存,尤其是那些會產生大量結果的查詢語句,并且,你不需要等到所有的結果都返回,只需要第一行數據返回的時候,你就可以開始馬上開始工作于查詢結果了。?
然而,這會有一些限制。因為你要么把所有行都讀走,或是你要在進行下一次的查詢前調用 mysql_free_result() 清除結果。而且, mysql_num_rows() 或 mysql_data_seek() 將無法使用。所以,是否使用無緩沖的查詢你需要仔細考慮。?
14. 把IP地址存成 UNSIGNED INT?
很多程序員都會創建一個 VARCHAR(15) 字段來存放字符串形式的IP而不是整形的IP。如果你用整形來存放,只需要4個字節,并且你可以有定長的字段。而且,這會為你帶來查詢上的優勢,尤其是當你需要使用這樣的WHERE條件:IP between ip1 and ip2。?
我們必需要使用UNSIGNED INT,因為 IP地址會使用整個32位的無符號整形。?
而你的查詢,你可以使用 INET_ATON() 來把一個字符串IP轉成一個整形,并使用 INET_NTOA() 把一個整形轉成一個字符串IP。在PHP中,也有這樣的函數 ip2long() 和 long2ip()。?
1 $r = "UPDATE users SET ip = INET_ATON('{$_SERVER['REMOTE_ADDR']}') WHERE user_id = $user_id";?
15. 固定長度的表會更快?
如果表中的所有字段都是“固定長度”的,整個表會被認為是 “static” 或 “fixed-length”。 例如,表中沒有如下類型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一個這些字段,那么這個表就不是“固定長度靜態表”了,這樣,MySQL 引擎會用另一種方法來處理。?
固定長度的表會提高性能,因為MySQL搜尋得會更快一些,因為這些固定的長度是很容易計算下一個數據的偏移量的,所以讀取的自然也會很快。而如果字段不是定長的,那么,每一次要找下一條的話,需要程序找到主鍵。?
并且,固定長度的表也更容易被緩存和重建。不過,唯一的副作用是,固定長度的字段會浪費一些空間,因為定長的字段無論你用不用,他都是要分配那么多的空間。?
使用“垂直分割”技術(見下一條),你可以分割你的表成為兩個一個是定長的,一個則是不定長的。?
16. 垂直分割?
“垂直分割”是一種把數據庫中的表按列變成幾張表的方法,這樣可以降低表的復雜度和字段的數目,從而達到優化的目的。(以前,在銀行做過項目,見過一張表有100多個字段,很恐怖)?
示例一:在Users表中有一個字段是家庭地址,這個字段是可選字段,相比起,而且你在數據庫操作的時候除了個人信息外,你并不需要經常讀取或是改寫這個字段。那么,為什么不把他放到另外一張表中呢? 這樣會讓你的表有更好的性能,大家想想是不是,大量的時候,我對于用戶表來說,只有用戶ID,用戶名,口令,用戶角色等會被經常使用。小一點的表總是會有好的性能。?
示例二: 你有一個叫 “last_login” 的字段,它會在每次用戶登錄時被更新。但是,每次更新時會導致該表的查詢緩存被清空。所以,你可以把這個字段放到另一個表中,這樣就不會影響你對用戶 ID,用戶名,用戶角色的不停地讀取了,因為查詢緩存會幫你增加很多性能。?
另外,你需要注意的是,這些被分出去的字段所形成的表,你不會經常性地去Join他們,不然的話,這樣的性能會比不分割時還要差,而且,會是極數級的下降。?
17. 拆分大的 DELETE 或 INSERT 語句?
如果你需要在一個在線的網站上去執行一個大的 DELETE 或 INSERT 查詢,你需要非常小心,要避免你的操作讓你的整個網站停止相應。因為這兩個操作是會鎖表的,表一鎖住了,別的操作都進不來了。?
Apache 會有很多的子進程或線程。所以,其工作起來相當有效率,而我們的服務器也不希望有太多的子進程,線程和數據庫鏈接,這是極大的占服務器資源的事情,尤其是內存。?
如果你把你的表鎖上一段時間,比如30秒鐘,那么對于一個有很高訪問量的站點來說,這30秒所積累的訪問進程/線程,數據庫鏈接,打開的文件數,可能不僅僅會讓你泊WEB服務Crash,還可能會讓你的整臺服務器馬上掛了。?
所以,如果你有一個大的處理,你定你一定把其拆分,使用 LIMIT 條件是一個好的方法。下面是一個示例:
復制代碼 代碼如下:
while (1) {?
//每次只做1000條?
mysql_query("DELETE FROM logs WHERE log_date <= '2009-11-01' LIMIT 1000");?
if (mysql_affected_rows() == 0) {?
// 沒得可刪了,退出!?
break;?
}?
// 每次都要休息一會兒?
usleep(50000);?
}
18. 越小的列會越快?
對于大多數的數據庫引擎來說,硬盤操作可能是最重大的瓶頸。所以,把你的數據變得緊湊會對這種情況非常有幫助,因為這減少了對硬盤的訪問。?
參看 MySQL 的文檔 Storage Requirements 查看所有的數據類型。?
如果一個表只會有幾列罷了(比如說字典表,配置表),那么,我們就沒有理由使用 INT 來做主鍵,使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 會更經濟一些。如果你不需要記錄時間,使用 DATE 要比 DATETIME 好得多。?
當然,你也需要留夠足夠的擴展空間,不然,你日后來干這個事,你會死的很難看,參看Slashdot的例子(2009年11月06 日),一個簡單的ALTER TABLE語句花了3個多小時,因為里面有一千六百萬條數據。?
19. 選擇正確的存儲引擎?
在 MySQL 中有兩個存儲引擎 MyISAM 和 InnoDB,每個引擎都有利有弊。酷殼以前文章《MySQL: InnoDB 還是 MyISAM?》討論和這個事情。?
MyISAM 適合于一些需要大量查詢的應用,但其對于有大量寫操作并不是很好。甚至你只是需要update一個字段,整個表都會被鎖起來,而別的進程,就算是讀進程都無法操作直到讀操作完成。另外,MyISAM 對于 SELECT COUNT(*) 這類的計算是超快無比的。?
InnoDB 的趨勢會是一個非常復雜的存儲引擎,對于一些小的應用,它會比 MyISAM 還慢。他是它支持“行鎖” ,于是在寫操作比較多的時候,會更優秀。并且,他還支持更多的高級應用,比如:事務。?
下面是MySQL的手冊?
* target=”_blank”MyISAM Storage Engine?
* InnoDB Storage Engine?
20. 使用一個對象關系映射器(Object Relational Mapper)?
使用 ORM (Object Relational Mapper),你能夠獲得可靠的性能增漲。一個ORM可以做的所有事情,也能被手動的編寫出來。但是,這需要一個高級專家。?
ORM 的最重要的是“Lazy Loading”,也就是說,只有在需要的去取值的時候才會去真正的去做。但你也需要小心這種機制的副作用,因為這很有可能會因為要去創建很多很多小的查詢反而會降低性能。?
ORM 還可以把你的SQL語句打包成一個事務,這會比單獨執行他們快得多得多。?
目前,個人最喜歡的PHP的ORM是:Doctrine。?
21. 小心“永久鏈接”?
“永久鏈接”的目的是用來減少重新創建MySQL鏈接的次數。當一個鏈接被創建了,它會永遠處在連接的狀態,就算是數據庫操作已經結束了。而且,自從我們的Apache開始重用它的子進程后——也就是說,下一次的HTTP請求會重用Apache的子進程,并重用相同的 MySQL 鏈接。?
* PHP手冊:mysql_pconnect()?
在理論上來說,這聽起來非常的不錯。但是從個人經驗(也是大多數人的)上來說,這個功能制造出來的麻煩事更多。因為,你只有有限的鏈接數,內存問題,文件句柄數,等等。?
而且,Apache 運行在極端并行的環境中,會創建很多很多的了進程。這就是為什么這種“永久鏈接”的機制工作地不好的原因。在你決定要使用“永久鏈接”之前,你需要好好地考慮一下你的整個系統的架構。
========
MySQL性能優化總結
http://www.cnblogs.com/luxiaoxun/p/4694144.html一、MySQL的主要適用場景
1、Web網站系統
2、日志記錄系統
3、數據倉庫系統
4、嵌入式系統
二、MySQL架構圖:
三、MySQL存儲引擎概述
1)MyISAM存儲引擎
MyISAM存儲引擎的表在數據庫中,每一個表都被存放為三個以表名命名的物理文件。首先肯定會有任何存儲引擎都不可缺少的存放表結構定義信息的.frm文件,另外還有.MYD和.MYI文件,分別存放了表的數據(.MYD)和索引數據(.MYI)。每個表都有且僅有這樣三個文件做為MyISAM存儲類型的表的存儲,也就是說不管這個表有多少個索引,都是存放在同一個.MYI文件中。
MyISAM支持以下三種類型的索引:
1、B-Tree索引
B-Tree索引,顧名思義,就是所有的索引節點都按照balancetree的數據結構來存儲,所有的索引數據節點都在葉節點。
2、R-Tree索引
R-Tree索引的存儲方式和b-tree索引有一些區別,主要設計用于為存儲空間和多維數據的字段做索引,所以目前的MySQL版本來說,也僅支持geometry類型的字段作索引。
3、Full-text索引
Full-text索引就是我們長說的全文索引,他的存儲結構也是b-tree。主要是為了解決在我們需要用like查詢的低效問題。
2)Innodb 存儲引擎
1、支持事務安裝
2、數據多版本讀取
3、鎖定機制的改進
4、實現外鍵
3)NDBCluster存儲引擎
NDB存儲引擎也叫NDBCluster存儲引擎,主要用于MySQLCluster分布式集群環境,Cluster是MySQL從5.0版本才開始提供的新功能。
4)Merge存儲引擎
MERGE存儲引擎,在MySQL用戶手冊中也提到了,也被大家認識為MRG_MyISAM引擎。Why?因為MERGE存儲引擎可以簡單的理解為其功能就是實現了對結構相同的MyISAM表,通過一些特殊的包裝對外提供一個單一的訪問入口,以達到減小應用的復雜度的目的。要創建MERGE表,不僅僅基表的結構要完全一致,包括字段的順序,基表的索引也必須完全一致。
5)Memory存儲引擎
Memory存儲引擎,通過名字就很容易讓人知道,他是一個將數據存儲在內存中的存儲引擎。Memory存儲引擎不會將任何數據存放到磁盤上,僅僅存放了一個表結構相關信息的.frm文件在磁盤上面。所以一旦MySQLCrash或者主機Crash之后,Memory的表就只剩下一個結構了。Memory表支持索引,并且同時支持Hash和B-Tree兩種格式的索引。由于是存放在內存中,所以Memory都是按照定長的空間來存儲數據的,而且不支持BLOB和TEXT類型的字段。Memory存儲引擎實現頁級鎖定。
6)BDB存儲引擎
BDB存儲引擎全稱為BerkeleyDB存儲引擎,和Innodb一樣,也不是MySQL自己開發實現的一個存儲引擎,而是由SleepycatSoftware所提供,當然,也是開源存儲引擎,同樣支持事務安全。
7)FEDERATED存儲引擎
FEDERATED存儲引擎所實現的功能,和Oracle的DBLINK基本相似,主要用來提供對遠程MySQL服務器上面的數據的訪問接口。如果我們使用源碼編譯來安裝MySQL,那么必須手工指定啟用FEDERATED存儲引擎才行,因為MySQL默認是不起用該存儲引擎的。
8)ARCHIVE存儲引擎
ARCHIVE存儲引擎主要用于通過較小的存儲空間來存放過期的很少訪問的歷史數據。ARCHIVE表不支持索引,通過一個.frm的結構定義文件,一個.ARZ的數據壓縮文件還有一個.ARM的meta信息文件。由于其所存放的數據的特殊性,ARCHIVE表不支持刪除,修改操
作,僅支持插入和查詢操作。鎖定機制為行級鎖定。
9)BLACKHOLE存儲引擎
BLACKHOLE存儲引擎是一個非常有意思的存儲引擎,功能恰如其名,就是一個“黑洞”。就像我們unix系統下面的“/dev/null”設備一樣,不管我們寫入任何信息,都是有去無回。
10)CSV存儲引擎
CSV存儲引擎實際上操作的就是一個標準的CSV文件,他不支持索引。起主要用途就是大家有些時候可能會需要通過數據庫中的數據導出成一份報表文件,而CSV文件是很多軟件都支持的一種較為標準的格式,所以我們可以通過先在數據庫中建立一張CVS表,然后將生成的報表信息插入到該表,即可得到一份CSV報表文件了。
四、影響MySQLServer性能的相關因素
1商業需求對性能的影響
典型需求:一個論壇帖子總量的統計,要求:實時更新。
2系統架構及實現對性能的影響
以下幾類數據都是不適合在數據庫中存放的:
二進制多媒體數據
流水隊列數據
超大文本數據
通過Cache技術來提高系統性能:
系統各種配置及規則數據;
活躍用戶的基本信息數據;
活躍用戶的個性化定制信息數據;
準實時的統計信息數據;
其他一些訪問頻繁但變更較少的數據;
3 Query語句對系統性能的影響
需求:取出某個group(假設id為1)下的用戶編號(id),用戶昵稱(nick_name),并按照加入組的時間(user_group.gmt_create)來進行倒序排列,取出前20個。
解決方案一:
SELECT id,nick_name FROM user,user_group WHERE user_group.group_id=1 and user_group.user_id=user.id ORDER BY user_group.gmt_create desc limit 100,20;
解決方案二:
復制代碼
SELECT user.id,user.nick_name FROM(
SELECT user_id
FROM user_group
WHERE user_group.group_id=1
ORDER BY gmt_create desc
limit 100,20)t,user
WHERE t.user_id=user.id;
復制代碼
通過比較兩個解決方案的執行計劃,我們可以看到第一中解決方案中需要和user表參與Join的記錄數MySQL通過統計數據估算出來是31156,也就是通過user_group表返回的所有滿足group_id=1的記錄數(系統中的實際數據是20000)。而第二種解決方案的執行計劃中,user表參與Join的數據就只有20條,兩者相差很大,我們認為第二中解決方案應該明顯優于第一種解決方案。
4 Schema設計對系統的性能影響
盡量減少對數據庫訪問的請求。
盡量減少無用數據的查詢請求。
5硬件環境對系統性能的影響
1、典型OLTP應用系統
對于各種數據庫系統環境中大家最常見的OLTP系統,其特點是并發量大,整體數據量比較多,但每次訪問的數據比較少,且訪問的數據比較離散,活躍數據占總體數據的比例不是太大。對于這類系統的數據庫實際上是最難維護,最難以優化的,對主機整體性能要求也是最高的。因為不僅訪問量很高,數據量也不小。
針對上面的這些特點和分析,我們可以對OLTP的得出一個大致的方向。
雖然系統總體數據量較大,但是系統活躍數據在數據總量中所占的比例不大,那么我們可以通過擴大內存容量來盡可能多的將活躍數據cache到內存中;
雖然IO訪問非常頻繁,但是每次訪問的數據量較少且很離散,那么我們對磁盤存儲的要求是IOPS表現要很好,吞吐量是次要因素;
并發量很高,CPU每秒所要處理的請求自然也就很多,所以CPU處理能力需要比較強勁;
雖然與客戶端的每次交互的數據量并不是特別大,但是網絡交互非常頻繁,所以主機與客戶端交互的網絡設備對流量能力也要求不能太弱。
2、典型OLAP應用系統
用于數據分析的OLAP系統的主要特點就是數據量非常大,并發訪問不多,但每次訪問所需要檢索的數據量都比較多,而且數據訪問相對較為集中,沒有太明顯的活躍數據概念。
基于OLAP系統的各種特點和相應的分析,針對OLAP系統硬件優化的大致策略如下:
數據量非常大,所以磁盤存儲系統的單位容量需要盡量大一些;
單次訪問數據量較大,而且訪問數據比較集中,那么對IO系統的性能要求是需要有盡可能大的每秒IO吞吐量,所以應該選用每秒吞吐量盡可能大的磁盤;
雖然IO性能要求也比較高,但是并發請求較少,所以CPU處理能力較難成為性能瓶頸,所以CPU處理能力沒有太苛刻的要求;
雖然每次請求的訪問量很大,但是執行過程中的數據大都不會返回給客戶端,最終返回給客戶端的數據量都較小,所以和客戶端交互的網絡設備要求并不是太高;
此外,由于OLAP系統由于其每次運算過程較長,可以很好的并行化,所以一般的OLAP系統都是由多臺主機構成的一個集群,而集群中主機與主機之間的數據交互量一般來說都是非常大的,所以在集群中主機之間的網絡設備要求很高。
3、除了以上兩個典型應用之外,還有一類比較特殊的應用系統,他們的數據量不是特別大,但是訪問請求及其頻繁,而且大部分是讀請求。可能每秒需要提供上萬甚至幾萬次請求,每次請求都非常簡單,可能大部分都只有一條或者幾條比較小的記錄返回,就比如基于數據庫的DNS服務就是這樣類型的服務。
雖然數據量小,但是訪問極其頻繁,所以可以通過較大的內存來cache住大部分的數據,這能夠保證非常高的命中率,磁盤IO量比較小,所以磁盤也不需要特別高性能的;
并發請求非常頻繁,比需要較強的CPU處理能力才能處理;
雖然應用與數據庫交互量非常大,但是每次交互數據較少,總體流量雖然也會較大,但是一般來說普通的千兆網卡已經足夠了。
五、MySQL 鎖定機制簡介
行級鎖定(row-level)
表級鎖定(table-level)
頁級鎖定(page-level)
在MySQL數據庫中,使用表級鎖定的主要是MyISAM,Memory,CSV等一些非事務性存儲引擎,而使用行級鎖定的主要是Innodb存儲引擎和NDBCluster存儲引擎,頁級鎖定主要是BerkeleyDB存儲引擎的鎖定方式。
六、MySQL Query的優化
Query語句的優化思路和原則主要提現在以下幾個方面:
1. 優化更需要優化的Query;
2. 定位優化對象的性能瓶頸;
3. 明確的優化目標;
4. 從Explain入手;
5. 多使用profile
6. 永遠用小結果集驅動大的結果集;
7. 盡可能在索引中完成排序;
8. 只取出自己需要的Columns;
9. 僅僅使用最有效的過濾條件;
10.盡可能避免復雜的Join和子查詢;
合理設計并利用索引
1)B-Tree索引
一般來說,MySQL中的B-Tree索引的物理文件大多都是以BalanceTree的結構來存儲的,也就是所有實際需要的數據都存放于Tree的LeafNode,而且到任何一個LeafNode的最短路徑的長度都是完全相同的,所以我們大家都稱之為B-Tree索引當然,可能各種數據庫(或MySQL的各種存儲引擎)在存放自己的B-Tree索引的時候會對存儲結構稍作改造。如Innodb存儲引擎的B-Tree索引實際使用的存儲結構實際上是B+Tree,也就是在B-Tree數據結構的基礎上做了很小的改造,在每一個LeafNode上面出了存放索引鍵的相關信息之外,還存儲了指向與該LeafNode相鄰的后一個LeafNode的指針信息,這主要是為了加快檢索多個相鄰LeafNode的效率考慮。
2)Hash索引
Hash索引在MySQL中使用的并不是很多,目前主要是Memory存儲引擎使用,而且在Memory存儲引擎中將Hash索引作為默認的索引類型。所謂Hash索引,實際上就是通過一定的Hash算法,將需要索引的鍵值進行Hash運算,然后將得到的Hash值存入一個Hash表中。然后每次需要檢索的時候,都會將檢索條件進行相同算法的Hash運算,然后再和Hash表中的Hash值進行比較并得出相應的信息。
Hash索引僅僅只能滿足“=”,“IN”和“<=>”查詢,不能使用范圍查詢;
Hash索引無法被利用來避免數據的排序操作;
Hash索引不能利用部分索引鍵查詢;
Hash索引在任何時候都不能避免表掃面;
Hash索引遇到大量Hash值相等的情況后性能并不一定就會比B-Tree索引高;
3)Full-text索引
Full-text索引也就是我們常說的全文索引,目前在MySQL中僅有MyISAM存儲引擎支持,而且也并不是所有的數據類型都支持全文索引。目前來說,僅有CHAR,VARCHAR和TEXT這三種數據類型的列可以建Full-text索引。
索引能夠極大的提高數據檢索效率,也能夠改善排序分組操作的性能,但是我們不能忽略的一個問題就是索引是完全獨立于基礎數據之外的一部分數據,更新數據會帶來的IO量和調整索引所致的計算量的資源消耗。
是否需要創建索引,幾點原則:較頻繁的作為查詢條件的字段應該創建索引;唯一性太差的字段不適合單獨創建索引,即使頻繁作為查詢條件;更新非常頻繁的字段不適合創建索引;
不會出現在WHERE子句中的字段不該創建索引;
Join語句的優化
盡可能減少Join語句中的NestedLoop的循環總次數;“永遠用小結果集驅動大的結果集”。
優先優化NestedLoop的內層循環;
保證Join語句中被驅動表上Join條件字段已經被索引;
當無法保證被驅動表的Join條件字段被索引且內存資源充足的前提下,不要太吝惜JoinBuffer的設置;
ORDER BY,GROUP BY和DISTINCT優化
1)ORDER BY的實現與優化
優化Query語句中的ORDER BY的時候,盡可能利用已有的索引來避免實際的排序計算,可以很大幅度的提升ORDER BY操作的性能。
優化排序:
1.加大max_length_for_sort_data參數的設置;
2.去掉不必要的返回字段;
3.增大sort_buffer_size參數設置;
2)GROUP BY的實現與優化
由于GROUP BY實際上也同樣需要進行排序操作,而且與ORDER BY相比,GROUP BY主要只是多了排序之后的分組操作。當然,如果在分組的時候還使用了其他的一些聚合函數,那么還需要一些聚合函數的計算。所以,在GROUP BY的實現過程中,與ORDER BY一樣也可以利用到索引。
3)DISTINCT的實現與優化
DISTINCT實際上和GROUP BY的操作非常相似,只不過是在GROUP BY之后的每組中只取出一條記錄而已。所以,DISTINCT的實現和GROUP BY的實現也基本差不多,沒有太大的區別。同樣可以通過松散索引掃描或者是緊湊索引掃描來實現,當然,在無法僅僅使用索引即能完成DISTINCT的時候,MySQL只能通過臨時表來完成。但是,和GROUP BY有一點差別的是,DISTINCT并不需要進行排序。也就是說,在僅僅只是DISTINCT操作的Query如果無法僅僅利用索引完成操作的時候,MySQL會利用臨時表來做一次數據的“緩存”,但是不會對臨時表中的數據進行filesort操作。
七、MySQL數據庫Schema設計的性能優化
高效的模型設計
適度冗余-讓Query盡兩減少Join
大字段垂直分拆-summary表優化
大表水平分拆-基于類型的分拆優化
統計表-準實時優化
合適的數據類型
時間存儲格式總類并不是太多,我們常用的主要就是DATETIME,DATE和TIMESTAMP這三種了。從存儲空間來看TIMESTAMP最少,四個字節,而其他兩種數據類型都是八個字節,多了一倍。而TIMESTAMP的缺點在于他只能存儲從1970年之后的時間,而另外兩種時間類型可以存放最早從1001年開始的時間。如果有需要存放早于1970年之前的時間的需求,我們必須放棄TIMESTAMP類型,但是只要我們不需要使用1970年之前的時間,最好盡量使用TIMESTAMP來減少存儲空間的占用。
字符存儲類型
CHAR[(M)]類型屬于靜態長度類型,存放長度完全以字符數來計算,所以最終的存儲長度是基于字符集的,如latin1則最大存儲長度為255字節,但是如果使用gbk則最大存儲長度為510字節。CHAR類型的存儲特點是不管我們實際存放多長數據,在數據庫中都會存放M個字符,不夠的通過空格補上,M默認為1。雖然CHAR會通過空格補齊存放的空間,但是在訪問數據的時候,MySQL會忽略最后的所有空格,所以如果我們的實際數據中如果在最后確實需要空格,則不能使用CHAR類型來存放。
VARCHAR[(M)]屬于動態存儲長度類型,僅存占用實際存儲數據的長度。TINYTEXT,TEXT,MEDIUMTEXT和LONGTEXT這四種類型同屬于一種存儲方式,都是動態存儲長度類型,不同的僅僅是最大長度的限制。
事務優化
1. 臟讀:臟讀就是指當一個事務正在訪問數據,并且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時,另外一個事務也訪問這個數據,然后使用了這個數據。
2. 不可重復讀:是指在一個事務內,多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該同一數據。那么,在第一個事務中的兩次讀數據之間,由于第二個事務的修改,那么第一個事務兩次讀到的的數據可能是不一樣的。這樣就發生了在一個事務內兩次讀到的數據是不一樣的,因此稱為是不可重復讀。
3. 幻讀:是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那么,以后就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。
Innodb在事務隔離級別方面支持的信息如下:
1.READ UNCOMMITTED
常被成為Dirty Reads(臟讀),可以說是事務上的最低隔離級別:在普通的非鎖定模式下SELECT的執行使我們看到的數據可能并不是查詢發起時間點的數據,因而在這個隔離度下是非Consistent Reads(一致性讀);
2.READ COMMITTED
這一隔離級別下,不會出現DirtyRead,但是可能出現Non-RepeatableReads(不可重復讀)和PhantomReads(幻讀)。
3. REPEATABLE READ
REPEATABLE READ隔離級別是InnoDB默認的事務隔離級。在REPEATABLE READ隔離級別下,不會出現DirtyReads,也不會出現Non-Repeatable Read,但是仍然存在PhantomReads的可能性。
4.SERIALIZABLE
SERIALIZABLE隔離級別是標準事務隔離級別中的最高級別。設置為SERIALIZABLE隔離級別之后,在事務中的任何時候所看到的數據都是事務啟動時刻的狀態,不論在這期間有沒有其他事務已經修改了某些數據并提交。所以,SERIALIZABLE事務隔離級別下,PhantomReads也不會出現。
八、可擴展性設計之數據切分
數據的垂直切分
數據的垂直切分,也可以稱之為縱向切分。將數據庫想象成為由很多個一大塊一大塊的“數據塊”(表)組成,我們垂直的將這些“數據塊”切開,然后將他們分散到多臺數據庫主機上面。這樣的切分方法就是一個垂直(縱向)的數據切分。
垂直切分的優點
◆數據庫的拆分簡單明了,拆分規則明確;
◆應用程序模塊清晰明確,整合容易;
◆數據維護方便易行,容易定位;
垂直切分的缺點
◆部分表關聯無法在數據庫級別完成,需要在程序中完成;
◆對于訪問極其頻繁且數據量超大的表仍然存在性能平靜,不一定能滿足要求;
◆事務處理相對更為復雜;
◆切分達到一定程度之后,擴展性會遇到限制;
◆過讀切分可能會帶來系統過渡復雜而難以維護。
數據的水平切分
數據的垂直切分基本上可以簡單的理解為按照表按照模塊來切分數據,而水平切分就不再是按照表或者是功能模塊來切分了。一般來說,簡單的水平切分主要是將某個訪問極其平凡的表再按照某個字段的某種規則來分散到多個表之中,每個表中包含一部分數據。
水平切分的優點
◆表關聯基本能夠在數據庫端全部完成;
◆不會存在某些超大型數據量和高負載的表遇到瓶頸的問題;
◆應用程序端整體架構改動相對較少;
◆事務處理相對簡單;
◆只要切分規則能夠定義好,基本上較難遇到擴展性限制;
水平切分的缺點
◆切分規則相對更為復雜,很難抽象出一個能夠滿足整個數據庫的切分規則;
◆后期數據的維護難度有所增加,人為手工定位數據更困難;
◆應用系統各模塊耦合度較高,可能會對后面數據的遷移拆分造成一定的困難。
數據切分與整合中可能存在的問題
1.引入分布式事務的問題
完全可以將一個跨多個數據庫的分布式事務分拆成多個僅處于單個數據庫上面的小事務,并通過應用程序來總控各個小事務。當然,這樣作的要求就是我們的俄應用程序必須要有足夠的健壯性,當然也會給應用程序帶來一些技術難度。
2.跨節點Join的問題
推薦通過應用程序來進行處理,先在驅動表所在的MySQLServer中取出相應的驅動結果集,然后根據驅動結果集再到被驅動表所在的MySQL Server中取出相應的數據。
3.跨節點合并排序分頁問題
從多個數據源并行的取數據,然后應用程序匯總處理。
九、可擴展性設計之Cache與Search的利用
通過引入Cache(Redis、Memcached),減少數據庫的訪問,增加性能。
通過引入Search(Lucene、Solr、ElasticSearch),利用搜索引擎高效的全文索引和分詞算法,以及高效的數據檢索實現,來解決數據庫和傳統的Cache軟件完全無法解決的全文模糊搜索、分類統計查詢等功能。
本文乃《MySQL性能調優與架構設計》讀書筆記
========
MySQL 調優/優化的 100 個建議
http://blog.jobbole.com/87989/MySQL是一個強大的開源數據庫。隨著MySQL上的應用越來越多,MySQL逐漸遇到了瓶頸。這里提供 101 條優化 MySQL 的建議。有些技巧適合特定的安裝環境,但是思路是相通的。我已經將它們分成了幾類以幫助你理解。
MySQL監控
MySQL服務器硬件和OS(操作系統)調優:
1、有足夠的物理內存,能將整個InnoDB文件加載到內存里 —— 如果訪問的文件在內存里,而不是在磁盤上,InnoDB會快很多。
2、全力避免 Swap 操作 — 交換(swapping)是從磁盤讀取數據,所以會很慢。
3、使用電池供電的RAM(Battery-Backed RAM)。
4、使用一個高級磁盤陣列 — 最好是 RAID10 或者更高。
5、避免使用RAID5 — 和校驗需要確保完整性,開銷很高。
6、將你的操作系統和數據分開,不僅僅是邏輯上要分開,物理上也要分開 — 操作系統的讀寫開銷會影響數據庫的性能。
7、將臨時文件和復制日志與數據文件分開 — 后臺的寫操作影響數據庫從磁盤文件的讀寫操作。
8、更多的磁盤空間等于更高的速度。
9、磁盤速度越快越好。
10、SAS優于SATA。
11、小磁盤的速度比大磁盤的更快,尤其是在 RAID 中。
12、使用電池供電的緩存 RAID(Battery-Backed Cache RAID)控制器。
13、避免使用軟磁盤陣列。
14. 考慮使用固態IO卡(不是磁盤)來作為數據分區 — 幾乎對所有量級數據,這種卡能夠支持 2 GBps 的寫操作。
15、在 Linux 系統上,設置 swappiness 的值為0 — 沒有理由在數據庫服務器上緩存文件,這種方式在Web服務器或桌面應用中用的更多。
16、盡可能使用 noatime 和 nodirtime 來掛載文件系統 — 沒有必要為每次訪問來更新文件的修改時間。
17、使用 XFS 文件系統 — 一個比ext3更快的、更小的文件系統,擁有更多的日志選項,同時,MySQL在ext3上存在雙緩沖區的問題。
18、優化你的 XFS 文件系統日志和緩沖區參數 – -為了獲取最大的性能基準。
19、在Linux系統中,使用 NOOP 或 DEADLINE IO 調度器 — CFQ 和 ANTICIPATORY 調度器已經被證明比 NOOP 和 DEADLINE 慢。
20、使用 64 位操作系統 — 有更多的內存能用于尋址和 MySQL 使用。
21、將不用的包和后臺程序從服務器上刪除 — 減少資源占用。
22、將使用 MySQL 的 host 和 MySQL自身的 host 都配置在一個 host 文件中 — 這樣沒有 DNS 查找。
23、永遠不要強制殺死一個MySQL進程 — 你將損壞數據庫,并運行備份。
24、讓你的服務器只服務于MySQL — 后臺處理程序和其他服務會占用數據庫的 CPU 時間。
MySQL 配置:
25、使用 innodb_flush_method=O_DIRECT 來避免寫的時候出現雙緩沖區。
26、避免使用 O_DIRECT 和 EXT3 文件系統 — 這會把所有寫入的東西序列化。
27、分配足夠 innodb_buffer_pool_size ,來將整個InnoDB 文件加載到內存 — 減少從磁盤上讀。
28、不要讓 innodb_log_file_size 太大,這樣能夠更快,也有更多的磁盤空間 — 經常刷新有利降低發生故障時的恢復時間。
29、不要同時使用 innodb_thread_concurrency 和 thread_concurrency 變量 — 這兩個值不能兼容。
30、為 max_connections 指定一個小的值 — 太多的連接將耗盡你的RAM,導致整個MySQL服務器被鎖定。
31、保持 thread_cache 在一個相對較高的數值,大約是 16 — 防止打開連接時候速度下降。
32、使用 skip-name-resolve — 移除 DNS 查找。
33、如果你的查詢重復率比較高,并且你的數據不是經常改變,請使用查詢緩存 — 但是,在經常改變的數據上使用查詢緩存會對性能有負面影響。
34、增加 temp_table_size — 防止磁盤寫。
35、增加 max_heap_table_size — 防止磁盤寫。
36、不要將 sort_buffer_size 的值設置的太高 — 可能導致連接很快耗盡所有內存。
37、監控 key_read_requests 和 key_reads,以便確定 key_buffer 的值 — key 的讀需求應該比 key_reads 的值更高,否則使用 key_buffer 就沒有效率了。
38、設置 innodb_flush_log_at_trx_commit = 0 可以提高性能,但是保持默認值(1)的話,能保證數據的完整性,也能保證復制不會滯后。
39、有一個測試環境,便于測試你的配置,可以經常重啟,不會影響生產環境。
MySQL Schema 優化:
40、保證你的數據庫的整潔性。
41、歸檔老數據 — 刪除查詢中檢索或返回的多余的行
42、在數據上加上索引。
43、不要過度使用索引,評估你的查詢。
44、壓縮 text 和 blob 數據類型 — 為了節省空間,減少從磁盤讀數據。
45、UTF 8 和 UTF16 比 latin1 慢。
46、有節制的使用觸發器。
47、保持數據最小量的冗余 — 不要復制沒必要的數據.
48、使用鏈接表,而不是擴展行。
49、注意你的數據類型,盡可能的使用最小的。
50、如果其他數據需要經常需要查詢,而 blob/text 不需要,則將 blob/text 數據域其他數據分離。
51、經常檢查和優化表。
52、經常做重寫 InnoDB 表的優化。
53、有時,增加列時,先刪除索引,之后在加上索引會更快。
54、為不同的需求選擇不同的存儲引擎。
55、日志表或審計表使用ARCHIVE存儲引擎 — 寫的效率更高。
56、將 session 數據存儲在 memcache 中,而不是 MySQL 中 — memcache 可以設置自動過期,防止MySQL對臨時數據高成本的讀寫操作。
57、如果字符串的長度是可變的,則使用VARCHAR代替CHAR — 節約空間,因為CHAR是固定長度,而VARCHAR不是(utf8 不受這個影響)。
58、逐步對 schema 做修改 — 一個小的變化將產生的巨大的影響。
59、在開發環境測試所有 schema 變動,而不是在生產環境的鏡像上去做。
60、不要隨意改變你的配置文件,這可能產生非常大的影響。
61、有時候,少量的配置會更好。
62、質疑使用通用的MySQL配置文件。
查詢優化:
63、使用慢查詢日志,找出執行慢的查詢。
64、使用 EXPLAIN 來決定查詢功能是否合適。
65、經常測試你的查詢,看是否需要做性能優化 — 性能可能會隨著時間的變化而變化。
66、避免在整個表上使用count(*) ,它可能會將整個表鎖住。
67、保持查詢一致,這樣后續類似的查詢就能使用查詢緩存了。
68、如果合適,用 GROUP BY 代替 DISTINCT。
69、在 WHERE、GROUP BY 和 ORDER BY 的列上加上索引。
70、保證索引簡單,不要在同一列上加多個索引。
71、有時,MySQL 會選擇錯誤的索引,這種情況使用 USE INDEX。
72、使用 SQL_MODE=STRICT 來檢查問題。
73、索引字段少于5個時,UNION 操作用 LIMIT,而不是 OR。
74、使用 INSERT ON DUPLICATE KEY 或 INSERT IGNORE 來代替 UPDATE,避免 UPDATE 前需要先 SELECT。
75、使用索引字段和 ORDER BY 來代替 MAX。
76、避免使用 ORDER BY RAND()。
77、LIMIT M,N 在特定場景下會降低查詢效率,有節制使用。
78、使用 UNION 來代替 WHERE 子句中的子查詢。
79、對 UPDATE 來說,使用 SHARE MODE 來防止排他鎖。
80、重啟 MySQL 時,記得預熱數據庫,確保將數據加載到內存,提高查詢效率。
81、使用 DROP TABLE ,然后再 CREATE TABLE ,而不是 DELETE FROM ,以刪除表中所有數據。
82、最小化你要查詢的數據,只獲取你需要的數據,通常來說不要使用 *。
83、考慮持久連接,而不是多次建立連接,已減少資源的消耗。
84、基準查詢,包括服務器的負載,有時一個簡單的查詢會影響其他的查詢。
85、當服務器的負載增加時,使用SHOW PROCESSLIST來查看慢的/有問題的查詢。
86、在存有生產環境數據副本的開發環境中,測試所有可疑的查詢。
MySQL備份過程:
87、在二級復制服務器上進行備份。
88、備份過程中停止數據的復制,以防止出現數據依賴和外鍵約束的不一致。
89、徹底停止MySQL之后,再從數據文件進行備份。
90、如果使用MySQL dump進行備份,請同時備份二進制日志 — 確保復制過程不被中斷。
91、不要信任 LVM 快照的備份 — 可能會創建不一致的數據,將來會因此產生問題。
92、為每個表做一個備份,這樣更容易實現單表的恢復 — 如果數據與其他表是相互獨立的。
93、使用 mysqldump 時,指定 -opt 參數。
94、備份前檢測和優化表。
95、臨時禁用外鍵約束,來提高導入的速度。
96、臨時禁用唯一性檢查,來提高導入的速度。
97、每次備份完后,計算數據庫/表數據和索引的大小,監控其增長。
98、使用定時任務(cron)腳本,來監控從庫復制的錯誤和延遲。
99、定期備份數據。
100、定期測試備份的數據。
========
mysql性能優化-慢查詢分析、優化索引和配置
http://blog.chinaunix.net/uid-11640640-id-3426908.html目錄
一、優化概述
二、查詢與索引優化分析
1性能瓶頸定位
Show命令
慢查詢日志
explain分析查詢
profiling分析查詢
2索引及查詢優化
三、配置優化
1) ? ? ?max_connections
2) ? ? ?back_log
3) ? ? ?interactive_timeout
4) ? ? ?key_buffer_size
5) ? ? ?query_cache_size
6) ? ? ?record_buffer_size
7) ? ? ?read_rnd_buffer_size
8) ? ? ?sort_buffer_size
9) ? ? ?join_buffer_size
10) ? ?table_cache
11) ? ?max_heap_table_size
12) ? ?tmp_table_size
13) ? ?thread_cache_size
14) ? ?thread_concurrency
15) ? ?wait_timeout
一、 優化概述
MySQL數據庫是常見的兩個瓶頸是CPU和I/O的瓶頸,CPU在飽和的時候一般發生在數據裝入內存或從磁盤上讀取數據時候。磁盤I/O瓶頸發生在裝入數據遠大于內存容量的時候,如果應用分布在網絡上,那么查詢量相當大的時候那么平瓶頸就會出現在網絡上,我們可以用mpstat, iostat, sar和vmstat來查看系統的性能狀態。
除了服務器硬件的性能瓶頸,對于MySQL系統本身,我們可以使用工具來優化數據庫的性能,通常有三種:使用索引,使用EXPLAIN分析查詢以及調整MySQL的內部配置。
二、查詢與索引優化分析
在優化MySQL時,通常需要對數據庫進行分析,常見的分析手段有慢查詢日志,EXPLAIN 分析查詢,profiling分析以及show命令查詢系統狀態及系統變量,通過定位分析性能的瓶頸,才能更好的優化數據庫系統的性能。
1 性能瓶頸定位Show命令
我們可以通過show命令查看MySQL狀態及變量,找到系統的瓶頸:
Mysql> show status ——顯示狀態信息(擴展show status like ‘XXX’)
Mysql> show variables ——顯示系統變量(擴展show variables like ‘XXX’)
Mysql> show innodb status ——顯示InnoDB存儲引擎的狀態
Mysql> show processlist ——查看當前SQL執行,包括執行狀態、是否鎖表等
Shell> mysqladmin variables -u username -p password——顯示系統變量
Shell> mysqladmin extended-status -u username -p password——顯示狀態信息
查看狀態變量及幫助:
Shell> mysqld –verbose –help [|more #逐行顯示]
比較全的Show命令的使用可參考: http://blog.phpbean.com/a.cn/18/
慢查詢日志
慢查詢日志開啟:
在配置文件my.cnf或my.ini中在[mysqld]一行下面加入兩個配置參數
log-slow-queries=/data/mysqldata/slow-query.log ? ? ? ? ??
long_query_time=2 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
注:log-slow-queries參數為慢查詢日志存放的位置,一般這個目錄要有mysql的運行帳號的可寫權限,一般都將這個目錄設置為mysql的數據存放目錄;
long_query_time=2中的2表示查詢超過兩秒才記錄;
在my.cnf或者my.ini中添加log-queries-not-using-indexes參數,表示記錄下沒有使用索引的查詢。
log-slow-queries=/data/mysqldata/slow-query.log ? ? ? ? ??
long_query_time=10 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
log-queries-not-using-indexes ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
慢查詢日志開啟方法二:
我們可以通過命令行設置變量來即時啟動慢日志查詢。由下圖可知慢日志沒有打開,slow_launch_time=# 表示如果建立線程花費了比這個值更長的時間,slow_launch_threads 計數器將增加
設置慢日志開啟
MySQL后可以查詢long_query_time 的值 。
為了方便測試,可以將修改慢查詢時間為5秒。
慢查詢分析mysqldumpslow
我們可以通過打開log文件查看得知哪些SQL執行效率低下
[root@localhost mysql]# more slow-query.log ? ? ? ? ? ? ? ? ? ? ? ? ? ?
# Time: 081026 19:46:34 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
# User@Host: root[root] @ localhost [] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
# Query_time: 11 Lock_time: 0 Rows_sent: 1 Rows_examined: 6552961 ? ? ? ?
select count(*) from t_user; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
從日志中,可以發現查詢時間超過5 秒的SQL,而小于5秒的沒有出現在此日志中。
如果慢查詢日志中記錄內容很多,可以使用mysqldumpslow工具(MySQL客戶端安裝自帶)來對慢查詢日志進行分類匯總。mysqldumpslow對日志文件進行了分類匯總,顯示匯總后摘要結果。
進入log的存放目錄,運行
[root@mysql_data]#mysqldumpslow ?slow-query.log ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
Reading mysql slow query log from slow-query.log ? ? ? ? ? ? ? ? ? ? ? ? ? ?
Count: 2 Time=11.00s (22s) Lock=0.00s (0s) Rows=1.0 (2), root[root]@mysql ? ?
select count(N) from t_user; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
mysqldumpslow命令
/path/mysqldumpslow -s c -t 10 /database/mysql/slow-query.log ? ? ? ? ? ? ? ? ? ? ?
這會輸出記錄次數最多的10條SQL語句,其中:
-s, 是表示按照何種方式排序,c、t、l、r分別是按照記錄次數、時間、查詢時間、返回的記錄數來排序,ac、at、al、ar,表示相應的倒敘;
-t, 是top n的意思,即為返回前面多少條的數據;
-g, 后邊可以寫一個正則匹配模式,大小寫不敏感的;
例如:
/path/mysqldumpslow -s r -t 10 /database/mysql/slow-log ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
得到返回記錄集最多的10個查詢。
/path/mysqldumpslow -s t -t 10 -g “left join” /database/mysql/slow-log ? ? ??
得到按照時間排序的前10條里面含有左連接的查詢語句。
使用mysqldumpslow命令可以非常明確的得到各種我們需要的查詢語句,對MySQL查詢語句的監控、分析、優化是MySQL優化非常重要的一步。開啟慢查詢日志后,由于日志記錄操作,在一定程度上會占用CPU資源影響mysql的性能,但是可以階段性開啟來定位性能瓶頸。
explain分析查詢
使用 EXPLAIN 關鍵字可以模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的。這可以幫你分析你的查詢語句或是表結構的性能瓶頸。通過explain命令可以得到:
– 表的讀取順序
– 數據讀取操作的操作類型
– 哪些索引可以使用
– 哪些索引被實際使用
– 表之間的引用
– 每張表有多少行被優化器查詢
EXPLAIN字段:
?Table:顯示這一行的數據是關于哪張表的
?possible_keys:顯示可能應用在這張表中的索引。如果為空,沒有可能的索引。可以為相關的域從WHERE語句中選擇一個合適的語句
?key:實際使用的索引。如果為NULL,則沒有使用索引。MYSQL很少會選擇優化不足的索引,此時可以在SELECT語句中使用USE INDEX(index)來強制使用一個索引或者用IGNORE INDEX(index)來強制忽略索引
?key_len:使用的索引的長度。在不損失精確性的情況下,長度越短越好
?ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數
?rows:MySQL認為必須檢索的用來返回請求數據的行數
?type:這是最重要的字段之一,顯示查詢使用了何種類型。從最好到最差的連接類型為system、const、eq_reg、ref、range、index和ALL
nsystem、const:可以將查詢的變量轉為常量. ?如id=1; id為 主鍵或唯一鍵.
neq_ref:訪問索引,返回某單一行的數據.(通常在聯接時出現,查詢使用的索引為主鍵或惟一鍵)
nref:訪問索引,返回某個值的數據.(可以返回多行) 通常使用=時發生
nrange:這個連接類型使用索引返回一個范圍中的行,比如使用>或<查找東西,并且該字段上建有索引時發生的情況(注:不一定好于index)
nindex:以索引的順序進行全表掃描,優點是不用排序,缺點是還要全表掃描
nALL:全表掃描,應該盡量避免
?Extra:關于MYSQL如何解析查詢的額外信息,主要有以下幾種
nusing index:只用到索引,可以避免訪問表.?
nusing where:使用到where來過慮數據. 不是所有的where clause都要顯示using where. 如以=方式訪問索引.
nusing tmporary:用到臨時表
nusing filesort:用到額外的排序. (當使用order by v1,而沒用到索引時,就會使用額外的排序)
nrange checked for eache record(index map:N):沒有好的索引.
profiling分析查詢
通過慢日志查詢可以知道哪些SQL語句執行效率低下,通過explain我們可以得知SQL語句的具體執行情況,索引使用等,還可以結合show命令查看執行狀態。
如果覺得explain的信息不夠詳細,可以同通過profiling命令得到更準確的SQL執行消耗系統資源的信息。
profiling默認是關閉的。可以通過以下語句查看
打開功能: mysql>set profiling=1; 執行需要測試的sql 語句:
mysql> show profiles\G; 可以得到被執行的SQL語句的時間和ID
mysql>show profile for query 1; 得到對應SQL語句執行的詳細信息
Show Profile命令格式:
SHOW PROFILE [type [, type] … ] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? [FOR QUERY n] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? [LIMIT row_count [OFFSET offset]] ? ? ? ? ? ? ? ? ? ? ? ? ? ??
type: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ALL ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? | BLOCK IO ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? | CONTEXT SWITCHES ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? | CPU ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? | IPC ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? | MEMORY ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? | PAGE FAULTS ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? | SOURCE ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? | SWAPS ? ? ? ? ? ? ? ?
以上的16rows是針對非常簡單的select語句的資源信息,對于較復雜的SQL語句,會有更多的行和字段,比如converting HEAP to MyISAM 、Copying to tmp table等等,由于以上的SQL語句不存在復雜的表操作,所以未顯示這些字段。通過profiling資源耗費信息,我們可以采取針對性的優化措施。
?
測試完畢以后 ,關閉參數:mysql> set profiling=0
2 ? ? 索引及查詢優化
?
索引的類型
? 普通索引:這是最基本的索引類型,沒唯一性之類的限制。
? 唯一性索引:和普通索引基本相同,但所有的索引列值保持唯一性。
? 主鍵:主鍵是一種唯一索引,但必須指定為”PRIMARY KEY”。
? 全文索引:MYSQL從3.23.23開始支持全文索引和全文檢索。在MYSQL中,全文索引的索引類型為FULLTEXT。全文索引可以在VARCHAR或者TEXT類型的列上創建。
大多數MySQL索引(PRIMARY KEY、UNIQUE、INDEX和FULLTEXT)使用B樹中存儲。空間列類型的索引使用R-樹,MEMORY表支持hash索引。
單列索引和多列索引(復合索引)
索引可以是單列索引,也可以是多列索引。對相關的列使用索引是提高SELECT操作性能的最佳途徑之一。
多列索引:
MySQL可以為多個列創建索引。一個索引可以包括15個列。對于某些列類型,可以索引列的左前綴,列的順序非常重要。
多列索引可以視為包含通過連接索引列的值而創建的值的排序的數組。一般來說,即使是限制最嚴格的單列索引,它的限制能力也遠遠低于多列索引。
最左前綴
多列索引有一個特點,即最左前綴(Leftmost Prefixing)。假如有一個多列索引為key(firstname lastname age),當搜索條件是以下各種列的組合和順序時,MySQL將使用該多列索引:
firstname,lastname,age
firstname,lastname
firstname
也就是說,相當于還建立了key(firstname lastname)和key(firstname)。
索引主要用于下面的操作:
? 快速找出匹配一個WHERE子句的行。
? 刪除行。當執行聯接時,從其它表檢索行。
? 對具體有索引的列key_col找出MAX()或MIN()值。由預處理器進行優化,檢查是否對索引中在key_col之前發生所有關鍵字元素使用了WHERE key_part_# = constant。在這種情況下,MySQL為每個MIN()或MAX()表達式執行一次關鍵字查找,并用常數替換它。如果所有表達式替換為常量,查詢立即返回。例如:
SELECT MIN(key2), MAX (key2) ?FROM tb WHERE key1=10;
? 如果對一個可用關鍵字的最左面的前綴進行了排序或分組(例如,ORDER BY key_part_1,key_part_2),排序或分組一個表。如果所有關鍵字元素后面有DESC,關鍵字以倒序被讀取。
? 在一些情況中,可以對一個查詢進行優化以便不用查詢數據行即可以檢索值。如果查詢只使用來自某個表的數字型并且構成某些關鍵字的最左面前綴的列,為了更快,可以從索引樹檢索出值。
SELECT key_part3 FROM tb WHERE key_part1=1
有時MySQL不使用索引,即使有可用的索引。一種情形是當優化器估計到使用索引將需要MySQL訪問表中的大部分行時。(在這種情況下,表掃描可能會更快些)。然而,如果此類查詢使用LIMIT只搜索部分行,MySQL則使用索引,因為它可以更快地找到幾行并在結果中返回。例如:
合理的建立索引的建議:
(1) ?越小的數據類型通常更好:越小的數據類型通常在磁盤、內存和CPU緩存中都需要更少的空間,處理起來更快。?
(2) ?簡單的數據類型更好:整型數據比起字符,處理開銷更小,因為字符串的比較更復雜。在MySQL中,應該用內置的日期和時間數據類型,而不是用字符串來存儲時間;以及用整型數據類型存儲IP地址。
(3) ?盡量避免NULL:應該指定列為NOT NULL,除非你想存儲NULL。在MySQL中,含有空值的列很難進行查詢優化,因為它們使得索引、索引的統計信息以及比較運算更加復雜。你應該用0、一個特殊的值或者一個空串代替空值
?
這部分是關于索引和寫SQL語句時應當注意的一些瑣碎建議和注意點。
1. 當結果集只有一行數據時使用LIMIT 1
2. 避免SELECT *,始終指定你需要的列
從表中讀取越多的數據,查詢會變得更慢。他增加了磁盤需要操作的時間,還是在數據庫服務器與WEB服務器是獨立分開的情況下。你將會經歷非常漫長的網絡延遲,僅僅是因為數據不必要的在服務器之間傳輸。
3. 使用連接(JOIN)來代替子查詢(Sub-Queries)
? ? ? ?連接(JOIN).. 之所以更有效率一些,是因為MySQL不需要在內存中創建臨時表來完成這個邏輯上的需要兩個步驟的查詢工作。
4. 使用ENUM、CHAR 而不是VARCHAR,使用合理的字段屬性長度
5. 盡可能的使用NOT NULL
6. 固定長度的表會更快
7. 拆分大的DELETE 或INSERT 語句
8. 查詢的列越小越快
?
?Where條件
在查詢中,WHERE條件也是一個比較重要的因素,盡量少并且是合理的where條件是很重要的,盡量在多個條件的時候,把會提取盡量少數據量的條件放在前面,減少后一個where條件的查詢時間。
有些where條件會導致索引無效:
? where子句的查詢條件里有!=,MySQL將無法使用索引。
? where子句使用了Mysql函數的時候,索引將無效,比如:select * from tb where left(name, 4) = ‘xxx’
? 使用LIKE進行搜索匹配的時候,這樣索引是有效的:select * from tbl1 where name like ‘xxx%’,而like ‘%xxx%’ 時索引無效
?
三、 ? ?配置優化
安裝MySQL后,配置文件my.cnf在 /MySQL安裝目錄/share/mysql目錄中,該目錄中還包含多個配置文件可供參考,有my-large.cnf ,my-huge.cnf, ?my-medium.cnf,my-small.cnf,分別對應大中小型數據庫應用的配置。win環境下即存在于MySQL安裝目錄中的.ini文件。
?
下面列出了對性能優化影響較大的主要變量,主要分為連接請求的變量和緩沖區變量。
1. ? 連接請求的變量:
1) ? ? max_connections
MySQL的最大連接數,增加該值增加mysqld 要求的文件描述符的數量。如果服務器的并發連接請求量比較大,建議調高此值,以增加并行連接數量,當然這建立在機器能支撐的情況下,因為如果連接數越多,介于MySQL會為每個連接提供連接緩沖區,就會開銷越多的內存,所以要適當調整該值,不能盲目提高設值。
數值過小會經常出現ERROR 1040: Too many connections錯誤,可以過’conn%’通配符查看當前狀態的連接數量,以定奪該值的大小。
show variables like ‘max_connections’ 最大連接數
show ?status like ‘max_used_connections’響應的連接數
如下:
mysql> show variables like ‘max_connections‘;
+———————–+——-+
| Variable_name | Value |
+———————–+——-+
| max_connections | 256 |
+———————–+——-+
mysql> show status like ‘max%connections‘;
+———————–+——-+
| Variable_name ? ? ?| Value |
+—————————-+——-+
| max_used_connections | 256|
+—————————-+——-+
max_used_connections / max_connections * 100% (理想值≈ 85%)?
如果max_used_connections跟max_connections相同 那么就是max_connections設置過低或者超過服務器負載上限了,低于10%則設置過大。
2) ? ? back_log
MySQL能暫存的連接數量。當主要MySQL線程在一個很短時間內得到非常多的連接請求,這就起作用。如果MySQL的連接數據達到max_connections時,新來的請求將會被存在堆棧中,以等待某一連接釋放資源,該堆棧的數量即back_log,如果等待連接的數量超過back_log,將不被授予連接資源。
back_log值指出在MySQL暫時停止回答新請求之前的短時間內有多少個請求可以被存在堆棧中。只有如果期望在一個短時間內有很多連接,你需要增加它,換句話說,這值對到來的TCP/IP連接的偵聽隊列的大小。
當觀察你主機進程列表(mysql> show full processlist),發現大量264084 | unauthenticated user | xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 的待連接進程時,就要加大back_log 的值了。
默認數值是50,可調優為128,對于Linux系統設置范圍為小于512的整數。?
3) ? ? interactive_timeout
一個交互連接在被服務器在關閉前等待行動的秒數。一個交互的客戶被定義為對mysql_real_connect()使用CLIENT_INTERACTIVE 選項的客戶。?
默認數值是28800,可調優為7200。?
2. ? 緩沖區變量
全局緩沖:
4) ? ? key_buffer_size
key_buffer_size指定索引緩沖區的大小,它決定索引處理的速度,尤其是索引讀的速度。通過檢查狀態值Key_read_requests和Key_reads,可以知道key_buffer_size設置是否合理。比例key_reads / key_read_requests應該盡可能的低,至少是1:100,1:1000更好(上述狀態值可以使用SHOW STATUS LIKE ‘key_read%’獲得)。
key_buffer_size只對MyISAM表起作用。即使你不使用MyISAM表,但是內部的臨時磁盤表是MyISAM表,也要使用該值。可以使用檢查狀態值created_tmp_disk_tables得知詳情。
舉例如下:
mysql> show variables like ‘key_buffer_size‘;
+——————-+————+
| Variable_name | Value ? ? ?|
+———————+————+
| key_buffer_size | 536870912 |
+———— ———-+————+
key_buffer_size為512MB,我們再看一下key_buffer_size的使用情況:
mysql> show global status like ‘key_read%‘;
+————————+————-+
| Variable_name ?| Value ? ?|
+————————+————-+
| Key_read_requests| 27813678764 |
| Key_reads | ?6798830 ? ? ?|
+————————+————-+
一共有27813678764個索引讀取請求,有6798830個請求在內存中沒有找到直接從硬盤讀取索引,計算索引未命中緩存的概率:
key_cache_miss_rate =Key_reads / Key_read_requests * 100%,設置在1/1000左右較好
默認配置數值是8388600(8M),主機有4GB內存,可以調優值為268435456(256MB)。
5) ? ? query_cache_size
使用查詢緩沖,MySQL將查詢結果存放在緩沖區中,今后對于同樣的SELECT語句(區分大小寫),將直接從緩沖區中讀取結果。
通過檢查狀態值Qcache_*,可以知道query_cache_size設置是否合理(上述狀態值可以使用SHOW STATUS LIKE ‘Qcache%’獲得)。如果Qcache_lowmem_prunes的值非常大,則表明經常出現緩沖不夠的情況,如果Qcache_hits的值也非常大,則表明查詢緩沖使用非常頻繁,此時需要增加緩沖大小;如果Qcache_hits的值不大,則表明你的查詢重復率很低,這種情況下使用查詢緩沖反而會影響效率,那么可以考慮不用查詢緩沖。此外,在SELECT語句中加入SQL_NO_CACHE可以明確表示不使用查詢緩沖。
?
與查詢緩沖有關的參數還有query_cache_type、query_cache_limit、query_cache_min_res_unit。
?
query_cache_type指定是否使用查詢緩沖,可以設置為0、1、2,該變量是SESSION級的變量。
query_cache_limit指定單個查詢能夠使用的緩沖區大小,缺省為1M。
query_cache_min_res_unit是在4.1版本以后引入的,它指定分配緩沖區空間的最小單位,缺省為4K。檢查狀態值Qcache_free_blocks,如果該值非常大,則表明緩沖區中碎片很多,這就表明查詢結果都比較小,此時需要減小query_cache_min_res_unit。
舉例如下:
mysql> show global status like ‘qcache%‘;
+——————————-+—————–+
| Variable_name ? ? ? ? ? ? ? ? ?| Value ? ? ? |
+——————————-+—————–+
| Qcache_free_blocks ? ? ? | 22756 ? ? ?|
| Qcache_free_memory ? ?| 76764704 ? ?|
| Qcache_hits ? ? ?| 213028692 |
| Qcache_inserts ? ? | 208894227 ? |
| Qcache_lowmem_prunes ? | 4010916 ? ? ?|
| Qcache_not_cached | 13385031 ? ?|
| Qcache_queries_in_cache | 43560 |
| Qcache_total_blocks ? ? ? ? ?| 111212 ? ? |
+——————————-+—————–+
mysql> show variables like ‘query_cache%‘;
+————————————–+————–+
| Variable_name ? ? ? | Value ? ? |
+————————————–+———–+
| query_cache_limit ? ?| 2097152 ? ? |
| query_cache_min_res_unit ? ? | 4096 ?|
| query_cache_size ? ?| 203423744 |
| query_cache_type ? | ON ? ? ? ? ?|
| query_cache_wlock_invalidate | OFF ?|
+————————————–+—————+
查詢緩存碎片率= Qcache_free_blocks / Qcache_total_blocks * 100%
如果查詢緩存碎片率超過20%,可以用FLUSH QUERY CACHE整理緩存碎片,或者試試減小query_cache_min_res_unit,如果你的查詢都是小數據量的話。
查詢緩存利用率= (query_cache_size – Qcache_free_memory) / query_cache_size * 100%
查詢緩存利用率在25%以下的話說明query_cache_size設置的過大,可適當減小;查詢緩存利用率在80%以上而且Qcache_lowmem_prunes > 50的話說明query_cache_size可能有點小,要不就是碎片太多。
查詢緩存命中率= (Qcache_hits – Qcache_inserts) / Qcache_hits * 100%
示例服務器查詢緩存碎片率=20.46%,查詢緩存利用率=62.26%,查詢緩存命中率=1.94%,命中率很差,可能寫操作比較頻繁吧,而且可能有些碎片。
每個連接的緩沖
6) ? ?record_buffer_size
每個進行一個順序掃描的線程為其掃描的每張表分配這個大小的一個緩沖區。如果你做很多順序掃描,你可能想要增加該值。
默認數值是131072(128K),可改為16773120 (16M)
7) ? ? read_rnd_buffer_size
隨機讀緩沖區大小。當按任意順序讀取行時(例如,按照排序順序),將分配一個隨機讀緩存區。進行排序查詢時,MySQL會首先掃描一遍該緩沖,以避免磁盤搜索,提高查詢速度,如果需要排序大量數據,可適當調高該值。但MySQL會為每個客戶連接發放該緩沖空間,所以應盡量適當設置該值,以避免內存開銷過大。
一般可設置為16M?
8) ? ? sort_buffer_size
每個需要進行排序的線程分配該大小的一個緩沖區。增加這值加速ORDER BY或GROUP BY操作。
默認數值是2097144(2M),可改為16777208 (16M)。
9) ? ? join_buffer_size
聯合查詢操作所能使用的緩沖區大小
record_buffer_size,read_rnd_buffer_size,sort_buffer_size,join_buffer_size為每個線程獨占,也就是說,如果有100個線程連接,則占用為16M*100
10) ?table_cache
表高速緩存的大小。每當MySQL訪問一個表時,如果在表緩沖區中還有空間,該表就被打開并放入其中,這樣可以更快地訪問表內容。通過檢查峰值時間的狀態值Open_tables和Opened_tables,可以決定是否需要增加table_cache的值。如果你發現open_tables等于table_cache,并且opened_tables在不斷增長,那么你就需要增加table_cache的值了(上述狀態值可以使用SHOW STATUS LIKE ‘Open%tables’獲得)。注意,不能盲目地把table_cache設置成很大的值。如果設置得太高,可能會造成文件描述符不足,從而造成性能不穩定或者連接失敗。
1G內存機器,推薦值是128-256。內存在4GB左右的服務器該參數可設置為256M或384M。
11) ?max_heap_table_size
用戶可以創建的內存表(memory table)的大小。這個值用來計算內存表的最大行數值。這個變量支持動態改變,即set @max_heap_table_size=#
這個變量和tmp_table_size一起限制了內部內存表的大小。如果某個內部heap(堆積)表大小超過tmp_table_size,MySQL可以根據需要自動將內存中的heap表改為基于硬盤的MyISAM表。
12) ?tmp_table_size
通過設置tmp_table_size選項來增加一張臨時表的大小,例如做高級GROUP BY操作生成的臨時表。如果調高該值,MySQL同時將增加heap表的大小,可達到提高聯接查詢速度的效果,建議盡量優化查詢,要確保查詢過程中生成的臨時表在內存中,避免臨時表過大導致生成基于硬盤的MyISAM表。
mysql> show global status like ‘created_tmp%‘;
+——————————–+———+
| Variable_name ? ? ? ? ? | Value |
+———————————-+———+
| Created_tmp_disk_tables | 21197 ?|
| Created_tmp_files | 58 |
| Created_tmp_tables | 1771587 |
+——————————–+———–+
每次創建臨時表,Created_tmp_tables增加,如果臨時表大小超過tmp_table_size,則是在磁盤上創建臨時表,Created_tmp_disk_tables也增加,Created_tmp_files表示MySQL服務創建的臨時文件文件數,比較理想的配置是:
Created_tmp_disk_tables / Created_tmp_tables * 100% <= 25%比如上面的服務器Created_tmp_disk_tables / Created_tmp_tables * 100% =1.20%,應該相當好了
默認為16M,可調到64-256最佳,線程獨占,太大可能內存不夠I/O堵塞
13) ?thread_cache_size
可以復用的保存在中的線程的數量。如果有,新的線程從緩存中取得,當斷開連接的時候如果有空間,客戶的線置在緩存中。如果有很多新的線程,為了提高性能可以這個變量值。
通過比較 Connections和Threads_created狀態的變量,可以看到這個變量的作用。
默認值為110,可調優為80。?
14) ?thread_concurrency
推薦設置為服務器 CPU核數的2倍,例如雙核的CPU, 那么thread_concurrency的應該為4;2個雙核的cpu, thread_concurrency的值應為8。默認為8
15) ?wait_timeout
指定一個請求的最大連接時間,對于4GB左右內存的服務器可以設置為5-10。
?
3. ? ?配置InnoDB的幾個變量
innodb_buffer_pool_size
對于InnoDB表來說,innodb_buffer_pool_size的作用就相當于key_buffer_size對于MyISAM表的作用一樣。InnoDB使用該參數指定大小的內存來緩沖數據和索引。對于單獨的MySQL數據庫服務器,最大可以把該值設置成物理內存的80%。
根據MySQL手冊,對于2G內存的機器,推薦值是1G(50%)。
?
innodb_flush_log_at_trx_commit
主要控制了innodb將log buffer中的數據寫入日志文件并flush磁盤的時間點,取值分別為0、1、2三個。0,表示當事務提交時,不做日志寫入操作,而是每秒鐘將log buffer中的數據寫入日志文件并flush磁盤一次;1,則在每秒鐘或是每次事物的提交都會引起日志文件寫入、flush磁盤的操作,確保了事務的ACID;設置為2,每次事務提交引起寫入日志文件的動作,但每秒鐘完成一次flush磁盤操作。
實際測試發現,該值對插入數據的速度影響非常大,設置為2時插入10000條記錄只需要2秒,設置為0時只需要1秒,而設置為1時則需要229秒。因此,MySQL手冊也建議盡量將插入操作合并成一個事務,這樣可以大幅提高速度。
根據MySQL手冊,在允許丟失最近部分事務的危險的前提下,可以把該值設為0或2。
?
innodb_log_buffer_size
log緩存大小,一般為1-8M,默認為1M,對于較大的事務,可以增大緩存大小。
可設置為4M或8M。
?
innodb_additional_mem_pool_size
該參數指定InnoDB用來存儲數據字典和其他內部數據結構的內存池大小。缺省值是1M。通常不用太大,只要夠用就行,應該與表結構的復雜度有關系。如果不夠用,MySQL會在錯誤日志中寫入一條警告信息。
根據MySQL手冊,對于2G內存的機器,推薦值是20M,可適當增加。
?
innodb_thread_concurrency=8
推薦設置為 2*(NumCPUs+NumDisks),默認一般為8
========
MySQL優化必須調整的10項配置
http://www.jb51.net/article/47419.htm
這篇文章主要介紹了MySQL優化必須調整的10項配置,使用這些方法可以讓你快速地獲得一個穩健的MySQL配置,需要的朋友可以參考下
..當我們被人雇來監測MySQL性能時,人們希望我們能夠檢視一下MySQL配置然后給出一些提高建議。許多人在事后都非常驚訝,因為我們建議他們僅僅改動幾個設置,即使是這里有好幾百個配置項。這篇文章的目的在于給你一份非常重要的配置項清單。
我們曾在幾年前在博客里給出了這樣的建議,但是MySQL的世界變化實在太快了!
寫在開始前…
即使是經驗老道的人也會犯錯,會引起很多麻煩。所以在盲目的運用這些推薦之前,請記住下面的內容:
一次只改變一個設置!這是測試改變是否有益的唯一方法。
大多數配置能在運行時使用SET GLOBAL改變。這是非常便捷的方法它能使你在出問題后快速撤銷變更。但是,要永久生效你需要在配置文件里做出改動。
一個變更即使重啟了MySQL也沒起作用?請確定你使用了正確的配置文件。請確定你把配置放在了正確的區域內(所有這篇文章提到的配置都屬于 [mysqld])
服務器在改動一個配置后啟不來了:請確定你使用了正確的單位。例如,innodb_buffer_pool_size的單位是MB而max_connection是沒有單位的。
不要在一個配置文件里出現重復的配置項。如果你想追蹤改動,請使用版本控制。
不要用天真的計算方法,例如”現在我的服務器的內存是之前的2倍,所以我得把所有數值都改成之前的2倍“。
基本配置
你需要經常察看以下3個配置項。不然,可能很快就會出問題。
innodb_buffer_pool_size:這是你安裝完InnoDB后第一個應該設置的選項。緩沖池是數據和索引緩存的地方:這個值越大越好,這能保證你在大多數的讀取操作時使用的是內存而不是硬盤。典型的值是5-6GB(8GB內存),20-25GB(32GB內存),100-120GB(128GB內存)。
innodb_log_file_size:這是redo日志的大小。redo日志被用于確保寫操作快速而可靠并且在崩潰時恢復。一直到MySQL 5.1,它都難于調整,因為一方面你想讓它更大來提高性能,另一方面你想讓它更小來使得崩潰后更快恢復。幸運的是從MySQL 5.5之后,崩潰恢復的性能的到了很大提升,這樣你就可以同時擁有較高的寫入性能和崩潰恢復性能了。一直到MySQL 5.5,redo日志的總尺寸被限定在4GB(默認可以有2個log文件)。這在MySQL 5.6里被提高。
一開始就把innodb_log_file_size設置成512M(這樣有1GB的redo日志)會使你有充裕的寫操作空間。如果你知道你的應用程序需要頻繁的寫入數據并且你使用的時MySQL 5.6,你可以一開始就把它這是成4G。
max_connections:如果你經常看到‘Too many connections'錯誤,是因為max_connections的值太低了。這非常常見因為應用程序沒有正確的關閉數據庫連接,你需要比默認的151連接數更大的值。max_connection值被設高了(例如1000或更高)之后一個主要缺陷是當服務器運行1000個或更高的活動事務時會變的沒有響應。在應用程序里使用連接池或者在MySQL里使用進程池有助于解決這一問題。
InnoDB配置
從MySQL 5.5版本開始,InnoDB就是默認的存儲引擎并且它比任何其他存儲引擎的使用都要多得多。那也是為什么它需要小心配置的原因。
innodb_file_per_table:這項設置告知InnoDB是否需要將所有表的數據和索引存放在共享表空間里(innodb_file_per_table = OFF) 或者為每張表的數據單獨放在一個.ibd文件(innodb_file_per_table = ON)。每張表一個文件允許你在drop、truncate或者rebuild表時回收磁盤空間。這對于一些高級特性也是有必要的,比如數據壓縮。但是它不會帶來任何性能收益。你不想讓每張表一個文件的主要場景是:有非常多的表(比如10k+)。
MySQL 5.6中,這個屬性默認值是ON,因此大部分情況下你什么都不需要做。對于之前的版本你必需在加載數據之前將這個屬性設置為ON,因為它只對新創建的表有影響。
innodb_flush_log_at_trx_commit:默認值為1,表示InnoDB完全支持ACID特性。當你的主要關注點是數據安全的時候這個值是最合適的,比如在一個主節點上。但是對于磁盤(讀寫)速度較慢的系統,它會帶來很巨大的開銷,因為每次將改變flush到redo日志都需要額外的fsyncs。將它的值設置為2會導致不太可靠(reliable)因為提交的事務僅僅每秒才flush一次到redo日志,但對于一些場景是可以接受的,比如對于主節點的備份節點這個值是可以接受的。如果值為0速度就更快了,但在系統崩潰時可能丟失一些數據:只適用于備份節點。
innodb_flush_method: 這項配置決定了數據和日志寫入硬盤的方式。一般來說,如果你有硬件RAID控制器,并且其獨立緩存采用write-back機制,并有著電池斷電保護,那么應該設置配置為O_DIRECT;否則,大多數情況下應將其設為fdatasync(默認值)。sysbench是一個可以幫助你決定這個選項的好工具。
innodb_log_buffer_size: 這項配置決定了為尚未執行的事務分配的緩存。其默認值(1MB)一般來說已經夠用了,但是如果你的事務中包含有二進制大對象或者大文本字段的話,這點緩存很快就會被填滿并觸發額外的I/O操作。看看Innodb_log_waits狀態變量,如果它不是0,增加innodb_log_buffer_size。
其他設置
query_cache_size: query cache(查詢緩存)是一個眾所周知的瓶頸,甚至在并發并不多的時候也是如此。 最佳選項是將其從一開始就停用,設置query_cache_size = 0(現在MySQL 5.6的默認值)并利用其他方法加速查詢:優化索引、增加拷貝分散負載或者啟用額外的緩存(比如memcache或redis)。如果你已經為你的應用啟用了query cache并且還沒有發現任何問題,query cache可能對你有用。這是如果你想停用它,那就得小心了。
log_bin:如果你想讓數據庫服務器充當主節點的備份節點,那么開啟二進制日志是必須的。如果這么做了之后,還別忘了設置server_id為一個唯一的值。就算只有一個服務器,如果你想做基于時間點的數據恢復,這(開啟二進制日志)也是很有用的:從你最近的備份中恢復(全量備份),并應用二進制日志中的修改(增量備份)。二進制日志一旦創建就將永久保存。所以如果你不想讓磁盤空間耗盡,你可以用 PURGE BINARY LOGS 來清除舊文件,或者設置 expire_logs_days 來指定過多少天日志將被自動清除。
記錄二進制日志不是沒有開銷的,所以如果你在一個非主節點的復制節點上不需要它的話,那么建議關閉這個選項。
skip_name_resolve:當客戶端連接數據庫服務器時,服務器會進行主機名解析,并且當DNS很慢時,建立連接也會很慢。因此建議在啟動服務器時關閉skip_name_resolve選項而不進行DNS查找。唯一的局限是之后GRANT語句中只能使用IP地址了,因此在添加這項設置到一個已有系統中必須格外小心。
總結
當然還有其他的設置可以起作用,取決于你的負載或硬件:在慢內存和快磁盤、高并發和寫密集型負載情況下,你將需要特殊的調整。然而這里的目標是使得你可以快速地獲得一個穩健的MySQL配置,而不用花費太多時間在調整一些無關緊要的MySQL設置或讀文檔找出哪些設置對你來說很重要上。
========
比較全面的MySQL優化參考
http://www.cnblogs.com/zengkefu/p/5683438.html?
本文整理了一些MySQL的通用優化方法,做個簡單的總結分享,旨在幫助那些沒有專職MySQL DBA的企業做好基本的優化工作,至于具體的SQL優化,大部分通過加適當的索引即可達到效果,更復雜的就需要具體分析了。
?
1、硬件層相關優化
1.1、CPU相關
在服務器的BIOS設置中,可調整下面的幾個配置,目的是發揮CPU最大性能,或者避免經典的NUMA問題:
1、選擇Performance Per Watt Optimized(DAPC)模式,發揮CPU最大性能,跑DB這種通常需要高運算量的服務就不要考慮節電了;
2、關閉C1E和C States等選項,目的也是為了提升CPU效率;
3、Memory Frequency(內存頻率)選擇Maximum Performance(最佳性能);
4、內存設置菜單中,啟用Node Interleaving,避免NUMA問題;
1.2、磁盤I/O相關
下面幾個是按照IOPS性能提升的幅度排序,對于磁盤I/O可優化的一些措施:
1、使用SSD或者PCIe SSD設備,至少獲得數百倍甚至萬倍的IOPS提升;
2、購置陣列卡同時配備CACHE及BBU模塊,可明顯提升IOPS(主要是指機械盤,SSD或PCIe SSD除外。同時需要定期檢查CACHE及BBU模塊的健康狀況,確保意外時不至于丟失數據);
3、有陣列卡時,設置陣列寫策略為WB,甚至FORCE WB(若有雙電保護,或對數據安全性要求不是特別高的話),嚴禁使用WT策略。并且閉陣列預讀策略,基本上是雞肋,用處不大;
4、盡可能選用RAID-10,而非RAID-5;
5、使用機械盤的話,盡可能選擇高轉速的,例如選用15KRPM,而不是7.2KRPM的盤,不差幾個錢的;
2、系統層相關優化
2.1、文件系統層優化
在文件系統層,下面幾個措施可明顯提升IOPS性能:
1、使用deadline/noop這兩種I/O調度器,千萬別用cfq(它不適合跑DB類服務);
2、使用xfs文件系統,千萬別用ext3;ext4勉強可用,但業務量很大的話,則一定要用xfs;
3、文件系統mount參數中增加:noatime, nodiratime, nobarrier幾個選項(nobarrier是xfs文件系統特有的);
2.2、其他內核參數優化
針對關鍵內核參數設定合適的值,目的是為了減少swap的傾向,并且讓內存和磁盤I/O不會出現大幅波動,導致瞬間波峰負載:
1、將vm.swappiness設置為5-10左右即可,甚至設置為0(RHEL 7以上則慎重設置為0,除非你允許OOM kill發生),以降低使用SWAP的機會;
2、將vm.dirty_background_ratio設置為5-10,將vm.dirty_ratio設置為它的兩倍左右,以確保能持續將臟數據刷新到磁盤,避免瞬間I/O寫,產生嚴重等待(和MySQL中的innodb_max_dirty_pages_pct類似);
3、將net.ipv4.tcp_tw_recycle、net.ipv4.tcp_tw_reuse都設置為1,減少TIME_WAIT,提高TCP效率;
4、至于網傳的read_ahead_kb、nr_requests這兩個參數,我經過測試后,發現對讀寫混合為主的OLTP環境影響并不大(應該是對讀敏感的場景更有效果),不過沒準是我測試方法有問題,可自行斟酌是否調整;
3、MySQL層相關優化
3.1、關于版本選擇
官方版本我們稱為ORACLE MySQL,這個沒什么好說的,相信絕大多數人會選擇它。
我個人強烈建議選擇Percona分支版本,它是一個相對比較成熟的、優秀的MySQL分支版本,在性能提升、可靠性、管理型方面做了不少改善。它和官方ORACLE MySQL版本基本完全兼容,并且性能大約有20%以上的提升,因此我優先推薦它,我自己也從2008年一直以它為主。
另一個重要的分支版本是MariaDB,說MariaDB是分支版本其實已經不太合適了,因為它的目標是取代ORACLE MySQL。它主要在原來的MySQL Server層做了大量的源碼級改進,也是一個非常可靠的、優秀的分支版本。但也由此產生了以GTID為代表的和官方版本無法兼容的新特性(MySQL 5.7開始,也支持GTID模式在線動態開啟或關閉了),也考慮到絕大多數人還是會跟著官方版本走,因此沒優先推薦MariaDB。
3.2、關于最重要的參數選項調整建議
建議調整下面幾個關鍵參數以獲得較好的性能(可使用本站提供的my.cnf生成器生成配置文件模板):
1、選擇Percona或MariaDB版本的話,強烈建議啟用thread pool特性,可使得在高并發的情況下,性能不會發生大幅下降。此外,還有extra_port功能,非常實用, 關鍵時刻能救命的。還有另外一個重要特色是 QUERY_RESPONSE_TIME 功能,也能使我們對整體的SQL響應時間分布有直觀感受;
2、設置default-storage-engine=InnoDB,也就是默認采用InnoDB引擎,強烈建議不要再使用MyISAM引擎了,InnoDB引擎絕對可以滿足99%以上的業務場景;
3、調整innodb_buffer_pool_size大小,如果是單實例且絕大多數是InnoDB引擎表的話,可考慮設置為物理內存的50% ~ 70%左右;
4、根據實際需要設置innodb_flush_log_at_trx_commit、sync_binlog的值。如果要求數據不能丟失,那么兩個都設為1。如果允許丟失一點數據,則可分別設為2和10。而如果完全不用care數據是否丟失的話(例如在slave上,反正大不了重做一次),則可都設為0。這三種設置值導致數據庫的性能受到影響程度分別是:高、中、低,也就是第一個會另數據庫最慢,最后一個則相反;
5、設置innodb_file_per_table = 1,使用獨立表空間,我實在是想不出來用共享表空間有什么好處了;
6、設置innodb_data_file_path = ibdata1:1G:autoextend,千萬不要用默認的10M,否則在有高并發事務時,會受到不小的影響;
7、設置innodb_log_file_size=256M,設置innodb_log_files_in_group=2,基本可滿足90%以上的場景;
8、設置long_query_time = 1,而在5.5版本以上,已經可以設置為小于1了,建議設置為0.05(50毫秒),記錄那些執行較慢的SQL,用于后續的分析排查;
9、根據業務實際需要,適當調整max_connection(最大連接數)、max_connection_error(最大錯誤數,建議設置為10萬以上,而open_files_limit、innodb_open_files、table_open_cache、table_definition_cache這幾個參數則可設為約10倍于max_connection的大小;
10、常見的誤區是把tmp_table_size和max_heap_table_size設置的比較大,曾經見過設置為1G的,這2個選項是每個連接會話都會分配的,因此不要設置過大,否則容易導致OOM發生;其他的一些連接會話級選項例如:sort_buffer_size、join_buffer_size、read_buffer_size、read_rnd_buffer_size等,也需要注意不能設置過大;
11、由于已經建議不再使用MyISAM引擎了,因此可以把key_buffer_size設置為32M左右,并且強烈建議關閉query cache功能;
3.3、關于Schema設計規范及SQL使用建議
下面列舉了幾個常見有助于提升MySQL效率的Schema設計規范及SQL使用建議:
1、所有的InnoDB表都設計一個無業務用途的自增列做主鍵,對于絕大多數場景都是如此,真正純只讀用InnoDB表的并不多,真如此的話還不如用TokuDB來得劃算;
2、字段長度滿足需求前提下,盡可能選擇長度小的。此外,字段屬性盡量都加上NOT NULL約束,可一定程度提高性能;
3、盡可能不使用TEXT/BLOB類型,確實需要的話,建議拆分到子表中,不要和主表放在一起,避免SELECT * 的時候讀性能太差。
4、讀取數據時,只選取所需要的列,不要每次都SELECT *,避免產生嚴重的隨機讀問題,尤其是讀到一些TEXT/BLOB列;
5、對一個VARCHAR(N)列創建索引時,通常取其50%(甚至更小)左右長度創建前綴索引就足以滿足80%以上的查詢需求了,沒必要創建整列的全長度索引;
6、通常情況下,子查詢的性能比較差,建議改造成JOIN寫法;
7、多表聯接查詢時,關聯字段類型盡量一致,并且都要有索引;
8、多表連接查詢時,把結果集小的表(注意,這里是指過濾后的結果集,不一定是全表數據量小的)作為驅動表;
9、多表聯接并且有排序時,排序字段必須是驅動表里的,否則排序列無法用到索引;
10、多用復合索引,少用多個獨立索引,尤其是一些基數(Cardinality)太小(比如說,該列的唯一值總數少于255)的列就不要創建獨立索引了;
11、類似分頁功能的SQL,建議先用主鍵關聯,然后返回結果集,效率會高很多;
3.4、其他建議
關于MySQL的管理維護的其他建議有:
1、通常地,單表物理大小不超過10GB,單表行數不超過1億條,行平均長度不超過8KB,如果機器性能足夠,這些數據量MySQL是完全能處理的過來的,不用擔心性能問題,這么建議主要是考慮ONLINE DDL的代價較高;
2、不用太擔心mysqld進程占用太多內存,只要不發生OOM kill和用到大量的SWAP都還好;
3、在以往,單機上跑多實例的目的是能最大化利用計算資源,如果單實例已經能耗盡大部分計算資源的話,就沒必要再跑多實例了;
4、定期使用pt-duplicate-key-checker檢查并刪除重復的索引。定期使用pt-index-usage工具檢查并刪除使用頻率很低的索引;
5、定期采集slow query log,用pt-query-digest工具進行分析,可結合Anemometer系統進行slow query管理以便分析slow query并進行后續優化工作;
6、可使用pt-kill殺掉超長時間的SQL請求,Percona版本中有個選項 innodb_kill_idle_transaction 也可實現該功能;
7、使用pt-online-schema-change來完成大表的ONLINE DDL需求;
8、定期使用pt-table-checksum、pt-table-sync來檢查并修復mysql主從復制的數據差異;
寫在最后:這次的優化參考,大部分情況下我都介紹了適用的場景,如果你的應用場景和本文描述的不太一樣,那么建議根據實際情況進行調整,而不是生搬硬套。歡迎質疑拍磚,但拒絕不經過大腦的習慣性抵制。
========
總結
以上是生活随笔為你收集整理的MySQL优化学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++ 通讯录学习总结
- 下一篇: windbg 脚本学习总结