mysql 資料型別 高效能mysql筆記
1.選擇優化的資料型別
更小的通常更好。
應該儘量使用可以正確儲存資料的最小型別,更小的資料型別通常更快,因為他們佔用更少的磁碟,記憶體和CPU快取,並且處理時需要的CPU週期更少。
簡單就好
更簡單的資料型別的操作通常需要更少的CPU週期。例如,整型數字比字元操作代價更低,因為字符集和校對規則(排序規則)使字元比較相對整型數字比較更復雜。比如,應使用INTERGER儲存IP地址(inet_aton)
儘量避免NULL
通常情況下,最好指定列為NOT NULL。如果查詢中包含可為NULL的列,對MySQL來說更難優化,因為可為NULL的列使得索引,索引統計和值比較非常複雜,可為NULL的列會使用更多的儲存空間,當可謂NULL的列被索引時,每個索引記錄需要一個額外的位元組。但是把可為NULL的列改成NOT NULL帶來的效能提升比較小,但如果計劃在列上建立索引,就應該避免設計成可為NULL的列。
1.1整數型別
整數型別 | 佔用空間 | 範圍 |
---|---|---|
TINYINT | 8 | [-2^7,2^7-1] |
SMALLINT | 16 | [-2^15,2^15-1] |
MEDIUMINT | 24 | [-2^23,2^23-1] |
INT | 32 | [-2^31,2^31-1] |
BIGINT | 64 | [-2^63,2^63-1] |
整型型別有可選的UNSIGNED屬性,表示不允許負值,可以使原本正數的上線提高一倍。有符號和無符號型別使用相同的儲存空間,並具有相同的效能。整型之間相互計算,是以64位的BIGINT作為中間型別進行計算的。
1.2實數型別
實數是帶有小數部分的數字,可以使用DECIMAL儲存比BIGINT還大的整數。
DECIMAL型別用於儲存精確的小數,支援精確計算。例如,DECIMAL(18,9)小數點兩邊將各儲存9個數字,一共使用9個位元組,其中小數點前面的數字使用。DECIMAL最多允許65個數字。
浮點型別在儲存同樣範圍的值時,通常比DECIMAL佔用更少的空間,內部計算時採用DOUBLE作為計算型別。
因為需要額外的空間和計算開銷,儘量只在對小鼠進行精確計算時才使用DECIMAL,在資料量比較大的時候,可以考慮使用BIGINT代替DECIMAL,講需要儲存的貨幣單位根據小數的位數乘以相應的倍數即可。
1.3字串型別
varchar
varchar型別用於儲存可變長字串,比定長更節省空間,varchar需要使用1個或2個額外位元組記錄字串的長度,如果列的最大長度小於或等於255個位元組,則只是用1個位元組表示,否則使用2個位元組。varchar節省了儲存空間,所以對效能也有幫助。但是,由於行是變長的,如果在UPDATE時增加了該邊長列的實際儲存長度,這就導致需要額外的工作,如果一個行佔用的空間增長,並且在頁內沒有更多的儲存空間可以儲存,在這種情況下,InnoDB需要分裂頁來使行可以放進頁內。
varchar使用場合:1.字串列的最大長度比平均長度大很多,列的更新很少
2.使用了UTF-8這種複合的字符集(每個字元都使用不同的位元組數儲存)
MySQL在儲存和檢索時會保留varchar尾部的空格。InnoDB可以把過長的VARCHAR儲存為BLOB。
char
定長字串,MySQL在儲存時會去除char尾部的空格。會造成“A ”與“A”產生唯一性衝突。資料如何儲存取決於儲存引擎,填充和擷取空格的行為是在MySQL服務層進行的。
更長的列會消耗更高的記憶體,MySQL通常會分配固定大小的記憶體來儲存內部值,尤其是使用記憶體臨時表進行排序或操作總是會特別糟糕。
blob
採用二進位制的方式儲存,沒有排序規則和字符集。包含tinyblob,blob,mediumblob,longblob
text
採用字串的方式儲存,有排序規則和字符集,包含tinytext,text,mediumtext,longtext。
ENUM
列舉不推薦使用
注意:
- BLOB 是二進位制資料 text是字串資料 當二者過大時mysql會在該列儲存一個1-4位元組的記憶體地址 然後在外部儲存實際的值
- varchar 的儲存會額外多1或者2個位元組儲存字串長度(字串長度小於255位元組用1)varchar的更新會產生更多碎片
- Char 是定長的會自動去除字元末尾空格 適合儲存定長較短的更新頻繁的資料如定長的Y和N (cahr型別不容易產生碎片)
- Varchar(10) 比varhcar(100) 在查詢時使用的空間更小速度更快(查詢的時候是根據varchar的大小去分配記憶體的) 在設定varchar大小的時候要儘可能接近真實資料不要過大
1.4日期和時間型別
日期時間型別 |
佔用空間 |
日期格式 |
最小值 |
最大值 |
零值表示 |
DATETIME |
8 bytes |
YYYY-MM-DD HH:MM:SS |
1000-01-01 00:00:00 |
9999-12-31 23:59:59 |
0000-00-00 00:00:00 |
TIMESTAMP |
4 bytes |
YYYY-MM-DD HH:MM:SS |
19700101080001 |
2038 年的某個時刻 |
00000000000000 |
DATE |
4 bytes |
YYYY-MM-DD |
1000-01-01 |
9999-12-31 |
0000-00-00 |
TIME |
3 bytes |
HH:MM:SS |
-838:59:59 |
838:59:59 |
00:00:00 |
YEAR |
1 bytes |
YYYY |
1901 |
2155 |
0000 |
DATETIME和TIMESTAMP
現在推薦使用DATETIME,範圍更大,與時區無關,佔用8個位元組
1.5位資料型別
InnoDB為每個BIT列使用一個足夠儲存的最小整數型別來存放,使用BIT型別並不能節省太多的儲存空間,MySQL把BIT當作字串型別,當檢索BIT(1)的值時,結果是一個包含二進位制0或者1的字串。
2.MySQL 模式設計的陷阱
2.1 太多的列
MySQL的儲存引擎API在工作的時需要在伺服器層和儲存引擎層通過行緩衝格式拷貝資料,然後在伺服器層將行緩衝內容解碼成各個列。從行緩衝中將編碼過的列轉換成行結構的操作代價非常的高,轉換的代價依賴於列的數量。
2.2太多的關聯
一個粗略的經驗法則,如果希望查詢執行的快且併發性好,單個查詢最好在12個表內做關聯
2.3NULL值
需要儲存一個事實上的“空值”到列表中時,可以使用0,某個特殊值,或者空字串代替。MySQL會在索引中儲存NULL值,而Oracle則不會。
3.正規化和反正規化
在正規化化的資料庫中,每個事實資料只會出現一次,
反正規化化的資料庫中,資訊是冗餘的,可能會儲存在多個地方。
3.1正規化化的優點和缺點
優點:
正規化化的更新操作更快,只需要更改較少的資料。
正規化化的表更小,可以更好的放在記憶體裡,執行操作會更快。
沒有多餘的資料,可以減少distinct或GROUP BY的操作。
缺點:
通常需要關聯,關聯代價昂貴,也可能使一些索引策略無效。
3.2 反正規化的優點和缺點
優點:
所有的資料都在一張表中,可以避免關聯。
不關聯的時候即使全表掃描,也是順序IO。
缺點:
冗餘的多餘資料,更新更慢
表大,放到記憶體中,佔用大,容易擠出熱資料
4.更快的讀,更慢的寫
為了提升讀查詢的速度,經常會建一些額外索引,增加冗餘列,甚至是建立快取表和彙總表,這些方法會增加寫查詢的負擔。
寫操作變慢並不是讀操作變得更快所付出的唯一代價,還可能同時增加了讀操作和寫操作的併發難度。
5.加快ALTER TABLE操作的速度
ALTER TABLE操作對特大表來說,是個大問題。
MySQL執行大部分修改表結構的步驟:
1.用新結構建立一個空表
2.從舊錶中查出所有資料插入新表
3.刪除舊錶
一般而言,大部分ALTER TABLE操作將導致MySQL服務對該表的訪問中斷。
對於常見的場景,常見的技巧有兩種:
1.現在一臺不提供服務的機器上執行ALTER TABLE操作,然後切換
2.影子拷貝,即和原來的步驟一樣,但是通過觸發器的方式更新新表舊錶資料,然後重新命名
所有的MODIFY COLUMN操作,都會導致表重建。
5.1 只修改frm(表結構)檔案
下面這些操作是有可能不需要重建的:
移除一個列的AUTO_INCREMENT屬性
增加,移除,或更改ENUM和SET常量
步驟(本操作是火中取栗):
1.建立一張有相同結構的空表,進行所需要的修改
2.執行FLUSH TABLES WITH READ LOCK。關閉所有正在使用的表,並且禁止表被開啟
3.交換frm檔案
4.執行UNLOCK TABLES來釋放第二步的讀鎖。
6.總結
1.避免設計過度複雜的資料庫模式
2.使用小而簡單的合適資料型別,儘可能避免使用NULL值
3.儘量使用相同的資料型別儲存相似或者相關的值。
4.可變長字串在臨時表和排序時有可能悲觀的按照最大長度分配記憶體。
5.儘量使用自增整數列定義主鍵
6.避免使用MySQL不再推薦的特性
7.謹慎對待BIT,ENUM,SET