MySQL 效能最佳化

來源:互聯網
上載者:User

標籤:addition   login   retrieve   讀取   不能   複合   狀態   char   use   

參考文章:http://www.jb51.net/article/24392.htm

 

當我們去設計資料庫表結構,對操作資料庫時(尤其是查表時的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” 的欄位,它會在每次使用者登入時被更新。但是,每次更新時會導致該表的查詢快取被清空。所以,你可以把這個欄位放到另一個表中,這樣就不會影響你對使用者識別碼,使用者名稱,使用者角色的不停地讀取了,因為查詢快取會幫你增加很多效能。 

另外,你需要注意的是,這些被分出去的欄位所形成的表,你不會經常性地去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個多小時,因為裡面有一千六百萬條資料。 

 

 

 

=========================================

以下內容參考:http://www.ihref.com/read-16422.html

 

1.對查詢進行最佳化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。

2.應盡量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,

Sql 代碼 : select id from t where num is null;

可以在 num 上設定預設值 0,確保表中 num 列沒有 null 值,然後這樣查詢:

Sql 代碼 : select id from t where num=0;

3.應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。

4.應盡量避免在 where 子句中使用 or 來串連條件,否則將導致引擎放棄使用索引而進行全表掃描,

Sql 代碼 : select id from t where num=10 or num=20;

可以這樣查詢:

Sql 代碼 : select id from t where num=10 union all select id from t where num=20;

5.in 和 not in 也要慎用,否則會導致全表掃描,如:

Sql 代碼 : select id from t where num in(1,2,3);

對於連續的數值,能用 between 就不要用 in 了:

Sql 代碼 : select id from t where num between 1 and 3;

6.下面的查詢也將導致全表掃描:

Sql 代碼 : select id from t where name like ‘%c%‘;

若要提高效率,可以考慮全文檢索索引。

7.如果在 where 子句中使用參數,也會導致全表掃描。因為 SQL 只有在運行時才會解析局部變數,但優 化程式不能將訪問計劃的選擇延遲到運行時;它必須在編譯時間進行選擇。然 而,如果在編譯時間建立訪問計 劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:

Sql 代碼 : select id from t where [email protected] ;

可以改為強制查詢使用索引:

Sql 代碼 : select id from t with(index(索引名)) where [email protected] ;

8.應盡量避免在 where 子句中對欄位進行運算式操作, 這將導致引擎放棄使用索引而進行全表掃描。

Sql 代碼 : select id from t where num/2=100;

可以這樣查詢:

Sql 代碼 : select id from t where num=100*2;

9.應盡量避免在 where 子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:

Sql 代碼 : select id from t where substring(name,1,3)=‘abc‘;#name 以 abc 開頭的 id

應改為:

Sql 代碼 : select id from t where name like ‘abc%‘;

10.不要在 where 子句中的“=”左邊進行函數、算術運算或其他運算式運算,否則系統將可能無法正確使用 索引。

11.在使用索引欄位作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個欄位作為條件 時才能保證系統使用該索引, 否則該索引將不會 被使用, 並且應儘可能的讓欄位順序與索引順序相一致。

12.不要寫一些沒有意義的查詢,如需要產生一個空表結構:

Sql 代碼 : select col1,col2 into #t from t where 1=0;

這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:

Sql 代碼 : create table #t(…);

13.很多時候用 exists 代替 in 是一個好的選擇:

Sql 代碼 : select num from a where num in(select num from b);

用下面的語句替換:

Sql 代碼 : select num from a where exists(select 1 from b where num=a.num);

14.並不是所有索引對查詢都有效,SQL 是根據表中資料來進行查詢最佳化的,當索引列有大量資料重複時, SQL 查詢可能不會去利用索引,如一表中有欄位 ***,male、female 幾乎各一半,那麼即使在 *** 上建 了索引也對查詢效率起不了作用。

15.索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要謹慎考慮,視具體情況而定。一個表的索引數最好不要超過 6 個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。

16.應儘可能的避免更新 clustered 索引資料列, 因為 clustered 索引資料列的順序就是表記錄的實體儲存體順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引資料列,那麼需要考慮是否應將該索引建為 clustered 索引。

17.盡量使用數字型欄位,若只含數值資訊的欄位盡量不要設計為字元型,這會降低查詢和串連的效能,並 會增加儲存開銷。這是因為引擎在處理查詢和串連時會逐個比較字串中每一個字元,而對於數字型而言 只需要比較一次就夠了。

18.儘可能的使用 varchar/nvarchar 代替 char/nchar , 因為首先變長欄位儲存空間小, 可以節省儲存空間, 其次對於查詢來說,在一個相對較小的欄位內搜尋效率顯然要高些。

19.任何地方都不要使用 select * from t ,用具體的欄位列表代替“*”,不要返回用不到的任何欄位。

20.盡量使用表變數來代替暫存資料表。如果表變數包含大量資料,請注意索引非常有限(只有主鍵索引)。

21.避免頻繁建立和刪除暫存資料表,以減少系統資料表資源的消耗。

22.暫存資料表並不是不可使用,適當地使用它們可以使某些常式更有效,例如,當需要重複引用大型表或常用 表中的某個資料集時。但是,對於一次性事件, 最好使用匯出表。

23.在建立暫存資料表時,如果一次性插入資料量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果資料量不大,為了緩和系統資料表的資源,應先 create table,然後 insert.

24.如果使用到了暫存資料表, 在預存程序的最後務必將所有的暫存資料表顯式刪除, 先 truncate table ,然後 drop table ,這樣可以避免系統資料表的較長時間鎖定。

25.盡量避免使用遊標,因為遊標的效率較差,如果遊標操作的資料超過 1 萬行,那麼就應該考慮改寫。

26.使用基於遊標的方法或暫存資料表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更 有效。

27.與暫存資料表一樣,遊標並不是不可使用。對小型資料集使用 FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的資料時。在結果集中包括“合計”的常式通常要比使用遊標執行的速度快。如果開發時間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。

28.在所有的預存程序和觸發器的開始處設定 SET NOCOUNT ON ,在結束時設定 SET NOCOUNT OFF .無需在執行預存程序和觸發器的每個語句後向用戶端發送 DONE_IN_PROC 訊息。

29.盡量避免大事務操作,提高系統並發能力。 sql 最佳化方法使用索引來更快地遍曆表。 預設情況下建立的索引是非群集索引,但有時它並不是最佳的。在非群集索引下,資料在物理上隨機存放在資料頁上。合理的索引設計要建立在對各種查詢的分析和預測上。一般來說:

a.有大量重複值、且經常有範圍查詢( > ,< ,> =,< =)和 order by、group by 發生的列,可考慮建立叢集索引;

b.經常同時存取多列,且每列都含有重複值可考慮建立複合式索引;

c.複合式索引要盡量使關鍵查詢形成索引覆蓋,其前置列一定是使用最頻繁的列。索引雖有助於提高效能但 不是索引越多越好,恰好相反過多的索引會導致系統低效。使用者在表中每加進一個索引,維護索引集合就 要做相應的更新工作。

30.定期分析表和檢查表。

分析表的文法:ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tb1_name[, tbl_name]...

以上語句用於分析和儲存表的關鍵字分布,分析的結果將可以使得系統得到準確的統計資訊,使得SQL能夠產生正確的執行計畫。如果使用者感覺實際執行計畫並不是預期的執行計畫,執行一次分析表可能會解決問題。在分析期間,使用一個讀取鎖定對錶進行鎖定。這對於MyISAM,DBD和InnoDB表有作用。

例如分析一個資料表:analyze table table_name
檢查表的文法:CHECK TABLE tb1_name[,tbl_name]...[option]...option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}

