MySQL 的性能(下篇)—— 性能優化方法


簡介

文中內容均為閱讀前輩的文章所整理而來,參考文章已在最后全指明

本文分為上下兩篇:

下面為下篇內容,分為以下部分:

  • 一、創建表時的性能優化
  • 二、設計表時的性能優化
  • 三、優化 SQL 語句
  • 四、其它

一、創建表時的性能優化

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

每張表都應該設置一個 ID 字段為主鍵,該主鍵應為 INTUNSIGNED 類型,並設置上自動增加的 AUTO_INCREMENT 標志。因為使用 VARCHAR 類型的主鍵,會使得性能下降。

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

2. 為搜索字段建索引

詳情見我之前的文章:MySQL 索引

3. 使用 ENUM 而不是 VARCHAR

ENUM 類型是非常快和緊湊的。在實際上,其保存的是 TINYINT,但其外表上顯示為字符串。這樣一來,用這個字段來做一些選項列表變得相當的完美。

如果你有一個字段,比如 “國家”,你知道這些字段的取值是有限而且固定的,那么,你應該使用 ENUM 而不是 VARCHAR。

ENUM 是 MySQL 數據庫特有的字段類型,使用后會影響遷移到其它數據庫。所以,如果以后又改數據庫的情況,一定要慎用

4. 盡可能的使用 NOT NULL

應該總是讓你的字段保持 NOT NULL,因為這樣節省空間(NULL 也是需要空間的)。

5. 把IP地址存成 UNSIGNED INT

如果使用整形來存放 IP 而不是 VARCHAR(15) 字段,節省了很多的空間(需要寫一個 IP 轉換的函數)。

二、設計表時的性能優化

1. 選擇正確的存儲引擎

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

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

2. 固定長度的表會更快

表中沒有如下類型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一個這些字段,那么這個表就不是“固定長度靜態表”了,這樣,MySQL 引擎會用另一種方法來處理。

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

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

使用“垂直分割”技術(見下一條),你可以分割你的表成為兩個一個是定長的,一個則是不定長的。

3. 垂直分割

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

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

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

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

三、優化 SQL 語句

1. 使用查詢緩存

1.1 查看是否開啟緩存:

mysql> select @@query_cache_type;
+--------------------+
| @@query_cache_type |
+--------------------+
| ON                 |
+--------------------+

開啟緩存,修改 my.cnf,在末尾加入,重啟MySQL生效

query_cache_type = 1
query_cache_size = 600000

1.2 為查詢緩存優化你的查詢

// 查詢緩存不開啟
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 >= '%s'" % today);

上面兩條 SQL 語句的差別就是 CURDATE(),MySQL 的查詢緩存對這個函數不起作用。所以,像 NOW()RAND() 或是其它的諸如此類的 SQL 函數都不會開啟查詢緩存,因為這些函數的返回是會不定的易變的。所以,你所需要的就是用一個變量來代替 MySQL 的函數,從而開啟緩存

2. 當只要一行數據時使用 LIMIT 1

在這種情況下,加上 LIMIT 1 可以增加性能。這樣一樣,MySQL 數據庫引擎會在找到一條數據后停止搜索,而不是繼續往后查少下一條符合記錄的數據。

3. 在 JOIN 表的時候使用相當類型的例,並將其索引

如果有很多 JOIN 的操作,JOIN 的字段應該加索引,同時保證這些字段的類型一致

4. 避免 SELECT *

從數據庫里讀出越多的數據,那么查詢就會變得越慢。所以,應該養成需要什么就取什么的好的習慣

5. 拆分大的 DELETE 或 INSERT 語句

如果你需要在一個在線的網站上去執行一個大量的 DELETE 或 INSERT 查詢,你需要非常小心,要避免你的操作讓你的整個網站停止相應。因為這兩個操作是會鎖表的,表一鎖住了,別的操作都進不來了。

執行這種大量的 DELETE 和 INSERT,可以分成幾部分執行,沒執行一部分就暫停一下再執行。

四、其它

1. EXPLAIN 你的 SELECT 查詢

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

查看 rows 列可以讓我們找到潛在的性能問題。

2. 從 PROCEDURE ANALYSE() 取得建議

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

mysql> select * from charac procedure analyse()
*************************** 1. row ***************************
Field_name: world.charac.charac
Min_value: A
Max_value: E
Min_length: 1
Max_length: 1
Empties_or_zeros: 0
Nulls: 0
Avg_value_or_avg_length: 1.0000
Std: NULL
Optimal_fieldtype: ENUM('A','B','C','D','E') NOT NULL
1 row in set (0.00 sec)

3. 使用連接池和 ORM

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM