MySQL之 爲表中的字段選擇合適的數據類型

爲表中的字段選擇合適的數據類型

1、當一個列可以選擇多種數據類型時,應該優先考慮數字類型,其次是日期和二進制類型,最後是字符類型。

2、對於相同級別的數據類型,應該優先選擇佔用空間小的數據類型。


之所以這樣說,是有以下幾個原因:

1、首先在對數據進行比較,比如查詢條件、關聯排序時,字符處理,與當前所使用的排序規則是相關的,而數字與二進制則不需要參照字典的排序規則,其處理是按照二級制的大小來進行的,同樣的數據,字符串處理往往要比數字慢;

2、另外在數據庫中,數據處理是以頁爲單位的,每個頁能存儲的數據量是一定的,在INNODB中是16K,列的長度越小,就意味着列能夠在頁中容納的數據行就越多,這樣在加載同樣的數據時,使用寬度較小的類型,要比使用寬度較大的類型所要加載的數據頁就少,從而也減少了磁盤IO,有利於性能的提升。


正確選擇整數類型:

正確選擇實數類型:


如,DECIMAL(18, 9)就需要9個字節來存儲。前面九個數字,佔4個字節,後面九個數字,佔4個字節,小數點佔1個字節,總共,9個字節。

MySQL5.0 版本之後,DECIMAL最多允許存儲65個數字,這對於我們實際操作,已經完全足夠了。如果我們的業務涉及到財務,就得使用DECIMAL這種精確數字的類型。而對於其他的情況,就可以使用DOUBLE和FLOAT這些類型。


正確選擇VARCHAR和CHAR類型:

VARCHAR長度的選擇問題

1、使用最小符合需求的長度。

這個要做到,不容易,首先,我們很難確定,什麼是最小的符合需求的長度,這個要根據業務來定,比如用戶姓名這一列,如果只存中文名,長度應該不會超過10個字符,因爲,很少幾乎就沒有中國人的姓名有10個字,但是,如果還要存儲外國人的姓名,那麼,寬度可能要增加到20個寬度的字符了,外國人的姓名通常是很長的。但是,無論如何也不應該使用VARCHAR 255 來定義列的長度,因爲也沒有人會有這麼長的名字。    

另外,還有一個點要注意,雖然我們希望VARCHAR類的長度儘可能的小,但是,我們也不能不顧業務的情況,而去故意設小,並想着,以後長度不夠了,再改唄,如果這麼想,那就大錯特錯了,因爲業務一旦上線,再進行列的寬度的修改的話,那樣做的成本是非常大的,在MySQL5.7之前的版本中,對於VARCHAR類的寬度,無論是改大還是改小,都是要鎖表的。就算是在MySQL5.7版本之後,也只是說,如果VARCHAR列的寬度是在255個字節以內,改變後的寬度同樣不超過255個字符,這樣,是可以不鎖表的。

注意,在生產環境中,如果發生鎖表,在一個繁忙的系統中,肯定會發生很嚴重的系統性能問題。

2、VARCHAR(5)和VARCHA(255) 存儲”MySQL”字符串性能的不同。

這兩個長度都是沒有超過255的,所以,都需要佔用1個額外的存儲字節,來存儲字符串的長度,因此,存儲MySQL這個字符串,只需要6個字節,就夠了,那麼,我們還有必要選擇最小的列的寬度麼?不是不超過255個長度,存儲都是一樣的麼?其實,答案是,我們還是需要選擇最小的列的寬度的,這是因爲,MySQL爲了能夠更有效地優化查詢,所以在內存中,對於字符串使用的是固定的寬度,特別是在使用一些隱式的內存臨時表的時候,更是這樣,所以,如果我們把列的寬度定義的太長,就會消耗更多的內存,所以,這纔是我們要求對MySQL的列的寬度來選擇最小的符合需求的長度的原因。


VARCHAR的適用場景

1、適合字符串列的最大長度比平均長度大很多的字符串。這種情況,更能發揮出VARCHAR列變長存儲的特點。
2、適合字符串很少被更新的列。
3、適合使用多字節字符集存儲字符串的列,比如UTF8,因爲這樣的字符集,可能使用不同的字節數進行存儲,以UTF8爲例,如果我們存儲中文,可能需要3個字節,而如果存儲英文和數字,則只需要一個字節。


CHAR類型的存儲特點

1、CHAR類型是定長的。MySQL總是根據定義的CHAR類型的寬度,來分配足夠的空間,存儲CHAR類型中的數據。也就是說,如果我們定義的CHAR類型的寬度是50,如果只存儲了10個字符,那麼在存儲時,也會分配50個字符的存儲空間。

2、CHAR類型中存儲的字符串的末尾如果存在空格,那麼末尾的空格將會被刪除。同樣的,VARCHAR中,就不會刪除末尾的空格。

3、CHAR類型的最大寬度只有255,如果超過這個寬度,則要使用VARCHAR類型。