檢查表的作用是檢查一個或多個表是否有錯誤,CHECK TABLE 對MyISAM 和 InnoDB表有作用,對於MyISAM表,關鍵字統計資料被更新

CHECK TABLE 也可以檢查視圖是否有錯誤,比如在視圖定義中被引用的表不存在。

31.定期最佳化表。

最佳化表的文法:OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tb1_name [,tbl_name]...

如果刪除了表的一大部分,或者如果已經對含有可變長度行的表(含有 VARCHAR、BLOB或TEXT列的表)進行更多更改,則應使用OPTIMIZE TABLE命令來進行表最佳化。這個命令可以將表中的空間片段進行合并,並且可以消除由於刪除或者更新造成的空間浪費,但OPTIMIZE TABLE 命令只對MyISAM、 BDB 和InnoDB表起作用。

例如: optimize table table_name

注意: analyze、check、optimize執行期間將對錶進行鎖定,因此一定注意要在MySQL資料庫不繁忙的時候執行相關的操作。

補充:

1、在海量查詢時盡量少用格式轉換。

2、ORDER BY 和 GROPU BY:使用 ORDER BY 和 GROUP BY 短語,任何一種索引都有助於 SELECT 的效能提高。

3、任何對列的操作都將導致表掃描,它包括資料庫教程函數、計算運算式等等,查詢時要儘可能將操作移 至等號右邊。

4、IN、OR 子句常會使用工作表,使索引失效。如果不產生大量重複值,可以考慮把子句拆開。拆開的子 句中應該包含索引。

5、只要能滿足你的需求,應儘可能使用更小的資料類型:例如使用 MEDIUMINT 代替 INT

6、盡量把所有的列設定為 NOT NULL,如果你要儲存 NULL,手動去設定它,而不是把它設為預設值。

7、盡量少用 VARCHAR、TEXT、BLOB 類型

8、如果你的資料只有你所知的少量的幾個。最好使用 ENUM 類型

9、正如 graymice 所講的那樣,建立索引。

10、合理用運分表與分區表提高資料存放和提取速度。

MySQL 效能最佳化

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.