MySQL學習 - 數據類型的選擇

1. 類似的,數據類型間的,比較


1.1 原則上咱們但願你這樣去選擇數據類型

  • 夠用的狀況下,越小越好
  • 使用簡單的數據類型:       理論上MySQL內建類型處理起來更加方便,int會比varchar好處理
  • 儘可能避免使用NULL:          NULL的使用使得MySQL的優化比較難以執行下去
  • 在你設計一張表的時候:   你最好先肯定大的類型例如int, 而後再去肯定小類型如int8


1.2 整數類型

  • TINYINT / SMALLINT / ... / BIGINT 消耗的存儲空間逐漸變大
  • 在它們前面加上 UNSIGNED 標誌能進一步將存儲能力加大一倍
  • 涉及整數計算 最好使用 64 位的 BIGINT
  • INT(11) 這種寫法大部分狀況下都沒什麼意義
    • INT(11) 存儲能力 = INT(1) 
    • INT(11) 計算能力 = INT(1)
    • 在Mysql一些客戶端中,有時候INT(11)會只顯示11字符


1.3 實數類型

  • FLOAT[4] / DOUBLE[8] / DECIMAL(a,b) [ max(a,b) + 2 ] 
    • FLOAT / DOUBLE 是常見的單雙精度數據,計算過程由CPU本身實現
    • DECIMAL類型的出現是爲了存更加精確的小數。 假設你精確到了必定程度,那麼CPU自己是沒有實現這種東西的計算過程的。 
      • 所以在MYSQL-5.0之前其實是由浮點數模擬的DECIMAL計算
        故而可能會損失一些精度
      • 5之後的版本MYSQL本身實現了DECIMAL計算
        可是就快而言,天然是CPU自身實現計算會更快
  • MYSQL自己存在一種機制,即便你自身指定了精度,可是實際存儲的過程當中仍是會作出一些取捨,能夠說是本身在悄悄優化,因此建議只指定類型,不要指定精度


1.4 字符串類型

  • VARCHAR(變長) - 存儲的時候僅消耗一些必要的空間,可是會額外消耗1~2字節記錄長度
    • 最好不要老是更新VARCHAR
      • 假設變長了,可能致使內存頁內沒有更多空間存儲
      • 假設變短了,可能出現一個沒法被利用的內存碎片
    • 字符串長度波動幅度很是大的時候用,能佔到便宜
  • CHAR(定長)
    • MD5這樣的定長度值
    • 由於長度不會變,所以內存利用效率更高
  • VARCHAR & CHAR 具體是如何存儲的這要看存儲引擎怎麼決定
  • 一些行爲諸如TRIM是由MYSQL數據庫決定的
  • 若是真的按照你說的,VARCHAR只作必要的開銷,那麼VARCHAR(5) == VARCHAR(200)嗎


1.5 枚舉ENUM類型

  • 假設如今有三種字符串A/B/C,在使用ENUM的狀況下實際存儲的時候會變成1/2/3。在對這一列進行排序的時候,也是按照1/2/3的方式進行排序的。
  • 很差的地方:  
    • 排序的時候須要使用FILED( )來指定排序,不然就會按照1/2/3排序
    • 由於ENUM的candidate是固定的,所以但凡想要作出一些修改,最大的可能就是ALTER TABLE
    • 由於實際存儲的時候是按照1/2/3存儲的,所以轉換存在一些開銷,好在大部分時候這個映射表並不大,所以開銷也不是很大
  • 好的地方:
    • 假設某個屬性成爲了主鍵的一部分,面臨一些作聯表的可能,在聯表的時候,作過ENUM映射的表,聯的時候會比單純的字符串快不少
    • 在使用 SHOW TABLE STATUS 展現表當前狀態的時候使用ENUM會比使用字符串 data_length 更低


1.6 日期時間類型

  • DATETIME: 日期+時間
  • TIMESTAMP: UNIX時間,開銷更小
    • 與時區相關,好比TS=0在美國就會比在英國晚5小時


1.7 標識符 / 索引

  • 標識符有點像一個鍵,能夠用來惟一的肯定一列
  • 最好的選擇是使用整數類型做爲標識符。 與之相對的是避免使用字符串做爲標識符,由於它們會很消耗空間,大部分時候也挺慢
  • 避免使用UUID - MD5 - SHA1等隨機字符串做爲索引,這些值會隨意分佈在很大空間內,從而致使INSERT SELECT 變慢
    • 所謂的 "隨意分佈" / "很大空間" 是指咱們在索引生成之後,SHA1隨機生成的新值頗有可能會插入其中,變慢。 帶來的其餘影響則包含:  頁的中間插入 -> 頁分裂 / 磁盤隨機寫入行爲
    • 徹底隨機字符串會致使 -> 內容寫入到內存塊徹底隨機的地方上,邏輯上相鄰的行事實上相距很是遠,從而致使SELECT變慢
    • 內存訪問上有一種說法叫 "局部性原理", 內存里老是有一小片很"熱",老是被訪問,這種時候咱們選擇緩存這一小片,下次訪問緩存就頗有可能直接拿到想要的數據,總體是快的不行。   如今隨機數來了,全部地方都是同樣"熱",我緩存哪兒?我緩存哪兒對我都沒有明顯的好處


2. 設計一張表你最好這樣 :

(接下來可能會反覆補充設計表的一些東西)html

2.1 設計表的時候儘可能避免這些

  • 包含有太多列
  • 枚舉映射表太長
  • 過多使用NULL, 儘可能避免使用null
    • 你可使用一些符號代替 -1,0 均可以
    • 可是使用NULL也表明必定是壞事,若是你的表裏有太多不可能發生的數字自己也很差

2.2 範式 & 反範式

  • 使用範式
    • 好處: 
      • 若是沒有範式這種東西,表內有太多冗餘的信息,你不能說他們是錯誤信息,只是太多餘,然而在你嘗試更新一個字段的時候,哪怕你忘記更新其中一處,這些冗餘信息就會變成錯誤信息
      • 使用範式的狀況下更新屬性一般更清爽也更快
      • 範式化的表一般更小,所以能直接把整表塞進內存,查詢很快
    • 缺點: 
      • 查詢全量信息的時候,面臨聯表,噩夢
  • 使用反範式
    • 好處: 無需關聯,快
  • 總結
    • 實際上純範式化的數據庫 & 純反範式化的數據庫都只是理論上的說說,生產環境下我認爲應該仍是酌情,以及結合數據庫測試的表現來講
      • 例如你如今有user + message 表, 其中有個字段叫作 account_name_chinese,按照範式這個字段只應該在user表裏出現,可是message也會常常須要它,你能夠在數據庫的測試中的表現下,酌情使用
      • 可是像如今針對 這個字段的更新,你須要更新兩張表,這也是你須要考量的點,你會不會常常更新它? 你能接受一次更新兩張表嗎? 
      • 避免這種問題,使用trigger解決這種麻煩事 ( 什麼是 trigger )

2.3 該不應用視圖

  • 什麼是視圖:  
  • 什麼是物化視圖: 預先計算好的表,會根據一些手段更新
相關文章
相關標籤/搜索