MySQL數據類型與優化

關於數據類型的優化

1、假如只需要存0~255之間的數,無負數,應使用tinyint unsigned(保證最小數據類型)
2、如果長度不可定,如varchar,應該選擇一個你認爲不會超過範圍的最小類型
比如: varchar(20),可以存20箇中文、英文、符號,不要無腦使用varchar(150)
3、整形比字符操作代價更低。比如應該使用MySQL內建的類型(date/time/datetime)而不是字符串來存儲日期和時間
4、應該使用整形存儲IP地址,而不是字符串
5、儘量避免使用NULL,通常情況下最好指定列爲NOT NULL,除非真的要存儲NULL值
6、DATETIME和TIMESTAMP列都可以存儲相同類型的數據:時間和日期,且精確到秒。然而TIMESTAMP只使用DATETIME一半的內存空間,並且會根據時區變化,具有特殊的自動更新能力。另一方面,TIMESTAMP允許的時間範圍要小得多,有時候它的特殊能力會變成障礙


整數類型 
1、TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT分別使用8(-127~127或0~255)、16(0~65535)、24(0~1600萬)、32、64位存儲空間。 
2、整數類型有可選的UNSIGNED屬性,表示不允許負值,這大致可以使正數的上限提高一倍。有符號和無符號類型使用相同的存儲空間,有相同的性能,具體情況具體考慮。
3、MySQL可以爲整數類型指定寬度,例如INT(11),對大多數應用這是沒有意義的,INT(1)和INT(20)相同,它不會限制值的合法長度,除非使用zerofill。


實數類型
1、實數是帶有小數部分的數字。然而它們不只是爲了存儲小數部分,還可以使用DECIMAL存儲比BIGINT還大的整數。MySQL既支持精確類型,也支持不精確類型。
2、FLOAT和DOUBLE類型支持使用標準的浮點運算進行"近似"計算,注意!是近似計算。
3、DECIMAL類型用於存儲精確的小數。但在MySQL4.1 以及更早版本只能使用"浮點運算"來實現DECIMAL的計算,這樣可能會導致精度損失。因爲CPU不支持對DECIMAL的直接計算,在MySQL5.0及更高版本中,MySQL服務器自身實現了DECIMAL的高精度計算。相對而言,CPU直接支持原生的浮點運算,所有浮點運算明顯更快。
4、浮點和DECIMAL類型都可以指定精度。對於DECIMAL列,可以指定小數點前後所允許的最大位數,這會影響列的空間消耗。
5、MySQL5.0或更高的版本,將數字打包保存到一個二進制字符串中(每4個字節存9個數字)。DECIMAL(18,9)使用了9個字節,小數點左右各4個字節,小數點1個字節。

VARCHAR和CHAR類型
VARCHAR類型
1、VARCHAR和CHAR是兩種最重要的字符串類型。
2、VARCHAR類型需要使用1或2個額外字節記錄字符串的長度:如果列的最大長度小於或等於255字節,則只使用1個字節表示,否則使用2個字節。
3、INNODB會把過長的VARCHAR存儲爲BLOB(二進制方式存儲的字符串)。
CHAR類型
1、CHAR類型是定長的,對於不確定長的字符串,VARCHAR更省空間,因爲它並定長類型更節省空間,僅使用必要的空間。
2、CHAR類型適合存儲很短的字符串,或者所有值都很接近同一個長度,例如MD5。
3、經常變更的數據,CHAR也比VARCHAR更好,因爲定長的CHAR類型不易產生碎片。
4、在MySQL5.0或更高的版本,VARCHAR類型在存儲和檢索的時候會保留末尾空格,但在4.1或更老的版本,會剔除末尾的空格。而CHAR類型在新老版本都會查詢末尾的空格。

BLOB和TEXT類型
1、BLOB和TEXT類型都是爲了存儲很大的數據而設計的字符串數據類型,只是存儲方式不同,分別採用二進制和字符方式存儲。
2、實際上,它們分別屬於兩組不同的數據類型家族:字符類型是TINYTEXT、SMALLTEXT、TEXT、MEDIUMTEXT、LONGTEXT;對應的二進制類型是TINYBLOB、SMALLBLOB、BLOB、MEDIUMBLOB、LONGBLOB、BLOB。其中BLOB是SAMLLBLOB的同義詞,TEXT是TINYTEXT的同義詞。
3、與其他類型不同,MySQL把每個BLOB和TEXT值當做一個獨立的對象處理。存儲引擎在存儲時通常會特殊處理。當BLOB和TEXT值太大時,InnoDB會使用專門的"外部"存儲區域來進行存儲,此時每個值在行內需要1~4個字節存儲一個指針,然後在外部存儲趨於存儲實際的值。
4、BLOB和TEXT家族之間僅有的不同是BLOB類型存儲的是二進制數據,沒有排序規則或字符集,而TEXT類型有字符集和排序規則。
5、MySQL對BLOB和TEXT列進行排序與其他類型是不同的:它只對每個列的最前max_sort_length字節而不是整個字符串做排序。如果只需要排序前面一小部分字符,則可以減小max_sort_length的配置,或者使用ORDER BY SUBSTRING(column, length),將列值轉換爲字符串(在ORDER BY子句中也適用),這樣就可以生成內存臨時表了。這招對內存中創建大臨時表和文件排序,以及在存盤上創建大臨時表和文件排序這兩種情況都很有幫助。
6、MySQL不能將BLOB和TEXT列全部長度的字符串進行索引,也不能使用這些索引消除排序。
7、PLUS:如果EXPLAIN執行計劃的Extra列包含"Using temporary",則說明這個查詢使用了隱式臨時表。

