第四章 Schema與數(shù)據(jù)類型優(yōu)化

一、選擇優(yōu)化的數(shù)據(jù)類型

  1. 一般情況下,應該盡量使用可以正確存儲數(shù)據(jù)的最小數(shù)據(jù)類型。但是要確保沒有低估需要存儲的值的范圍,因為在schema中的多個地方增加數(shù)據(jù)類型的范圍是一個非常耗時的操作。
  2. 在使用字符類型時需要考慮其校對規(guī)則(排序規(guī)則)。
  3. 盡量避免使用NULL,因為可以為NULL的列會使用更多的存儲空間當它被索引時,每個索引的記錄需要一個額外的字節(jié)用于記錄它是否為NULL。

二、整數(shù)類型

MySQL可以為整數(shù)類型指定寬度,對于大多數(shù)應用這是沒有意義的,它不會限制值的合法范圍,只是規(guī)定了MySQL的一些交互工具(如命令行客戶端)用來顯示字符的個數(shù)

三、實數(shù)類型

實數(shù)是帶小數(shù)部分的數(shù)字,MySQL即支持精確類型,也支持不精確類型。FLOAT和DOUBLE類型支持使用標準的浮點運算進行近似計算;DECIMAL類型用于存儲精確的小數(shù)。

因為需要額外的控件和計算開銷,所以應該盡量只在對小數(shù)進行精確計算時才使用DECIMAL--如存儲財務數(shù)據(jù)。但在數(shù)據(jù)量比較大的時候,可以考慮使用BIGINT代替DECIMAL,將需要存儲的貨幣單位根據(jù)小數(shù)位數(shù)乘以相應的倍數(shù)即可。

四、字符串類型

  1. 字符串定義的長度不是字節(jié)數(shù),如varchar(10),定義的是字符長度為10的varchar類型。

  2. varchar類型用于存儲可變長字符串,它需要使用1或2個額外的字節(jié)記錄字符串的長度。

  3. 由于varchar是變長的,在update時,可能新的值比原先的長,從而使得新的行比原來的行長,此時導致需要做一些額外的操作,不同的存儲引擎處理方式不一樣,InnoDB會通過分裂頁的方式來使行可以放進頁內(nèi)(產(chǎn)生碎片)。

  4. 下面這些情況適合使用varchar:
    a. 字符串列的最大長度比平均長度大很多;
    b. 列的更新很少,減少碎片的產(chǎn)生。
    c. 使用了像UTF-8這樣復雜的字符集,每個字符都使用了不同的字節(jié)數(shù)進行存儲。

  5. char類型是定長的,Mysql總是根據(jù)定義的字符串長度分配足夠的空間。char適合存儲很短的字符串,或者所有值都接近同一個長度。對于經(jīng)常變更的數(shù)據(jù),char也比varchar更好,因為定長不易產(chǎn)生碎片

  6. 慷慨是不明智的,使用varchar(5)和varchar(200)存儲‘hello’的空間開銷是一樣的,但是在實際使用時,我們應該按照實際的存儲長度來定義,因為Mysql在運行時,更長的列會消耗更多的存儲內(nèi)存。Mysql通常會分配固定大小的內(nèi)存塊來保存內(nèi)部值,尤其是使用內(nèi)存臨時表進行排序操作時使用更長的列會顯得特別糟糕。

  7. BLOB和TEXT類型
    a. Mysql把每個BLOB和TEXT值當作一個獨立的對象處理,存儲引擎在存儲是通常會做特殊處理
    b. BLOB和TEXT值太大時,InnoDB會使用專門的“外部”存儲區(qū)域來進行存儲,此時每個值在行內(nèi)需要1~4個字節(jié)存儲一個指針,然后在外部存儲區(qū)域存儲實際的值
    c. BLOB類型存儲的是二進制數(shù)據(jù),沒有排序規(guī)則或字符集
    d. Mysql只對每個TEXT列的最前max_sort_length字節(jié)而不是整個字符串做排序
    e. Mysql不能將BLOB和TEXT列全部長度的字符串進行索引。

四、其他類型

  1. 使用枚舉類型時要注意,枚舉字段是按照內(nèi)部存儲的證書而不是定義的字符串進行排序的。枚舉最不好的地方是,字符串列表是固定的,添加或刪除字符串必須使用ALTER TABLE,而在舊版本的MySQL中,該操作是會鎖表的。

  2. 日期和時間類型
    a. DATETIME精度為秒,使用8個字節(jié)的存儲。
    b. TIMESTAMP使用4個字節(jié)存儲。默認情況下,如果插入數(shù)據(jù)時,沒有指定TIMESTAMP列的值,MySQL則設置這個列的值為當前時間。
    d. TIMESTAMP列默認為NOT NULL.

  3. 在選擇標識列(identifier,主鍵)的類型時,不僅僅需要考慮存儲類型,還需要考慮mysql對這種類型怎么執(zhí)行計算和比較。通常整數(shù)是標識列最好的選擇,因為計算快,而且可以使用AUTO_INCREMENT;因該避免使用字符串類型作為標識列,因為它們很消耗空間,并且通常比數(shù)字類型慢,MyISAM默認對字符串使用壓縮索引,這會導致查詢慢很多。

  4. 太多的列 Mysql在執(zhí)行查詢操作時需要在執(zhí)行層和存儲引擎層之間通過行緩沖格式拷貝數(shù)據(jù),然后在執(zhí)行層將緩沖的內(nèi)容解碼成各個列,轉(zhuǎn)換的代價依賴于列的數(shù)量

五、范式和反范式

  1. 在范式化的數(shù)據(jù)庫中,每個事實數(shù)據(jù)會出現(xiàn)并且只出現(xiàn)一次。相反,在反范式化的數(shù)據(jù)庫中,信息是冗余的,可能會存儲在多個地方。

六、加快ALTER TABLE操作的速度

  1. Mysql執(zhí)行修改表結(jié)構(gòu)的操作方法是用新的結(jié)構(gòu)創(chuàng)建一個空表,從舊表中查處所有數(shù)據(jù)插入新表,然后刪除舊表。

  2. 一般而言,大部分ALTER TABLE操作將導致Mysql服務中斷。常使用兩個技巧來完成相關的修改操作:一種是先在一臺不提供服務的機器上執(zhí)行ALTER TABLE操作,然后和提供服務的主庫進行切換; 另一種是通過“影子拷貝”,影子拷貝的技巧是用要求的表結(jié)構(gòu)創(chuàng)建一張和源表無關的新表(影子表),然后通過重命名和刪表操作交換兩張表。

  3. 不是所有的ALTER TABLE操作都會引起表重建。例如,有兩種方法可以改變或刪除一個列的默認值。
    eg: ALTER TABLE tb MODIFY COLUMN tb.col_1 TINYINT(3) NOT NULL DEFAULT 5;
    列的默認值實際上存在表的.frm文件中,所以理論上可以直接修改這個文件而不需要改動表本身,但是Mysql并沒有采用這種優(yōu)化,所有的MODIFY COLUMN 操作都將導致表重建。
    但是通過ALTER COLUMN來操作的話則會直接修改.frm文件而不涉及表數(shù)據(jù),所以這個操作非??臁H缦滤荆?br> eg: ALTER TABLE tb ALTER COLUMN tb.col_1 TINYINT(3) NOT NULL DEFAULT 5;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容