[MySQL] 基礎數據類型優化

  1. 整數類型
    存儲整數可使用TINYINT \ SMALLINT \ MEDIUMINT \ INT \ BIGINT,分別對應8、16、24、32、64位存儲空間,可選用需求範圍內最小的數據類型。INT UNSIGNED等表示對應的無符號類型。
    MySQL可以爲整數指定寬度,如INT(11),但這樣對存儲不會有影響 ,只是指定了交互工具顯示的字符個數(如命令行等工具)

  2. 實數類型
    FLOAT & DOUBLE類型使用了浮點運算進行的近似計算,分別佔用4個和8個字節。相比之下DECIMAL類型可指定精確的位數,但在計算中還是會轉爲DOUBLE類型進行浮點運算的。
    在DECIMAL中指定的位數並沒有標準實現方式,因此不推薦指定。只有必要時(如財務計算)纔會使用到DECIMAL,但實際上可以採用BIGINT類型來代替存儲(如需要精確到萬分之一,就將數據乘以一百萬存入數據庫),以避免DECIMAL的浮點計算不精確、開銷大問題。

  3. 字符串類型

    1. VARCHAR和CHAR類型:不同存儲引擎可能有自己的實現方式。
      VARCHAR可以存儲變長的字符串,需要額外的1~2個字節存儲長度信息(長度<=255時使用1個字節,否則2個)。若在MySQL表中使用ROW_FORMAT=FIXED創建表,每行的存儲長度就變成了定長,若又使用到VARCHAR,會非常浪費空間。 相比於CHAR類型,由於其不定長,更新效率會更長。
      CHAR類型會剃除末尾空格(總會在後面填充空格以實現定長字符串),VARCHAR在4.1以及更老版本時也會這樣而新版不會。
      VARCHAR適合的使用場景有:字符串的最大長度比平均長度大很多;列的更新較少;使用了UTF8這樣的複雜字符集使得長度不確定。CHAR適合的使用場景有:所有值長度接近如密碼MD5值、Y或N值等等。
      另外還有兩個類似的類型BINARY與VARBINARY分別對應二進制字串與變長二字制字串。

    2. BLOB和TEXT類型
      對應於整數,TEXT與BLOB也有TINYTEXT \ SMALLTEXT \ TINYBLOB等等。其中TEXT是普通字符串,而BLOB是二進制字符串。
      與其它類型不同,MySQL會將TEXT與BLOB當作一個獨立的對象處理,通常會做特殊處理。如InooDB會在此類型的值過大時,使用外部、專門的存儲區域存儲這個值,並在原行處存一個1~4字節的指針。
      另一個不同點在於,對此類型排序時只比較前max_sort_length個字符,若有特殊需求可配置此值或使用ORDER BY SUBSTRING(column, length)

    3. ENUM(枚舉)代替字符串
      把一些不重複的字符串存儲爲預定義的集合,可將此類值壓縮成一到兩個字節中。SQL語句如下:

      CREATE TABLE enum_test(
          e ENUM('fish', 'apple', 'dog') NOT NULL
      )
      INSERT INTO enum_test(e) VALUES('apple'), ('dog')

      SELECT e+0 FROM enum_test將返回1至3的數字,值得一提的是,其內部的排序規則不是字母序,而是按內部存儲的整數(1~3)排序。

  4. 日期和時間類型
    MySQL中的存儲只能精確到秒,大體來說有DATETIME與TIMESTAMP兩種日期類型。
    其中DATETIME能保護1001年至9999年,範圍較大。其被存儲至格式爲YYYYMMDDHHMMSS格式的整數中,並且與時區無關。
    而TIMESTAMP,保存的是自1970年1月1日(格林威治標準時間)以來的秒數,與UNIX時間戳相同,只需要4個字節存儲,因此其範圍比DATETIME小得多,只能表示1970年至2038年。MySQL提供了FROM_UNIXTIME()函數將時間戳轉爲日期,也提供了UNIX_TIMESTAMP()函數將日期轉爲時間戳。
    爲了效率快,應使用效率更高的TIMESTAMP。若需要比秒更精確的單位,只能手動使用BIGINT等整數類型存儲時間。

  5. 位數據類型

    1. BIT
      BIT在舊版的MySQL(5.0之前)中,與TINYINT是同義詞。在新版中成爲一個獨特的新類型,使用BIT(n)存儲n個0/1位,n最大爲64。
      但其在各個存儲引擎中的表現不同,如MyISAM只需要17個位就可以存儲BIT(17),而InnoDB \ Memory則需要使用足夠的最小整數類型來存放(在此處即32位整數)。BIT類型可以理解爲一個01的二進制值,如BIT(8)值爲’00111001’時,即可存儲爲數字57,展示出來也就是對應ASCII碼57號字符’9’。這種方式非常令人費解,因此應該謹慎使用(最好避免使用)。
      如果希望使用一個位存儲0或1,也不一定要使用BIT(1),可以使用CHAR(0)來代替,其值可以爲NULL或空串”“。
    2. SET
      如果需要保存很多個true/false值,可以使用SET,並且MySQL中提供了FIND_IN_SET()等函數來方便操作。但是此類型有一個劣勢在於改變SET的定義需要ALTER此表,在大表中的修改代價昂貴。一個較好的方法是使用整型的01位來表示true或false,並在應用中定義各個位的意義。
  6. 選擇標識符(IDENTIFIER)
    舉例來說,比如需要一個state_id字段來標識此物品所在的美國某州,那可以使用哪些類型呢?通常來說有整數、ENUM\SET、字符串三種。
    ENUM\SET只適用於極固定的東西,擴展效率低,而字符串的讀寫和操作效率都很低。因此推薦使用整數,並且儘可能使用最小的整數類型即可(如TINYINT等)
    比如存儲UUID時,推薦去除-,或使用UNHEX()函數轉爲16字節數字存入BINARY(16)類型中,取出時可使用HEX()格式化回普通的16進制UUID值。

  7. 特殊類型
    比較典型的一個特殊數據是IPv4地址,人們常用VARCHAR(15)來存儲。然而它實際上是32位無符號整數,只是平時用小數點將其分爲四段,方便人們閱讀而已。MySQL中提供了INET_ATON()INET_NTOA()兩個函數爲IPV4和32位無符號整數提供相互轉換。

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