文章出處

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

缺省情況下建立的索引是非群集索引,但有時它并不是最佳的。在非群集索引下,數據在物理上隨機存放在數據頁上。合理的索引設計要建立在對各種查詢的分析和預測上。一般來說:

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

  b.經常同時存取多列,且每列都含有重復值可考慮建立組合索引, 選擇度高的列建議作為索引的第一個字段

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

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 num=@num ;

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

Sql 代碼 : select id from t with(index(索引名)) where num=@num ;

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.盡量避免大事務操作,提高系統并發能力。

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數據庫不繁忙的時候執行相關的操作。32.存儲引擎的選擇如果數據表需要事務處理,應該考慮使用InnoDB,因為它完全符合ACID特性。如果不需要事務處理,使用默認存儲引擎MyISAM是比較明智的。


MyISAM適合于一些需要大量查詢的應用,但其對于有大量寫操作并不是很好。甚至你只是需要update一個字段,整個表都會被鎖起來,而別的進程,就算是讀進程都 無法操作直到讀操作完成。另外,MyISAM 對于 SELECT COUNT(*) 這類的計算是超快無比的。

InnoDB 的趨勢會是一個非常復雜的存儲引擎,對于一些小的應用,它會比 MyISAM 還慢。他是它支持“行鎖” ,于是在寫操作比較多的時候,會更優秀。并且,他還支持更多的高級應用,比如:事務。

33、定期用explain優化慢查詢中的SQL語句

34、EXPLAIN 你的 SELECT 查詢

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

EXPLAIN 的查詢結果還會告訴你你的索引主鍵被如何利用的,你的數據表是如何被搜索和排序的……等等,等等。

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

當我們為 group_id 字段加上索引后:

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

35、 當只要一行數據時使用 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) {
// ...
}

 

36. 在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 字段應該是被建過索引的,而且應該是相當的類型,相同的字符集。

37、千萬不要 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");


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

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

就算是你 users 表有一個主鍵叫 “email”的字段,你也別讓它成為主鍵。使用 VARCHAR 類型來當主鍵會使用得性能下降。另外,在你的程序中,你應該使用表的ID來構造你的數據結構。

而且,在MySQL數據引擎下,還有一些操作需要使用主鍵,在這些情況下,主鍵的性能和設置變得非常重要,比如,集群,分區……

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

 

39. 從 PROCEDURE ANALYSE() 取得建議

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

例 如,如果你創建了一個 INT 字段作為你的主鍵,然而并沒有太多的數據,那么,PROCEDURE ANALYSE()會建議你把這個字段的類型改成 MEDIUMINT 。或是你使用了一個 VARCHAR 字段,因為數據不多,你可能會得到一個讓你把它改成 ENUM 的建議。這些建議,都是可能因為數據不夠多,所以決策做得就不夠準。

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

一定要注意,這些只是建議,只有當你的表里的數據越來越多時,這些建議才會變得準確。一定要記住,你才是最終做決定的人。

 

40. 字段盡可能的使用 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.”
如果你要保存 NULL,手動去設置它,而不是把它設為默認值。 建議用用0、特殊值或空串代替NULL值


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

Prepared Statements 可以檢查一些你綁定好的變量,這樣可以保護你的程序不會受到“SQL注入式”攻擊。當然,你也可以手動地檢查你的這些變量,然而,手動的檢查容易出問題, 而且很經常會被程序員忘了。當我們使用一些framework或是ORM的時候,這樣的問題會好一些。

在性能方面,當一個相同的查詢被使用多次的時候,這會為你帶來可觀的性能優勢。你可以給這些Prepared Statements定義一些參數,而MySQL只會解析一次。

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

當然,也有一些情況下,我們需要避免使用Prepared Statements,因為其不支持查詢緩存。但據說版本5.1后支持了。

42. 把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";

43. 固定長度的表會更快
       如 果表中的所有字段都是“固定長度”的,整個表會被認為是 “static” 或 “fixed-length”。 例如,表中沒有如下類型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一個這些字段,那么這個表就不是“固定長度靜態表”了,這樣,MySQL 引擎會用另一種方法來處理。

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

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

使用“垂直分割”技術(見下一條),你可以分割你的表成為兩個一個是定長的,一個則是不定長的。
45. 垂直分割表
       “垂直分割”是一種把數據庫中的表按列變成幾張表的方法,這樣可以降低表的復雜度和字段的數目,從而達到優化的目的。(以前,在銀行做過項目,見過一張表有100多個字段,很恐怖)

       示 例一:在Users表中有一個字段是家庭地址,這個字段是可選字段,相比起,而且你在數據庫操作的時候除了個人信息外,你并不需要經常讀取或是改寫這個字 段。那么,為什么不把他放到另外一張表中呢? 這樣會讓你的表有更好的性能,大家想想是不是,大量的時候,我對于用戶表來說,只有用戶ID,用戶名,口令,用戶角色等會被經常使用。小一點的表總是會有 好的性能。

       示例二: 你有一個叫 “last_login” 的字段,它會在每次用戶登錄時被更新。但是,每次更新時會導致該表的查詢緩存被清空。所以,你可以把這個字段放到另一個表中,這樣就不會影響你對用戶 ID,用戶名,用戶角色的不停地讀取了,因為查詢緩存會幫你增加很多性能。

另外,你需要注意的是,這些被分出去的字段所形成的表,你不會經常性地去Join他們,不然的話,這樣的性能會比不分割時還要差,而且,會是極數級的下降。

