高性能Mysql讀書筆記#第四章

Schema與數據類型優化

轉自:https://blog.csdn.net/qqqqq1993qqqqq/article/details/78110594

4.1選擇優化的數據類型

①更小的通常更好。一般應該儘可能使用能正確存儲數據的最小數據類型,更小的數據類型通常更快,因爲他們佔用更少的磁盤、內存和CPU緩存,並且處理需要的CPU週期更少。
②簡單就好。整型比字符串操作代價更低。 兩個例子:1、應該用MySQL內建的類型來記錄日期和時間 2、應該用整型來存儲IP地址(IP地址正好是32位,而且都是01值,可以轉換成整形數值)
③儘量避免null。可爲NULL的列使得索引、索引統計和值比較都更復雜。NULL列被索引的時候,每個索引記錄都需要一個額外的字節。NULL列會使用更多的存儲空間,在MySQL也需要特殊處理。(通常把可爲NULL的列改爲NOT NULL帶來的性能提升比較小,但是如果打算在這個列上建索引,那就應該避免設計爲可爲NULL。)
例外:InnoDB使用單獨的位(bit)存儲NULL,所以對於稀疏數據(很多值爲NULL)有很好的空間效率。
爲數據列選擇數據類型時,先確定合適的大類型:數字,字符串,時間等。datetime和timestamp可以存儲相同類型的數據:日期和時間、精確到秒。然而timestamp只使用datetime一半的存儲空間,並且會根據時區進行變化,具有特殊的自動更新能力。但是timestamp允許的時間範圍要小的多,有時候它的特殊能力會成爲障礙。

4.1.1 整數類型

存儲整數的類型:TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT。分別使用的存儲空間爲8,16,24,32,64位存儲空間。
整數類型有可選的UNSIGNED屬性,表示不允許負值,這大致可以使整數的上限提升一倍。
MySQL可以爲整數類型指定寬度,例如INT(11),對於大多數應用這是沒有意義的。它不會限制值的合法範圍。只是規定了MySQL的交互工具(客戶端)用來顯示字符的個數。對於存儲和計算來講INT(1)和INT(20)是一樣的。

4.1.2 實數類型

float和double類型支持使用標準的浮點運算進行近似計算。(float4字節,double8字節)
DECIMAL類型用於存儲精確的小數。在MySQL5.0+版本中DECIMAL類型支持精確計算。(每4個字節存儲9位數字,因爲還是轉化爲2進制來存儲,4字節也就是32位,最大的位數是10位)
浮點和DECIMAL類型都可以指定精確度。對於DECIMAL列,可以指定小數點前後所允許的最大位數。這會影響列的空間消耗。

4.1.3 字符串類型(感覺比較常問到)

VARCHAR

用於存儲變長字符串,使用額外的存儲空間來存儲字符串長度。需要1或者2個額外字節記錄字符串長度。如果列的最大長度小於或者等於255,則值需要1個字節表示,否則使用2個字節。
在5.0以上版本,會保留末尾的空格。
如果UPDATE時使得行比原來更長,這時需要額外的工作,MyISAM會將行拆分成不同的片段存儲,InnoDB則需要分裂頁來使行可以放進頁內。會保留存儲字符串的末尾空格。
VARCHAR適用:1、字符串列的最大長度比平均長度大很多;2、列更新很少,所以碎片不是問題;3、使用了像UTF8這樣負責的字符集,每個字符使用不同的字節數進行存儲。

CHAR

CHAR:定長(也就是分配固定的空間),會刪除字符串末尾空格
CHAR適合:1、存儲定長或長度接近的數據;2、對於經常變更的數據CHAR不容易產生碎片;3、對於非常短的列CHAR在存儲空間上更有效率
※VARCHAR(1)比CHAR(1)需要更多空間,因爲VARCHAR還需要一個字節來記錄長度的額外字節

BLOB和TEXT類型

都是爲存儲很大的數據而設計的字符串數據類型,分別採用二進制和字符方式存儲。
字符類型:TINYTEXT,SMALLTEXT,TEXT,MEDIUMTEXT,LONGTEXT。
二進制類型:TINYBLOB,SMALLBLOB,BLOB,MEDIUMBLOB,LONGBLOB。
與其他的類型不同,MySQL把每個BLOB和TEXT值當作一個獨立的對象處理。存儲引擎在存儲時,通常會做特殊處理。當BLOB和TEXT值太大時,InnoDB會使用專門的“外部”存儲區域進行存儲,此時每個值在行內需要1~4個字節存儲一個指針,然後在外部存儲區域存儲實際的值。
BLOB和TEXT之間的不同是BLOB類型存儲的是二進制數據,沒有排序規則或字符集,而TEXT類型有字符集和排序規則。
MySQL對BLOB和TEXT進行排序與其他類型時不同的:它只對每個列的最前max_sort_length字節而不是整個字符串做排序。

ENUM