CHAR類型中的存儲場景

1、CHAR類型適合存儲長度近似的值的長度。因爲CHAR類型是定長的,如果長度接近某個值的,則可以給其一個固定的長度。這樣就不會浪費存儲空間和內存,這類字符串,有一個很好的例子,那就是MD5值,加密存儲32位定長長度的字符,這種情況,就非常適合,另外,身份證,手機號,也很適合CHAR類型字段的存儲。

2、CHAR類型適合存儲短字符串。短的字符串,存儲在CHAR類型中,比存儲在VARCHAR類型中,更節省空間。比如我們有一個列,用來存儲用戶的性別,男或女,使用CHAR(1)比使用VARCHAR(1)更適合,同樣,以UTF8爲例,在CHAR類型存儲,只需要3個字節,而VARCHAR(1)因爲還需要一個額外的字節來存儲變長字符串的長度,所以,使用VARCHAR就需要4個字節,所以,從這種情況來看,短字符,使用CHAR比VARCHAR更有效率。

3、CHAR類型適合存儲經常更新的數據的列。因爲CHAR類型的長度是固定的,MySQL會一次性地存儲足夠的空間,所以,在多次更新時也不會產生頁分裂的情況,也可以避免產生存儲碎片,獲取更好的IO性能。

正確地選擇存儲日期數據:

DATETIME類型

以YYYY-MM-DD HH:MM:SS[.fraction] 格式存儲日期時間。默認情況,是以    年月日時分秒的格式來存儲時間的,即datetime = YYYY-MM-DD HH:MM:SS。在MySQL5.6之前,能夠存儲的最小的精度是秒,而在MySQL5.6之後,可以存儲到微秒。

如果我們想保存微秒,就要爲DATETIME定義一個寬度,寬度的最大值是6,    如:
datetime(6) = YYYY-MM-DD HH:MM:SS.fraction

DATETIME是與時區無關的,佔8個字節的存儲空間。還有一點需要注意,那就是,DATETIME的存儲範圍 1000-01-01 00:00:00 到 9999-12-31 23:59:59。通常情況下,我們都可以使用DATETIME來存儲時間。


TIMESTAMP類型

它是一種非常有特色的日期時間類型,從名字來看,我們就能知道,這種類型存儲的是時間戳,也就是格林尼治時間1970年1月1日到當前時間的秒數。這和我們所熟悉的UNIX時間戳,是一樣的。

默認是以YYYY-MM-DD HH:MM:SS.[.fraction]格式顯示,佔用4個字節。由此,我們可以看出,TIMESTAMP類型要比DATETIME類型小的多,更加節約空間。

時間範圍:1970-01-01 到 2038-01-19

TIMESTAMP類型顯示依賴於所指定的時區。在不同的時區下,顯示不同的值,如果我們是在多個時區使用這個類型,就需要注意。

另外,在當前行的數據,修改時,可以自動修改TIMESTAMP列的值。這個功能,非常有用,我們經常用這個功能標明每行數據的最好修改時間。


DATE和TIME類型

在MySQL5.6,又增加了DATE和TIME兩種時間類型,在保存時間數據時,我們經常會有這樣的需求,比如存儲生日,那麼,就只需要存儲日期,而不用存儲時間,這種情況,在MySQL5.6之前,我們通常這麼實現:

1、把日期部分存儲爲字符串(至少要8個字節)
2、使用INT來存儲(4個字節)
3、使用DATETIME類型來存儲(需要8個字節)

DATE類型的優點:

1、佔用的字節數比使用字符串、DATETIME、INT存儲要少,使用DATE類型,只需要3個字節。
2、使用DATE類型,還可以利用日期時間函數進行日期之間的計算。這是INT類型、字符串類型存儲日期所做不到的。
3、DATE的時間範圍是 1000-01-01 到 9999-12-31.


TIME類型

主要用於存儲時間數據,格式爲HH:MM:SS,同時,也可以指定寬度來保存微秒的數據。


存儲日期時間數據的注意事項:

1、不要使用字符串類型來存儲日期時間數據。在實際的開發過程中,很多開發人員喜歡使用字符串來存儲日期時間數據,這樣,是不合適的,因爲日期時間類型通常比字符串佔用的存儲空間小。其次,日期時間類型在進行查找過濾時,可以利用日期來進行對比,如果我們使用字符串,那麼就只能按照字符集來順序進行過濾了。還有,日期時間類型還有着豐富的處理函數,可以方便的對日期類型來進行日期計算。

2、使用INT存儲日期時間不如使用TIMESTAMP類型。如果要存儲UNIX時間戳的話,用INT還不如直接使用TIMESTAMP類型,因爲這個類型本身就是以INT類型來存儲的,只不過顯示的是以年月日時分秒的格式顯示的,所以,在使用時更加方便,不用每次使用都用函數來進行轉換,就可以很直觀地看出時間。
 

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