天天看點

MySQL資料庫的資料類型和索引 2. MySQL資料庫索引

1. MySQL的資料類型

1.1 數字類型和時間類型

數字類型算是最簡單的了,主要差異在于各個類型的取值範圍大小限制,和對存儲空間位元組數的需求。數字類型當然是在滿足情況的條件下越短越好,一方面MySQL每行有65535位元組長度的限制,同時更寬的資料類型意味着對CPU、記憶體、磁盤I/O帶來壓力。

MySQL支援的定點數字類型和占用位元組數分别是

類型 長度
TINYINT 1
SMALLINT 2
MEDIUMINT 3
INTEGER 4
BIGINT 5

在資料庫設計的時候,常常看到這些整形有個字首長度,其實這對其類型本身的存儲長度和精度沒有影響,隻會關系到某些互動式工具顯示出來的字元個數。

MySQL支援的浮點(實數)類型和占用位元組數為

類型 長度
FLOAT 4
FLOAT(p) [0,24] 4
FLOAT(p) [25,53] 8
DOUBLE,REAL 8

計算機的浮點運算都是不精确的,如果要實作精确浮點運算,就需要使用DECIMAL類型。

時間類型

常被使用的是DATE、DATETIME和TIMESTAMP類型,其表示的範圍為:

DATE:’1000-01-01’ to ‘9999-12-31’

DATETIME:’1000-01-01 00:00:00’ to ‘9999-12-31 23:59:59’

TIMESTAMP:’1970-01-01 00:00:01’ UTC to ‘2038-01-19 03:14:07’ UTC

TIMESTAMP存儲的範圍比DATETIME要小,但是空間使用率也最高。MySQL支援的時間精度最高為1s,如果更精确的存儲,就必須自己定義存儲格式了。

1.2 字元串類型

MySQL中的字元串類型比較多也比較的複雜,各個字元串類型的差别不僅僅在存儲時候的空間占用,對存取時候字段某位的strip和padding還有差異。

對于類型CHAR/VARCHAR/TEXT是跟本地字元集相關的,這會影響到實際占用空間的位元組數、字元比較等。

CHAR(M)/VARCHAR(M)

長度限制參數M表示的是本地字元集的字元個數而不是bytes數目,比如對于UTF8編碼,每個本地字元其實際占用的byte長度可能是或4倍的本地字元長度。比如VARCHAR(255),如果每個本地字元占用兩個位元組,那麼其需要的存儲空間最大為255x2+2。

CHAR的M被限制在最大255,而VARCHAR的M理論上受限于Row Size的長度(65,535bytes),且實際存儲時候會附加1~2位元組的字首表示資料實際長度。如果strict SQL模式沒有被打開,那麼當插入資料超過聲明長度限制的時候,資料将會被截斷并産生警告資訊,在strict SQL模式下将會出錯。

CHAR類型在存儲的時候,會在右端padding SPACE到指定的M長度,當取該字段的時候,所有末尾的SPACE都将會被strip掉然後傳回;VARCHAR不會對進行SPACE進行padding以及strip操作,存儲什麼樣的資料就會傳回什麼樣的資料。

對于CHAR/VARCHAR/TEXT類型,在進行字元串比較的時候,(SQL語句參數中的字元串)結尾的空格都是不參與比較的,但是對于LIKE語句,檢索的時候結尾的空格是考慮在内的。

BINARY(M)/VARBINARY(M)

BINARY/VARBINARY在操作的時候,參考的是byte streaming而不是charaset streaming,是以其長度限制參數M表示的是byte數目,在比較的時候也是直接的數字大小比較(而非本地字元集方式比較)。

BINARY在插入的時候,會使用0x00(而非SPACE)padding到長度M,取值的時候不會進行strip尾部空字元的操作(意味着取出來的長度一定是M);VARBINARY則是保證原樣存取的。

BLOB/TEXT

分别有TINY/MEDIUM/LONG類型的衍生長度,BLOB是bytes streaming類型的,而TEXT是基于character streaming本地字元集類型的,兩者在存取的時候都不會進行padding和strip操作。

BLOB/TEXT的關系和之前的VARBINARY/VARCHAR是比較相似的,除了:BLOB/TEXT不能夠有DEFAULT值;BLOB/TEXT在建立索引的時候必須要有prefix length,而前者是可選的;給予TEXT索引需要有字首長度,而且建立索引會自動padding SPACE到索引長度,是以如果插入的字元前面一樣,隻是尾部空字元長度不同,也是會産生相同的索引值。

字元串各個類型占用的空間長度

