數據庫性能優化策略

有數據代表:用戶能夠承受的最大等待時間爲8秒。 
以前曾見過某個產品的一個列表頁,40秒左右才能加載出來,幾乎沒有進行任何優化措施。 
沒有索引,沒有緩存機制,沒有進行sql優化(sql語句很長,而且各類left join表關聯)。 
數據庫優化策略有不少,設計初期,創建好的數據結構對於後期性能優化相當重要。由於數據庫結構是系統的基石,基礎打很差,使用各類優化策略,也不能達到很完美的效果。mysql

一:規範化與反規範化

你們都據說過:數據庫設計三大範式. 
1.第一範式(確保每列保持原子性) 
第一範式是最基本的範式。若是數據庫表中的全部字段值都是不可分解的原子值,就說明該數據庫表知足了第一範式。sql

2.第二範式(確保表中的每列都和主鍵相關) 
第二範式在第一範式的基礎之上更進一層。第二範式須要確保數據庫表中的每一列都和主鍵相關,而不能只與主鍵的某一部分相關(主要針對聯合主鍵而言)。也就是說在一個數據庫表中,一個表中只能保存一種數據,不能夠把多種數據保存在同一張數據庫表中。數據庫

3.第三範式(確保每列都和主鍵列直接相關,而不是間接相關) 
第三範式須要確保數據表中的每一列數據都和主鍵直接相關,而不能間接相關。緩存

沒有最好的設計,只有最合適的設計,因此不要過度注重理論。三範式能夠做爲一個基本依據,不要生搬硬套。 
數據庫操做中最爲耗時的操做就是 IO 處理,大部分數據庫操做 90% 以上的時間都花在了 IO 讀寫上面。因此儘量減小 IO 讀寫量,能夠在很大程度上提升數據庫操做的性能。性能優化

二:優化策略:

在設計表時應同時考慮對某些表進行反規範化,方法有如下幾種:數據結構

一是分割表。 
分割表可分爲水平分割表和垂直分割表兩種: 
水平分割是按照行將一個表分割爲多個表,這能夠提升每一個表的查詢速度,但查詢、更新時要選擇不一樣的表,統計時要彙總多個表,所以應用程序會更復雜。 
垂直分割是對於一個列不少的表,若某些列的訪問頻率遠遠高於其它列,就能夠將主鍵和這些列做爲一個表,將主鍵和其它列做爲另一個表。經過減小列的寬度,增長了每一個數據頁的行數,一次I/O就能夠掃描更多的行,從而提升了訪問每個表的速度。可是因爲形成了多表鏈接,因此應該在同時查詢或更新不一樣分割表中的列的狀況比較少的狀況下使用。數據庫設計

二是保留冗餘列。當兩個或多個表在查詢中常常須要鏈接時,能夠在其中一個表上增長若干冗餘的列,以免表之間的鏈接過於頻繁,通常在冗餘列的數據不常常變更的狀況下使用。性能

三是增長派生列。派生列是由表中的其它多個列的計算所得,增長派生列能夠減小統計運算,在數據彙總時能夠大大縮短運算時間。優化

在數據庫的設計中,數據應當按兩種類別進行組織:頻繁訪問的數據和頻繁修改的數據。 
對於頻繁訪問可是不頻繁修改的數據,內部設計應當物理不規範化。 
對於頻繁修改但並不頻繁訪問的數據,內部設計應當物理規範化。 
有時還需將規範化的表做爲邏輯數據庫設計的基礎,而後再根據整個應用系統的須要,物理地非規範化數據。 
規範與反規範都是創建在實際的操做基礎之上的約束,脫離了實際二者都沒有意義。只有把二者合理地結合在一塊兒,才能相互補充,發揮各自的優勢。spa

適當拆分 
有些時候,咱們可能會但願將一個完整的對象對應於一張數據庫表,這對於應用程序開發來講是頗有好的,可是有些時候可能會在性能上帶來較大的問題。

當咱們的表中存在相似於 TEXT 或者是很大的 VARCHAR類型的大字段的時候,若是咱們大部分訪問這張表的時候都不須要這個字段,咱們就該義無反顧的將其拆分到另外的獨立表中,以減小經常使用數據所佔用的存儲空間。這樣作的一個明顯好處就是每一個數據塊中能夠存儲的數據條數能夠大大增長,既減小物理 IO 次數,也能大大提升內存中的緩存命中率。

適度冗餘 
爲何咱們要冗餘?這不是增長了每條數據的大小,減小了每一個數據塊可存放記錄條數嗎? 
確實,這樣作是會增大每條記錄的大小,下降每條記錄中可存放數據的條數,可是在有些場景下咱們仍然仍是不得不這樣作: 
1.被頻繁引用且只能經過 Join 2張(或者更多)大表的方式才能獲得的獨立小字段。 
2.這樣的場景因爲每次Join僅僅只是爲了取得某個小字段的值,Join到的記錄又大,會形成大量沒必要要的 IO,徹底能夠經過空間換取時間的方式來優化。不過,冗餘的同時須要確保數據的一致性不會遭到破壞,確保更新的同時冗餘字段也被更新。

三:其餘技巧:

1:字段類型優化 
下面的這些關於字段類型的優化建議主要適用於記錄條數較多,數據量較大的場景,由於精細化的數據類型設置可能帶來維護成本的提升,過分優化也可能會帶來其餘的問題:

(1)數字類型 
非萬不得已不要使用DOUBLE,不只僅只是存儲長度的問題,同時還會存在精確性的問題。一樣,固定精度的小數,也不建議使用DECIMAL。 
非萬不得已不要使用DOUBLE,不只僅只是存儲長度的問題,同時還會存在精確性的問題。一樣,固定精度的小數,也不建議使用DECIMAL 
(2)字符類型 
非萬不得已不要使用 TEXT 數據類型,其處理方式決定了他的性能要低於char或者是varchar類型的處理。定長字段,建議使用 CHAR 類型,不定長字段儘可能使用 VARCHAR,且僅僅設定適當的最大長度,而不是很是隨意的給一個很大的最大長度限定,由於不一樣的長度範圍,MySQL也會有不同的存儲處理。

(3)時間類型 
儘可能使用TIMESTAMP類型,由於其存儲空間只須要 DATETIME 類型的一半。對於只須要精確到某一天的數據類型,建議使用DATE類型,由於他的存儲空間只須要3個字節,比TIMESTAMP還少。不建議經過INT類型類存儲一個unix timestamp 的值,由於這太不直觀,會給維護帶來沒必要要的麻煩,同時還不會帶來任何好處。

2:合理使用索引

3:緩存機制

4:用EXPLAIN使你的SELECT查詢更加清晰

5:利用LIMIT 1取得惟一行

6: 儘可能避免SELECT *命令

7:使用ENUM而不是VARCHAR

8:儘量的使用NOT NULL 
 NULL 類型比較特殊,SQL 難優化。雖然 mysql NULL類型和 Oracle 的NULL 有差別,會進入索引中,但若是是一個組合索引,那麼這個NULL 類型的字段會極大影響整個索引的效率。此外,NULL 在索引中的處理也是特殊的,也會佔用額外的存放空間。

 不少人以爲 NULL 會節省一些空間,因此儘可能讓NULL來達到節省IO的目的,可是大部分時候這會拔苗助長,雖然空間上可能確實有必定節省,卻是帶來了不少其餘的優化問題,不但沒有將IO量省下來,反而加大了SQL的IO量。因此儘可能確保 DEFAULT 值不是 NULL,也是一個很好的表結構設計優化習慣。

參考:

http://blog.csdn.net/u013628152/article/details/51835121