46. 拆分大的 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);
}

 
47. 越小的列會越快
對于大多數的數據庫引擎來說,硬盤操作可能是最重大的瓶頸。所以,把你的數據變得緊湊會對這種情況非常有幫助,因為這減少了對硬盤的訪問。

參看 MySQL 的文檔 Storage Requirements 查看所有的數據類型。

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

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


48. 使用一個對象關系映射器(Object Relational Mapper)
    使用 ORM (Object Relational Mapper),你能夠獲得可靠的性能增漲。一個ORM可以做的所有事情,也能被手動的編寫出來。但是,這需要一個高級專家。

ORM 的最重要的是“Lazy Loading”,也就是說,只有在需要的去取值的時候才會去真正的去做。但你也需要小心這種機制的副作用,因為這很有可能會因為要去創建很多很多小的查 詢反而會降低性能。 ORM 還可以把你的SQL語句打包成一個事務,這會比單獨執行他們快得多得多。

49. 小心“永久鏈接”
“永 久鏈接”的目的是用來減少重新創建MySQL鏈接的次數。當一個鏈接被創建了,它會永遠處在連接的狀態,就算是數據庫操作已經結束了。而且,自從我們的 Apache開始重用它的子進程后——也就是說,下一次的HTTP請求會重用Apache的子進程,并重用相同的 MySQL 鏈接。

50、范圍列(>,<,between and)可以用到索引,但是范圍列后面的列無法用到索引。同時,索引最多用于一個范圍列,因此如果查詢條件中有兩個范圍列則無法全用到索引

51、如果需要在大字段上建立索引,可以考慮使用前綴索引。

建立前綴索引的語法為:

ALTER TABLE table_name ADD KEY(column_name(prefix_length));

 52、 將大字段、訪問頻率低的字段拆分到單獨的表中存儲,分離冷熱數據,有利于有效利用緩存,防止讀入無用的冷數據,較少磁盤IO,同時保證熱數據常駐內存提高緩存命中率。

53、 MYSQL的新增和修改列的操作相當于重建表,表設計要一步到位,盡量避免大表的DDL操作。 (TIPS:可以預定義一些列留作將來業務擴展,如:當前只需要10個字段,考慮到未來發展,可以預留10個字段,表上總共創建20個字段)

54、為了降低索引維護成本,禁止冗余索引,增大IO壓力。(a,b,c)、(a,b),后者為冗余索引。可以利用前綴索引來達到加速目的,減輕維護負擔。

55、WHERE子句中的數據掃描不超過表總數據量的30%

如何選擇prefix_length的長度,具體參考:前綴索引,一種優化索引大小的解決方案

 

補充:

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

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

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

》、盡量少用 CLOB、TEXT、BLOB大類型

》、如果你的數據只有你所知的少量的幾個。最好使用 ENUM 類型

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

》、合理用運分庫、分表與分區表提高數據存放和提取速度。具體參考:Mysql分表和分區的區別、分庫分表區別




下面是簡單版,只是對上面的知識點濃縮,方便記憶:
索引:
考慮在 where 及 order by 涉及的列上建立索引 經常同時存取多列,且每列都含有重復值可考慮建立組合索引,且查詢越頻繁的字段放前面 按需使用聚集與非聚集索引,聚集不適合頻繁更新、適合范圍查詢(
> ,< ,> =,< =)和 order by、group by , 注意復合索引的順序,選擇性高的建議放前面
不要在數據選擇性不高的字段建立索引
索引控制在6個以內為好

大字段可以考慮使用前綴索引
去除冗余索引

where子句的操作: 盡量避免在 where 子句中對字段進行
null 值判斷、!=或<>操作符、 or 來連接條件、in 和 not in、like時%在前面、使用參數,如where num=@num、 表達式操作,如where num/2=100、函數操作(“=”左邊進行函數),如substring(name,1,3)='abc';#name、算術運算或其他表達式運算 exists 代替 in
一個查詢中避免多個范圍查詢
WHERE子句中的數據掃描不超過表總數據量的30%

表結構: 能用數字和枚舉類型就不用其他類型 使用 varchar
/nvarchar 代替 char/nchar 字段盡可能的使用 NOT NULL
把IP地址存成 UNSIGNED INT
固定長度的表會更快
越小的列會越快


臨時表: 可用變量就不要用臨時表 避免頻繁創建和刪除臨時表 需要重復引用大型表或常用 表中的某個數據集時可用臨時表 新建臨時表時,如果一次性插入數據量很大,用 select into 代替 create table 注意刪除臨時表,先 truncate table ,然后 drop table

其他:
不使用select * 大量數據時不適合用游標處理 在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 定期ANALYZE、CHECK 、OPTIMIZE 表 EXPLAIN 你的 SELECT 查詢 善用LIMIT 避免一次性查詢大量數據 在Join表的時候使用相同類型的列,并將其索引 千萬不要 ORDER BY RAND() 除了關聯表 永遠為每張表設置一個ID Prepared Statements 小心“永久鏈接”
盡量避免大事務操作 拆分大的 DELETE 或 INSERT 或 insert .. into .. select.. 語句 減少鎖表時間 使用orm
使用緩存,例如一級緩存,二級緩存、redis、memcace分布式 合理用運分庫、分表與分區表提高數據存放和提取速度

 

附:

mysql 慢查詢查看方案

  truncate table  mysql.slow_log;

select db, query_TIME, lock_time, rows_examined, sql_text from mysql.slow_log

 

相關:

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()