1. 優化數據類型
1.0 幾個簡單的原則
1.更小的通常更好:儘量選擇可以正確存儲數據的最小數據類型。如int-->tinyint,
2.簡單就好:使用更少耗費cpu的類型。如整形比字符串操作代價更低;使用mysql內建的時間/日期類型而不是字符串存儲時間;使用整數存儲ip地址等等
3. 儘量避免 null 。如果查詢帶有null的列,對mysql來說更難優化。null使索引、索引統計、值比較都更加複雜。
1.1 整數類型
1儘量確定整數的範圍並使用對應的整形,tinyint/int/smallint/bigint等。
2 合理利用unsigned :如果只有正整數,不妨在之後加上unsigned 修飾
3. 雖然int可以指定長度。如int(11),但這只是規定了顯示的字符個數,實際上存儲和計算的仍是int類型的數值。比如int(1)和int(20)只是顯示的值不同。
1.2 實數類型
1 使用decimal 可以用來存儲比bigint還大的數據。
2 使用bigint 來避免浮點型計算不精確以及decimal 精確計算代價高的問題。例如,存儲財務數據,單位爲萬元時,存在小數的情況。可以直接使用單位爲元或者/角/分的更小單位的bigint數值來替代。
1.3 字符串類型
先講char和varchar
varchar 用來存儲不定長的字符串,它比定長類型更省空間(除非使用row_format=fixed創建,每一行都會使用定長字符串)。
varchar需要使用額外1或2字節存儲字符長度。如果長度<=255,則使用1字節,否則使用2字節。
varchar由於更新變長時,myisam和innodb的處理方式不同。myisam會將行拆分成不同的片段存儲,innodb則進行分裂頁來使行可以放入頁內。innodb還會將過長的varchar轉換爲blob
適合varchar 的場景:
字符串列最大長度比平均長度大很多;
字符串列更新少;
使用了utf-8等複雜的字符集。
blob和text
blob 存儲二進制,text存儲文本。
對blob和text進行排序時,只會對每列的前max_sort_length 字節進行排序。如果非要對其進行排序可以更改此變量值,或者使用 ` order by sustring(coulmn,length)`。
1.4 日期和時間類型
datetime和timestamp都可以存儲相同類型的數據:時間和日期(精確到秒)。但是timestamp只花費前者一半的存儲空間。但是其允許的時間範圍稍小。
1.5 BIT 類型
在mysql5.0 之前,bit相當於tinyint。在之後,bit在不同的存儲引擎上表現不同,在myisam上 bit就是使用對應長度字節存儲,而innodb和memorydb則使用足夠存儲bit位數的最小整數代替,無法減小開銷。
對於bit ,更奇怪的是它在不同上下文場景下的表現。在上文是字符串的場景下,查詢出的bit字段的 結果是一個 bit字段對應二進制值的ascii碼字符。但是如果在數字上下文,查詢出來的結果就會是數字。
例如
create table bittest (a bit(8));
insert into bittest a values(b'00111001');
select a ,a+0 from bittest;
最終會得出以下結果(字符9的ascii碼爲57)
|---------------|
| a |a +0 |
-----------------
| 9 | 57 |
應儘量避免使用BIT。
1.6 主鍵 id 字段的 選用
1. 數字 始終是最適合id的類型,因爲他們足夠快
2. 字符串
避免字符串作爲id標識符,因爲它們比數字開銷更大,且更慢。尤其是在myisam中,myisam默認會對字符串使用壓縮索引,這會導致查詢慢很多。
對於完全隨機的字符串,如uuid等,會任意分佈在很大的空間內,使得insert以及一些select 變得更慢。
(優點在寫的特別大的表可以消除熱點)
如果存儲uuid ,應該去除中間的 ‘-’ 字符。
一方面是由於主鍵字段過長,二是由於頁分裂和碎片導致的。在innoDB中,會根據主鍵去做聚簇索引,把索引和對應的數據行存儲的在葉子頁上,使用uuid寫入是無序的,InnoDB爲了數據的寫入,只能不斷頻繁的進行頁分裂操作,以便爲新的行分配空間。 由於頻繁的頁分裂,會導致頁變得稀疏被不規則的填充,所以最終導致產生了大量的數據碎片。
uuid適合數據量龐大、分佈式等特點的數據庫設計。
mysql 限制每個關聯操作最多61個表