高性能MySql第三版 閱讀簡記(1)

第4章 Schema與數據類型優化

4.1 選擇優化的數據類型

MySQL支持的數據類型非常多,選擇正確的數據類型對於獲得高性能至關重要。不管存儲哪種類型的數據,下面幾個簡單的原則都有助於做出更好的選擇。更小的通常更好。

一般情況下,應該儘量使用可以正確存儲數據的最小數據類型(1) 。更小的數據類型通常更快,因爲它們佔用更少的磁盤、內存和CPU緩存,並且處理時需要的CPU週期也更少。

但是要確保沒有低估需要存儲的值的範圍,因爲在schema中的多個地方增加數據類型的範圍是一個非常耗時和痛苦的操作。如果無法確定哪個數據類型是最好的,就選擇你認爲不會超過範圍的最小類型。(如果系統不是很忙或者存儲的數據量不多,或者是在可以輕易修改設計的早期階段,那之後修改數據類型也比較容易)。

簡單就好

簡單數據類型的操作通常需要更少的CPU週期。例如,整型比字符操作代價更低,因爲字符集和校對規則(排序規則)使字符比較比整型比較更復雜。這裏有兩個例子:一個是應該使用MySQL內建的類型(2)而不是字符串來存儲日期和時間,另外一個是應該用整型存儲IP地址。稍後我們將專門討論這個話題。

儘量避免NULL

很多表都包含可爲NULL(空值)的列,即使應用程序並不需要保存NULL也是如此,這是因爲可爲NULL是列的默認屬性(3)。通常情況下最好指定列爲NOTNULL,除非真的需要存儲NULL值。

如果查詢中包含可爲NULL的列,對MySQL來說更難優化,因爲可爲NULL的列使得索引、索引統計和值比較都更復雜。可爲NULL的列會使用更多的存儲空間,在MySQL裏也需要特殊處理。當可爲NULL的列被索引時,每個索引記錄需要一個額外的字節,在MyISAM裏甚至還可能導致固定大小的索引(例如只有一個整數列的索引)變成可變大小的索引。

通常把可爲NULL的列改爲NOT NULL帶來的性能提升比較小,所以(調優時)沒有必要首先在現有schema中查找並修改掉這種情況,除非確定這會導致問題。但是,如果計劃在列上建索引,就應該儘量避免設計成可爲NULL的列。

當然也有例外,例如值得一提的是,InnoDB使用單獨的位(bit)存儲NULL值,所以對於稀疏數據(4)有很好的空間效率。但這一點不適用於MyISAM。在爲列選擇數據類型時,第一步需要確定合適的大類型:數字、字符串、時間等。這通常是很簡單的,但是我們會提到一些特殊的不是那麼直觀的案例。下一步是選擇具體類型。很多MySQL的數據類型可以存儲相同類型的數據,只是存儲的長度和範圍不一樣、允許的精度不同,或者需要的物理空間(磁盤和內存空間)不同。相同大類型的不同子類型數據有時也有一些特殊的行爲和屬性。例如,DATETIME和TIMESAMP列都可以存儲相同類型的數據:時間和日期,精確到秒。

然而TIMESTAMP只使用DATETIME一半的存儲空間,並且會根據時區變化,具有特殊的自動更新能力。另一方面,TIMESTAMP允許的時間範圍要小得多,有時候它的特殊能力會成爲障礙。

4.1.1 整數類型

有兩種類型的數字:整數(whole number)和實數(real number)。如果存儲整數,可以使用這幾種整數類型:TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT。分別使用8,16,24,32,64位存儲空間。它們可以存儲的值的範圍從−2(N−1)到2(N−1)−1,其中N是存儲空間的位數。

整數類型有可選的UNSIGNED屬性,表示不允許負值,這大致可以使正數的上限提高一倍。例如TINYINT UNSIGNED可以存儲的範圍是0~255,而TINYINT的存儲範圍是−128~127。

4.1.2 實數類型

實數是帶有小數部分的數字。然而,它們不只是爲了存儲小數部分;也可以使用DECIMAL存儲比BIGINT還大的整數。MySQL既支持精確類型,也支持不精確類型。

因爲CPU不支持對DECIMAL的直接計算,所以在MySQL 5.0以及更高版本中,MySQL服務器自身實現了DECIMAL的高精度計算。相對而言,CPU直接支持原生浮點計算,所以浮點運算明顯更快。

浮點和DECIMAL類型都可以指定精度。對於DECIMAL列,可以指定小數點前後所允許的最大位數。這會影響列的空間消耗。MySQL 5.0和更高版本將數字打包保存到一個二進制字符串中(每4個字節存9個數字)。例如,DECIMAL(18,9)小數點兩邊將各存儲9個數字,一共使用9個字節:小數點前的數字用4個字節,小數點後的數字用4個字節,小數點本身佔1個字節。

因爲需要額外的空間和計算開銷,所以應該儘量只在對小數進行精確計算時才使用DECIMAL——例如存儲財務數據。但在數據量比較大的時候,可以考慮使用BIGINT代替DECIMAL,將需要存儲的貨幣單位根據小數的位數乘以相應的倍數即可。假設要存儲財務數據精確到萬分之一分,則可以把所有金額乘以一百萬,然後將結果存儲在BIGINT裏,這樣可以同時避免浮點存儲計算不精確和DECIMAL精確計算代價高的問題。

例如:

如果我想存儲精確度以 "分" 爲單位的數字."99.75元"

1.可以將數據庫中的列數據模型設計爲: 

ALTER TABLE demo_table ADD column_1 decimal(5,2) NULL;

譯:意思是添加一列小數點前可存放5位,小數點後可存放2位的數字;然後將"99.75"元直接存放進庫中

2.可以將數據庫中的列數據模型設計爲: 

ALTER TABLE demo_table ADD column_1 bigint(10) NULL;

譯:意思是添加一列較長的數字;並且在sql查詢/添加或者 在代碼中  將金錢乘以"100",得到"9975"然後存放庫中,取出時使用金錢除以100,換算成正確的金錢數額"99.75"; 

附錄:

(1) 例如只需要存0~200,tinyint unsigned更好。——譯者注
(2) date,time,datatime——譯者注
(3) 如果定義表結構時沒有指定列爲NOT NULL,默認都是允許爲NULL的。
(4) 很多值爲NULL,只有少數行的列有非NULL值。——譯者注

說明:當前內容爲從書中摘抄部分文字,添加部分例子,已記錄自己所得.如有侵權,請聯繫刪除!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章