類型 長度
CHAR(M) Mxw bytes
BINARY(M) M bytes
VARCHAR(M), VARBINARY(M) L+1/L+2 bytes
TINYBLOB, TINYTEXT L+1 bytes
LOB, TEXT L+2 bytes
MEDIUMBLOB, MEDIUMTEXT L+3 bytes
LONGBLOB, LONGTEXT L+4 bytes

根據官方手冊,CHAR/BINARY及其衍生的類型的資料是存儲在表的行内部(inline)的,而對于BLOB和TEXT類型,每一個字段隻占用該行9-12(1~4+8)個位元組(用于資料的位址和長度),實際的資料是存儲在Row Buffer之外位置的。是以對于經常通路的字元串類型,而長度又不是特别的大,還是建議用VARCHAR(M)的資料類型,性能會比TEXT快不少。

2. MySQL資料庫索引

資料庫索引可以用來快速找到需要的行,否則的話MySQL就需要一行一行的周遊,查詢效率自然相當的低。

MySQL支援的索引包括PRIMARY KEY、UNIQUE、INDEX、FULLTEXT類型的索引。前面說過,FULLTEXT類型的全文索引在中文下基本是報廢的,在此就不予讨論了。

特别注意的是,對于索引列隻能使用單純的列名,而不能是表達式或者函數的一部分,比如age+2、TO_DAYS(date_col),引擎在檢索的時候才能使用索引。

2.1 索引的類型

PRIMARY KEY

在InnoDB内部,表資料是優化主鍵快速查詢而排列分布的,其查找速度是最快的(相當于聚簇索引:該索引中鍵值的邏輯順序決定了表中相應行的實體順序)。即使表中沒有适合做主鍵的列,也推薦采用一個自動增長的整數主鍵(代理鍵),那麼這個表在增加資料的時候是順序存放的,而且後續在别的表參考該外鍵查詢的時候也會得到優化。本身在設計表的時候,也建議常用的資料額不常用的資料分表存放以增加效率。

INDEX 

普通索引,對資料沒有限制要求,多行記錄可以包含相同值。無論對于字元串索引,還是多列組合索引,都以及在查詢語句中,都有個最左字首的原則:

(1) 對于字元串類型,可以指定索引字首長度(且對于BLOB/TEXT字首長度參數是必須的),在InnoDB表中其字首長度最長是767 bytes,且參數M是用bytes計量的。是以太長的字元串,建立BTree索引浪費比較大,這時候用手動模拟HASH索引是個方法,不過這種方式對字元串無法靈活的使用字首方式查詢(例如LIKE這類的操作)。

(2) 在建立多列索引的時候,必須按照從左到右的順序使用全部或部分的索引列,才能充分的使用組合索引,比如:(col1, col2, col3)使用(col1)、(col1, col2)、(col1, col2, col3)有效。在查詢語句中會一直向右比對直到遇到範圍查詢(>,<,BETWEEN,LIKE)就停止比對,其後的索引列将不會使用索引來優化查找了。

(3) 索引不是建立的越多、越長越好,因為索引除了占用空間之外,對後續資料庫的增加、删除、修改都有額外的操作來更新索引,是以對索引列和字元串字首長度,都參考選擇性(Selectivity)這個名額來确定:選擇性定義為不重複的索引值和資料總記錄條數的比值,其選擇性越高,那麼索引的查詢效率也越高,對于性别這種參數,建立索引根本沒有意義。

  • UNIQUE
  • UNIQUE索引要求索引是唯一的。對于單列索引,要求該列所有資料都不相同,但允許有NULL值;對于多列的組合索引,要求這些列的組合是唯一的。UNIQUE索引其本身既可以作為索引,實際中也可以用以産生資料限制,防止增加或者修改後産生相同資料。

2.2 B+Tree和HASH

  • B+Tree
  • 該類型的索引中,列記錄都是按照順序排列的,可以優化用于比較或者範圍查找操作(=, >, >=, <, <=, BETWEEN, IN),以及用于(GROUP BY, ORDER BY)操作,而且對于字元串類型的索引,最左字首字元串也可以充分利用索引,比如LIKE ‘Patrick%’會解釋成 ‘Patrick’ <= key_col < ‘Patricl’。
  • HASH
  • 速度更快,不過隻能用于 =、<=>、IN操作符;優化器不能用于ORDER BY操作;任何查找操作必須是索引的完整列。

作者:Nicol TAO

原連結:http://taozj.org/2016/05/MySQL資料庫的資料類型和索引/

繼續閱讀