1. 程式人生 > 其它 >超全面常用的資料庫優化方案

超全面常用的資料庫優化方案

一、資料庫設計優化篇

1.1 選取最合適的的欄位屬性

關係型資料庫可以支援大資料量的存取,但是一般來說表越小,它執行的速度也就會越快。因此,在新建表的時候,在滿足我們業務需求的基礎上,儘可能的將欄位的寬度設定的小一點。

例如,在定義郵政編碼這個欄位時,如果將其設定為CHAR(100),顯然給資料庫增加了不必要的空間,甚至使用VARCHAR這種型別也是多餘的,因為CHAR(6)就可以很好的完成任務了。相同的,如果TINYINT能滿足我們的業務需求,那我們沒有必要使用INT或者BIGINT。

1.2資料庫索引

索引是提高資料庫效能最常用的方法,它可以大大提高資料庫查詢的效率,尤其是在查詢語句當中包含有MAX(),MIN()和ORDER BY這些函式和語句的時候,效能提高更為明顯。

通常情況,索引應建立在那些將用於JOIN連線,WHERE判斷和ORDERBY排序的欄位上。儘量不要對資料庫中某個含有大量重複的值的欄位建立索引。如使用者表中的性別欄位就不適合建立索引(因為性別只有男或女兩個值),在這樣的欄位上建立索引不僅不會提高資料庫查詢的效率,反而有可能降低資料庫的效能。

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

二、SQL語句優化篇

2.1 儘量避免使用子查詢,可以使用JOIN連結查詢替代

常用的關係型資料庫都支援子查詢,子查詢使用SELECT語句建立一個查詢結果,然後把這個結果作為一張臨時表用在另一個查詢中。使用子查詢可以一次完成多步SQL操作,也可以避免事務或者表鎖死,且寫起來比較容易。但是使用子查詢MYSQL會在記憶體中建立一張臨時表供外層查詢使用,所以會降低查詢的效率。這時候我們可以使用JOIN連結操作來替代子查詢。

2.2 UNION All能滿足業務需求不要使用UNION

如果我們需要將兩個或者多個SELECT語句的結果作為合併為一個整體顯示出來,我們可以用UNION或者UNION ALL關鍵字。UNION(聯合)和UNION ALL的作用是將多個結果合併在一起顯示出來。

兩者的區別是:

UNION會自動壓縮多個結果集合中的重複結果,而UNION ALL 則將所有的結果全部顯示出來,不管是不是重複。所以當UNION ALL能滿足業務需求的時候,儘量使用UNION ALL而不用UNION。

2.3 WHERE子句儘量避免使用!=或<>操作符

在WHERE子句中使用!=或<>操作符,查詢條件不會使用索引,會進行全表查詢。即影響查詢效率。

2.4 WHERE子句使用OR的優化

通常情況我們可以使用UNION ALL或UNION的方式替換OR會得到更好的效果。因為WHERE子句中使用了OR,將不會使用索引。

例如:SELECT ID FROM TABLENAME WHERE ID = 1 OR ID = 2 ;
優化:SELECT ID FROM TABLENAME WHERE ID = 1 UNION ALL SELECT ID FROM TABLENAME WHERE ID = 2 ;

2.5 WHERE子句使用IN或NOT IN優化

IN和NOT IN也要慎用,否則可能會導致全表掃描。

可用以下方案替換:

方案一:BETWEEN AND替換IN
例如:SELECT ID FROM TABLENAME WHERE ID IN(1,2,3);
優化:SELECT ID FROM TABLENAME WHERE ID BETWEEN 1 AND 3;

方案二:EXISTS替換IN
例如:SELECT ID FROM TABLEA WHERE ID IN (SELECT ID FROM TABLEB ) 
優化:SELECT ID FROM TABLEA AS A WHERE ID EXISTS(SELECT 1 FROM TABLEB AS A WHERE B.ID = A.ID)

方案三:LEFT JOIN替換IN
例如:SELECT ID FROM TABLEA WHERE ID IN(SELECT ID FROM TABLEB) 
優化:SELECT ID FROM TABLEA AS A LEFT JOIN TABLEB AS B ON A.ID = B.ID

2.6 WHERE子句中使用IS NULL或IS NOT NULL優化

在WHERE子句中使用IS NULL或IS NOT NULL判斷,索引將被放棄使用,會進行全表查詢。

例如:SELECT ID FROM TABLENAME WHERE AGE IS NULL 
優化成AGE上設定預設值0,確保表中AGE沒有NULL值,
優化:SELECT ID FROM TABLENAME WHERE AGE = 0

2.7 LIKE語句優化

一般情況下不建議使用LIKE操作,特別是資料量較大的表。

例如:SELECT NAME FROM TABLEA WHERE NAME LIKE '%張%';不會使用索引
優化:SELECT NAME FROM TABLEA WHERE NAME LIKE '張%';會使用索引

2.8 WHERE子句中避免對欄位進行表示式操作

儘量不要在WHERE子句中的=左邊進行函式、算數運算或其他表示式運算,否則系統將無法正確使用索引。

例如:SELECT ID FROM TABLENAME WHERE ID/2 = 50 
優化:SELECT ID FROM TABLENAME WHERE ID = 50*2

例如:SELECT ID FROM TABLENAME WHERE substring(name,1,2) = '歐陽' 
優化:SELECT ID FROM TABLENAME WHERE LIKE '歐陽%'

2.9 一定不要用SELECT * FROM TABLENAME

在定義SQL語句欄位列表替換"*",儘量避免返回無用的時候,要用具體的的欄位。

2.10 LIMIT分頁優化

MYSQL資料庫實現分頁一般都會使用LIMIT,但是當偏移量比較大時,LIMIT的效率會非常低,導致查詢超時。

如下SQL:
SELECT ID FROM TABLENAME LIMIT 1000,10   執行很快
SELECT ID FROM TABLENAME LIMIT 100000,10 執行很慢

優化方法:
方法一:SELECT ID FROM TABLENAME ORDER BY ID LIMIT 100000,10; 執行很快(因為用了ID主鍵做索引)
上述方法一是我們最常用的,但是如果表中的資料是千萬級別的,即便使用方法一,查詢速度可能還是比較慢,這時候我們可以把上一頁ID的最大值作為查詢條件來實現分頁,如方法二。

方法二:SELECT ID FROM TABLENAME WHERE id > @MAXID limit 10;
@MAXID的值是上一頁查詢結果中ID的最大值。

2.11 EXISTS代替IN

SELECT ID FROM TABLEA WHERE ID IN (SELECT ID FROM TABLEB)

如上SQL,IN執行的時候是在記憶體中遍歷比較,IN(SELECT ID FROM TABLEB)括號中語句只執行一次,把TABLEB表中的所有ID欄位快取起來,之後檢查TABLEA表的ID是否與TABLEB表中的ID相等,如果ID相等則將TABLEA表中的記錄加入到結果集中,直到遍歷完TABLEA表的所有記錄。

SELECT ID FROM TABLEA WHERE ID EXISTS(SELECT ID FROM TABLEA.ID= TABLEB.ID)

如上SQL,EXISTS查詢是遍歷TABLEA中的資料,TABLEA中的每一條資料與TABLEB連表查詢,如果有返回結果,則把該記錄新增到結果集中,所以當TABLEB的資料量遠大於TANLEA時,EXISTS效率大大優於IN.當TABLEA表資料與TABLEB表資料一樣大時,IN與EXISTS效率差不多

 

轉載自: 超全面常用的資料庫優化方案 - 知乎 (zhihu.com)