枚舉(ENUM)
1、有時候可以使用枚舉類型代替常用的字符串類型。枚舉列可以把一些不重複的字符串存儲成一個預定義的集合。MySQL在存儲枚舉時非常緊湊,會根據列表值的數量壓縮到一個或兩個字節中。MySQL在內部會將每個值在列表中的位置保存爲整數,並且在表的.frm文件中保存"數字-字符串"映射關係的"查找表"。
2、枚舉字段是按照內部存儲的整數而不是定義的字符串進行排序的。繞過這種限制的方式是按照需要的順序來定義枚舉列,另外也可以在查詢中使用FIELD()函數顯式地指定排序順序,但這會導致MySQL無法利用索引消除排序,如果定義時候就是按照字母順序,就沒有那麼做的必要了。
3、枚舉最不好的地方就是字符串列表是固定的,添加或刪除字符串必須使用ALTER TABLE。對於一系列將來可能會改變的字符串,枚舉可能不是一個很好的選擇,除非能接收在列表末尾添加元素。
4、由於MySQL把每個枚舉值都保存爲整數,並且必須進行查找才能轉換爲字符串,所以枚舉列有一些開銷,通常枚舉列都比較小,所以開銷還可以控制,在特定情況下,把CHAR/VARCHAR列與枚舉列進行關聯可能會直接比關聯CHAR/VARCHAR列更慢。

日期和時間類型
MySQL可以使用許多類型來保存日期和時間值,例如YEAR和DATE。MySQL能存儲的最小時間粒度爲秒(MariaDB支持微妙級別的時間類型)。
DATETIME
1、這個類型能保存大範圍的值,從1001年到9999年,精確度爲秒。
2、它把日期和時間裝到格式爲YYYYMMDDHHMMSS的整數中,與時區無關。使用8個字節的存儲空間。
3、默認情況下,MySQL以一種可排序的、無歧義的格式顯示DATETIME值,例如"2019-11-05 21:35:54"。這是ANSI標準定義的日期和時間表示方法。

TIMESTAMP
1、TIMESTAMP類型保存了從1970年1月1日午夜(格林尼治時間)以來的秒數,它和UNIX時間戳相同。
2、TIMESTAMP只使用4個字節存儲空間,它只能表示從1970年到2038年。
3、MySQL提供了FROM_UNIXTIME()函數把UNIX時間戳轉換爲日期,提供了UNIX_TIMESTAMP()函數把日期轉換爲Unix時間戳。
4、TIMESTAMP顯示的值依賴於時區,如果在多個時區存儲和訪問數據,TIMESTAMP和DATETIME的行爲很不一樣。前者提供的值與時區有關係,後者則保留文本表示的日期和時間。
5、默認情況下,如果插入時沒有指定第一個TIMESTAMP的值,MySQL則設置這個列的值爲當前時間。在插入一行記錄時,MySQL默認也會更新第一個TIMESTAMP列的值(除非在UPDATE語句中明確指定了值)。
6、TIMESTAMP列默認爲NOT NULL。
總結:儘量使用TIMESTAMP,因爲它比DATETIME空間效率更高。

 

標識符
1、整數通常是標誌符最好的選擇,因爲它們很快並且可以使用AUTO_INCREMENT。
2、應避免使用字符串類型作爲標誌符,因爲它們很消耗空間,並且通常比數字類型慢,有其是在MyISAM表中使用字符串作爲標識符要特別小心,MyISAM默認對字符串壓縮索引,這會導致查詢慢很多。
3、對於完全"隨機"的字符串也需要多加註意,例如MD5()、SHA1()或者UUID()產生的字符串。這些函數生成的新值會任意分佈在很大的空間內,這會導致INSERT以及一些SELECT語句變得很慢。因爲新插入的值會隨機寫索引到不同的位置,所以使得INSERT語句很慢。這會導致頁分裂、磁盤隨機訪問,以及對於聚簇索引存儲引擎產生聚簇索引碎片。SELECT語句會變得更慢,因爲邏輯上相鄰的行會分佈在磁盤和內存的不同地方。
4、UUID生成的值與加密散列函數例如SHA1()生成的值有不同的特徵;UUID值雖然分佈不均勻,但還是有一定的順序,儘管如此都不如遞增的整數好用

特殊類型數據(IP地址)
1、對於IPV4地址,人們常用VARCHAR(15)列來存儲IP地址。然而它們實際上是32位無符號整數,不是字符串。用小數點分成四段的表示方法只是爲了讓人們閱讀更容易。所以應該用無符號整數存儲IP地址。MySQL提供INET_ATON()和INET_NTOA()函數在這兩種表示方法之間轉換。

MySQL schema設計中的陷阱
1、太多的列。MySQL的存儲引擎API工作時需要在服務層和存儲引擎層之間通過行緩衝格式拷貝數據,然後在服務器層將緩衝內容解碼成各個列。從行緩衝中將編碼過的列轉換成行數據結構的操作代價是非常高的。MyISAM的定長行結構實際上與服務器層的行結構正好匹配,所以不需要轉換。然而MyISAM的變長行結構和InnoDB的行結構總是需要轉換,轉換的代價依賴於列的數量。
2、太多關聯。MySQL限制了每個關聯操作最多只能有61張表,但單個查詢最好在12個表以內做關聯。
3、防止過度使用枚舉。
4、儘可能避免使用NULL值,可以使用其他值替代。

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