MySQL優化(1):字段的設計


Web項目中,當Java或者Go等語言速度提升到瓶頸的時候,我們需要關心MySQL的優化

可以優化的方面有很多:設計表、負載均衡、讀寫分離、SQL語句優化等

 

(1)IP地址設計

例如我們需要存儲IP地址:192.168.1.1

第一反應是選用VARCHAR(15);但是更好的方式是INT UNSIGNED(占用四個字節)

因為:IP地址可以很容易地轉換為無符號整數

仔細觀察IP地址,四部分都是0-255的數字,1個字節(8位)恰好可以表示0-255的整數

而MySQL有函數:inet_aton():地址轉成數字,inet_ntoa():數字轉成地址

示例:

SELECT INET_ATON('192.168.0.1')

結果:3232235521

SELECT INET_NTOA("3232235521")

結果:192.168.0.1

INT UNSIGNED占用字節少於VARCHAR(15),並且整數查詢效率更高(代價是需要使用轉換函數)

總結:在設計字段的時候,盡量使用整數來表示字符串

 

(2)關聯表設計

整型的優勢:固定存儲空間,通常是少量空間

例如:MySQL內部的枚舉和集合類型:

enum(男,女,未知)

insert into user(gender) values(男)

這句話在MySQL中實際存儲的是1,這就是最典型的把字符串存成整數

注意:實際中,很少使用mysql的enum和set,因為維護成果過高

比如性別需要把未知改為人妖,需要執行alter table modify column操作,需要獨占整張表,檢查記錄性別值的合法性

如果一定要使用這種方式:關聯表,字段id,title,存儲1,男,2,女。這種方式使用較為廣泛

但是,比如家庭地址這樣的字符串,是無法改成整型的,不能強行操作

 

(3)金額存儲

金額的存儲對數據的精度要求較高,按理來說要使用DECIMAL()

例如DECIMAL(10,2):有2位小數的定點數

實際中有另一種操作:INT或BIGINT,這時候為了精度不丟失,采用”分“為單位(12.51元記錄為1251)

計算機中小數是無法做到不損失精度的,但是金額較特殊,固定了兩位小數,所以可以采用這種方式

而且編程中,整數的計算相對於小數較為方便

DECIMAL也有擅長的地方,比如存儲大數:123456789123456789

這時候不可以使用INT,只能使用BIGINT或者DECIMAL

 

注意:這里為什么我們不選擇浮點數DOUBLE和FLOAT呢?因為浮點數會導致精度丟失

原因:浮點數占用固定的存儲空間,無論存儲多大的數,空間是一定的;但是定點數空間會隨着數字變大而增加

由此引出了定長類型和變長類型:

定長類型:存儲空間固定(INT、FLOAT、DOUBLE、CHAR、DATE、TIME、DATETIME、YEAR、TIMESTAMP)

變長類型:存儲空間可變(VARCHAR、DECIMAL、TEXT)

注意:只有定長類型才會有損失精度的問題,定長類型效率較高

結論:在乎存儲空間采用定長類型,在乎存儲精度采用變長類型

 

(4)TEXT和VARCHAR的選擇

TEXT:通常感覺存儲容量較大,其實最大容量和VARCHAR的最大容量幾乎一樣

但是,TEXT是獨立存儲的,不占用字段的總空間,但是VARCHAR占用字段總空間,通常總空間是65535字節

結論:更大的數據還是采用TEXT更好

更大的數據類型有LONGTEXT,可以用於選擇

 

(5)字段設計的原則

1.盡可能選擇小的數據類型,這條無需多說

2.盡可能使用NOT NULL,因為數據庫不需要判斷是否為NULL,NULL在MYSQL中的存儲和運算更麻煩:

NULL參與常規運算的結果都是NULL,當判斷是否為空的時候,必須采用IS NULL和IS NOT NULL

MYSQL中每條記錄會使用到額外的存儲空間,用於表示每個字段是否為NULL

通常使用一個特殊的數據來占位,比如我要表達NULL通常設置為空字符串或者0

這種情況又會出現問題,比如成績字段,0代表沒有的話無法區分0分的學生,所以可以采用-1,消除歧義

3.字段注釋要完整:gender int comment '性別'

4.單張表的字段數量不宜過多,通常最多二三十個;數量過多通常會出現某個業務邏輯只是用其中一部分,浪費性能

5.預留字段,比如field1 int field2 varcahr等等;后期項目如果需要更改表結構,這樣做會方便很多

 

(6)關聯表的設計

一對一:一條記錄的字段較多,分布到多個表中存儲

例如學生表,基礎信息:姓名、身高、班級,還有一些不常用的數據:籍貫、家庭成員等信息

這時候應該設計基礎信息一張表,不常用數據一張表,使用相同的主鍵來表示

 

一對多:在多的一端使用關聯字段,關聯一端的主鍵

例如文章和分類表,分類是一端,文章是多端;那么在文章表中需要有一個分類ID的字段做關聯

 

多對多:使用中間表來實現

例如文章和標簽,多對多,那么就需要一張表,字段至少有ID、文章ID、標簽ID,每一條記錄代表一個關聯

 

(7)范式

第一范式:字段的原子性,不可再分割

關系型數據庫默認滿足第一范式,MYSQL滿足

但也可以強行做:比如一個時間字段,同時寫入開始時間和結束時間,這就不合理

一個容易出現的問題:(6)中的例子,文檔和標簽的設計中:如果我為了省事,不引入第三張表,而是在文章表中用一個字段標簽IDs字段(例如存入1,2,3)

這種情況很常見,是不合理的做法,在更新的時候會出現很多問題,需要把逗號拆開處理,而且無法建索引

除非是類似日志系統,存入后不再維護,那么可以使用這種方式

 

第二范式:滿足第一范式后,消除對主鍵的部分依賴(A字段可以確定B字段,那么B字段依賴A字段)

主鍵:可以唯一標識記錄的字段或者字段集合

部分依賴:如果某個字段依賴復合主鍵的一部分字段,稱之為對主鍵的部分依賴

 

例如一個課程信息表,字段有:老師,性別,班級,教室,時間,但是不存在ID

這時候需要我們選一個主鍵,這里面每一個字段都不能作為主鍵

老師和班級同時可以作為一個主鍵(復合主鍵)

但是性別對主鍵是部分依賴,如何消除呢?

 

部分依賴的產生必須是復合主鍵,那么增加一個ID即可消除對主鍵的部分依賴

 

第三范式:第二范式的基礎上,消除對主鍵的傳遞依賴

傳遞依賴:C依賴於B,B依賴於主鍵,那么C對主鍵存在傳遞依賴關系

上門的例子:性別依賴於老師,老師依賴於ID,那么存在傳遞依賴關系

消除方式:將獨立數據單獨建表,使用關聯字段進行存儲

例子中,建立一個單獨的表,記錄老師和性別的關系

 

總結:獨立數據獨立建表;表中存在與業務邏輯無關的ID主鍵;表之間的關系由關聯字段(或關聯表)進行表示

通俗來講:我們建表中,基本都是滿足三大范式的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM