1. 程式人生 > >[MySQL] 基礎資料型別優化

[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位無符號整數提供相互轉換。