使用枚舉(ENUM)代替字符串。對於枚舉類型在表.frm文件中會保存“數字-字符串”的映射關係,行內存儲的是值在列表中的位置(從1開始),排序的時候是按照列表中聲明的順序,使用枚舉類型可以減少表的大小。

枚舉類型最大的缺點在於增加或刪除字符串的時候必須使用ALTER TABLE, 除非只是在末尾添加字符串,不然需要重建整個表。枚舉列在進行關聯查詢的時候,如果和CHAR OR VARCHAR關聯,性能會比較差甚至不如直接用字符串,但是枚舉和枚舉關聯,性能不錯。在某些情況下,即使可能出現ENUM和VARCHAR關聯的情況這也是值得的,因爲可以減少I/O。

4.1.4 時間類型

DATETIME

這個類型能保存的值:從1001年到9999年,精度爲妙。它把時間和日期封裝到格式YYYYMMDDHHMMSS的整數中,與時區無關,保存在8字節中。

TIMESTAMP

它保存了從1970年1月1日午夜一來的秒數,它與unix時間戳是相同的。
但它只用4個字節,所以表示的範圍小一點。只能表示1970到2038年。
MySQL中FROM_UNIXTIME()函數把unix時間戳轉換爲日期。
UNIX_TIMESTAMP()函數將日期轉換爲Unix的時間戳。
依賴於時區。

位數據類型

BIT: BIT列最長64位。BIT(64)需要8個字節來存儲。MySQL把BIT當作字符串類型而非數字類型,所以查詢BIT列的時候得到的是所存儲的二進制值作爲ASCII碼對應的字符串,如果用BIT列和其他數字比較或計算,那麼查詢到的是數字。這個相當費解,建議謹慎使用。
SET: 在MySQL內部以一系列打包的位的集合來表示,可以有效的利用存儲空間,並且有FIND_IN_FIELD(), FIELD()這樣的函數可以在查詢時使用。主要缺點是改變列的定義代價比較大。
一種替代SET的方案就是用一個整數包裝一系列的位。類似於Linux文件系統的權限管理那樣。

特殊類型
IP地址: 通過INET_ATON()和INET_NTOA()函數在IP地址和無符號整數之間做轉換。

範式和反範式

範式優點:
範式化的更新操作比反範式化要快
當數據較好地範式化的時候,就只有很少或者沒有重複數據,所以只需要修改更少的數據
範式化的表通常更小,可以更好的放在內存裏,所以執行操作會更快
很少有多餘的數據意味着檢索列表數據時更少需要DISTINCT和GROUP BY這樣的語句。
範式缺點:
通常需要關聯
代價昂貴,也可能是一些索引策略無效
反範式優點:
不需要關聯查詢
反範式缺點:
數據冗餘
更新和插入操作需要做更多
緩存表和彙總表
這個感覺就看具體需求了,對於緩存或者彙總的數據實時性要求有多高,然後採取不同的策略。

影子表:是指在一張真是表“背後”創建同樣的表,然後建好之後通過原子的重命名操作切換。
mysql> DROP TABLE IF EXISTS my_summary_new, my_summary_old;
mysql> CREATE TABLE my_summary_new LIKE my_summary;
mysql> RENAME TABLE my_summary TO my_summary_old, my_summary_new TO my_summary;

物化視圖

MySQL並不支持物化視圖,可是使用開源工具Flexviews來實現。

加快ALTER TABLE的速度

ALTER TABLE一般都很慢,操作將導致MySQL服務中斷。一般來說是會新建個表,然後從舊錶讀取數據插入到新表中,這樣效率很慢。
但並不是所有的都這麼慢,比如修改一個列的默認值有兩種辦法:
①:mysql> ALTER TABLE film MODIFY COLUMN rental_duration TINYINT(3) NOT NULL DEFAULT 5;
②:mysql> ALTER TABLE file ALTER COLUMN rental_duration TINYINT(3) NOT NULL DEFAULT 5
第一種方法是通過上面所說的讀取插入的方式。 第二種方法會直接修改.frm文件不涉及數據,所以很快。

下面有一些修改表的操作是不需要重建表的:
移除一個列的AUTO_INCREMENT屬性
增加、移除或更改ENUM和SET常量。如果移除的是已經有行用到的,查詢將返回一個空字符串。
基本思路是爲想要的表結構創建一個新的.frm文件,然後替代已有的那個:
創建相同結構的表,並進行修改
執行FLUSH TABLES WITH READ LOCK。這將關閉所有正在表,並且禁止任何表被打開。
交換.frm文件
執行UNLOCK TABLES釋放鎖。
爲InnoDB表增加索引的時候也可以嘗試一種比較駭客的方法(官方並不支持,注意備份數據):

用需要的表結構創建一張表,但是不包括索引:
載入數據到表中以構建.MYD文件
按照需要的接口創建另外一張空表,這次包含索引。這會創建需要的.frm和.MYI文件。
獲取讀鎖並刷新表。
重命名第二張表的.frm和.MYI文件,讓MySQL以爲是第一張表的文件。
釋放讀鎖。
使用REPAIR TABLE來重建表的索引。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章