1)分類算法
按照取值範圍和存儲方式不一樣,分爲 tinyint、smallint、mediumint、int(即 integer)和 bigint 這 5 個類型,分別爲 一、二、三、四、8 字節,若是超出類型範圍的操做會發生 "Out of range" 錯誤提示。數據庫
整數類型 | 字節 | 最小值(有符號 無符號) | 最大值(有符號 無符號) | 描述 |
---|---|---|---|---|
tinyint | 1 | -128,0 | 127,255 | tinyint[(m)] [unsigned] [zerofill] |
smallint | 2 | -32768,0 | 32767,65535 | smallint[(m)] [unsigned] [zerofill] |
mediumint | 3 | -8388608,0 | 8388607,1677215 | mediumint[(m)] [unsigned] [zerofill] |
int、integer | 4 | -2147483648, 0 | 2147483647,4294967295 | int[(m)] [unsigned] [zerofill] |
bigint | 8 | -9223372036854775808,0 | 9223372036854775807,18446744073709551615 | bigint[(m)] [unsigned] [zerofill] |
2)指定顯示寬度編程
對於整型數據,MySQL 還支持在類型名稱後加 "(m)" 的方式來指定顯示寬度,"(m)" 表示該值一共顯示 m 位數字,m 又稱爲精度,若是不顯示指定寬度則默認爲 int(11)。服務器
通常配合 zerofill 使用,即在數字位數不夠的空間用字符 "0" 填滿。網絡
在設置了寬度限制後,若是插入值大於限制寬度,這時,寬度格式已經沒有意義,仍是按照類型的實際精度(如:int 無符號的數值範圍爲0-255)進行保存,左邊不會再填充任何的 "0" 字符。函數
3)屬性性能
unsigned(無符號)優化
auto_increment操作系統
1)分類3d
分爲浮點數和定點數。
浮點數通常用於表示含有小數部分的數值,包括 float(單精度)和 double(雙精度)。
浮點數類型 | 字節 | 最小值(有符號 無符號) | 最大值(有符號 無符號) | 描述 |
---|---|---|---|---|
float | 4 | ± 1.175494351E-38 | ± 3.402823466E+38 | float[(m, d)] [unsigned] [zerofill] |
double | 8 | ± 2.2250738585072014E-308 | ± 1.7976931348623157E+308 | double[(m, d)] [unsigned] [zerofill] |
在 MySQL 中,decimal(或 numberic)用來表示定點數,定點數其實是以字符串形式存放,比浮點數更精確,適合用來表示貨幣等精度高的數據。
定點數類型 | 字節 | 最小值(有符號 無符號) 最大值(有符號 無符號) | 描述 |
---|---|---|---|
dec(m, d)、decimal(m, d)、numeric(m, d) | m + 2 | 最大取值範圍與 double 相同,給定 dec 的有效值範圍由 m 和 d 決定 | dec[(m, d)] [unsigned] [zerofill] |
2)指定顯示寬度
浮點數和定點數均可以用類型名稱後加 "(m, d)" 的方式來進行表示,"(m, d)" 表示該值一共顯示 m 位數字(整數位+小數位),其中 d 位位於小數點後面,m 和 d 又稱爲精度和標度。
當一個字段被定義爲浮點類型後,若是插入數據的精度超過該列定義的實際精度,則插入值會被四捨五入到實際定義的精度值,而後插入,四捨五入的過程不會報錯。
當一個字段被定義爲定點數類型後,若是實際插入的數值精度大於實際定義的精度,則 MySQL 會進行警告(默認的 SQLMode 下),可是數據按照實際精度四捨五入後插入;若是 SQLMode 是在 traditional(傳統模式)下,則系統會直接報錯,致使數據沒法插入。
3)使用原則
4)示例
> create table t (f float(8, 1)); Query OK, 0 rows affected (0.03 sec) > desc t; +-------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------------+------+-----+---------+-------+ | f | float(8,1) | YES | | NULL | | +-------+------------+------+-----+---------+-------+ 1 row in set (0.00 sec) > insert into t values (1.23456), (1.25456); Query OK, 1 row affected (0.05 sec) > select * from t; +------+ | f | +------+ | 1.2 | | 1.3 | +------+ 2 rows in set (0.00 sec)
> create table test (c1 float(10, 2), c2 decimal(10, 2)); Query OK, 0 rows affected (0.03 sec) > insert into test values (131072.32, 131072.32); Query OK, 1 row affected (0.02 sec) > select * from test; +-----------+-----------+ | c1 | c2 | +-----------+-----------+ | 131072.31 | 131072.32 | +-----------+-----------+ 1 row in set (0.00 sec)
從上面的例子中能夠看到,c1 列的值由 131072.32 變成了 131072.31,這是上面的數值在使用單精度浮點數表示時,產生了偏差。這是浮點數特有的問題。所以在精度要求比較高的應用中(好比貨幣)要使用定點數而不是浮點數來保存數據。
另外,浮點數的比較也是一個廣泛存在的問題,在編程中應儘可能避免浮點數的比較,若是非要使用浮點數的比較則最好使用範圍比較而不要使用 「==」 比較。
1)用途
bit(m)位類型用於存放位字段值,
bit(m) 能夠用來存放多位二進制數,M範圍從 1~64,若是不寫則默認爲 1 位。
2)查看位類型字段
對於位字段,直接使用 select 命令將不會看到結果,可使用 bin(列名)(顯示爲二進制格式)或者 hex(列名)(顯示爲十六進制格式)函數進行讀取。
# 查看位類型字段值 > select bin(id), hex(id) from t2; +---------+---------+ | bin(id) | hex(id) | +---------+---------+ | 1 | 1 | +---------+---------+ 1 rows in set (0.00 sec)
3)位類型字段插入操做
數據插入 bit 類型字段時,首先轉換爲二進制,若是位數容許,將成功插入;若是位數小於實際定義的位數,則插入失敗。
# 插入位類型字段值 > insert into t2 values(2); Query OK, 1 row affected (0.00 sec) > select bin(id), hex(id) from t2; +---------+---------+ | bin(id) | hex(id) | +---------+---------+ | 1 | 1 | | 10 | 2 | +---------+---------+ 2 rows in set (0.00 sec)
1)分類
每種日期時間類型都有一個有效值範圍,若是超出這個範圍,在默認的SQLMode下,系統會進行錯誤提示,並將以零值來進行存儲。
日期時間類型 | 字節 | 最小值 | 最大值 | 格式 | 描述 |
---|---|---|---|---|---|
date | 4 | 1000-01-01 | 9999-12-31 | YYYY-MM-DD | date |
time | 3 | -838:59:59.000000 | 838:59:59.000000 | HH:MM:SS[.fraction] | time[(fsp)] |
datetime | 8 | 1000-01-01 00:00:00.000000 | 9999-12-31 23:59:59.999999 | YYYY-MM-DD HH:MM:SS[.fraction] | datetime[(fsp)] |
timestamp | 4 | 1970-01-01 00:00:01.000000 UTC | 2038-01-19 03:14:07.999999 UTC | YYYY-MM-DD HH:MM:SS[.fraction] | timestamp[(fsp)] |
year | 1 | 1000 | 9999 | YYYY | year(date) |
timestamp:YYYY-MM-DD HH:MM:SS 格式的字符串
year:YYYY
2)零值
每種日期時間類型都有一個有效值範圍,若是超出這個範圍,在默認的 SQLMode 下,系統會進行錯誤提示,並將以零值來進行存儲。
類型 | 零值 |
---|---|
date | 0000-00-00 |
time | 00:00:00 |
datetime | 0000-00-00 00:00:00 |
timestamp | 0000-00-00 00:00:00 |
year | 0000 |
3)timestamp 和 datetime 的區別
時間取值範圍不一樣
時間屬性的不一樣
4)使用原則
根據實際須要選擇可以知足應用的最小存儲的日期類型。若是應用只須要記錄「年份」,那麼用 1 個字節來存儲的 year 類型徹底能夠知足,而不須要用 4 個字節來存儲的 date 類型。這樣不只僅能節約存儲,更可以提升表的操做效率。
若是要記錄年月日時分秒,而且記錄的年份比較久遠,那麼最好使用 datetime,而不要使用 timestamp。由於 timestamp 表示的日期範圍比 datetime 要短得多。
若是記錄的日期須要讓不一樣時區的用戶使用,那麼最好使用 timestamp,由於日期類型中只有它可以和實際時區相對應。
5)示例
> create table t6(dt datetime); Query OK, 0 rows affected (0.03 sec) > insert into t6 values('2007-9-3 12:10:10'); Query OK, 1 row affected (0.00 sec) > insert into t6 values('2007/9/3 12+10+10'); Query OK, 1 row affected (0.00 sec) > insert into t6 values('20070903121010'); Query OK, 1 row affected (0.01 sec) > insert into t6 values(20070903121010); Query OK, 1 row affected (0.00 sec) > select * from t6; +---------------------+ | dt | +---------------------+ | 2007-09-03 12:10:10 | | 2007-09-03 12:10:10 | | 2007-09-03 12:10:10 | | 2007-09-03 12:10:10 | +---------------------+ 4 rows in set (0.00 sec)
MySQL 包括了 char、varchar、binary、varbinary、blob、text、enum 和 set 等多種字符串類型。
字符串類型 | 字節 | 描述及存儲要求 |
---|---|---|
char(m) | m | 容許長度 0~255 個字節的定長字節字符串 |
varchar(m) | 容許長度 0~65535 個字節的變長字節字符串,值的長度爲 +1 字節 | |
tinytext | 容許長度 0~255 字節,值的長度爲 +2 字節 | |
text | 容許長度 0~65535 字節,值的長度爲 +2 字節 | |
mediumtext | 容許長度 0~167772150 字節,值的長度爲 +3 字節 | |
longtext | 容許長度 0~4294967295 字節,值的長度爲 +4 字節 | |
binary(m) | m | 容許長度 0~m 個字節的定長字節字符串 |
varbinary(m) | 容許長度 0~m 個字節的變長字節字符串,值的長度爲 +1 字節 | |
tinyblob | 容許長度 0~255 字節,值的長度爲 +1 字節 | |
blob | 容許長度 0~65535 字節,值的長度爲 +2 字節 | |
mediumblob | 容許長度 0~167772150 字節,值的長度爲 +3 字節 | |
longblob | 容許長度 0~4294967295 字節,值的長度爲 +4 字節 | |
enum | 取值範圍須要在建立表時指定,能夠包含 0~65535 個成員 | |
set | 取值範圍須要在建立表時指定,能夠包含 0~64 個成員 |
1)相同點
2)區別
存儲方式的不一樣
在檢索時的處理方式
最後一行的值只適用 MySQL 運行在非「嚴格模式」時,若是 MySQL 運行在嚴格模式,超過列長度的值將不會保存,而且會出現錯誤提示。
值 | chart(4) | 存儲需求 | varchar(4) | 存儲需求 |
---|---|---|---|---|
"" | ' ' | 4 個字節 | '' | 1 個字節 |
'ab' | 'ab ' | 4 個字節 | 'ab' | 3 個字節 |
'abcd' | 'abcd' | 4 個字節 | 'abcd' | 5 個字節 |
'abcdefgh' | 'abcd' | 4 個字節 | 'abcd' | 5 個字節 |
因爲 chart 是固定長度的,因此它的處理速度比 varchar 快得多,可是其缺點是浪費存儲空間,程序須要對行尾空格進行處理,因此對於那些長度變化不大而且對查詢速度有較高要求的數據能夠考慮使用 chart 類型來存儲。
另外,隨着 MySQL 版本的不斷升級,varchar 數據類型的性能也在不斷改進並提升,因此在許多的應用中,VARCHAR 類型被更多地使用。
3)不一樣的存儲引擎對 chart 和 varchar 的使用原則
MyISAM 存儲引擎:建議使用固定長度的數據列代替可變長度的數據列。
MEMORY 存儲引擎:目前都使用固定長度的數據行存儲,所以不管使用 chart 或 varchar 列都沒有關係。二者都是做爲 chart 類型處理。
InnoDB 存儲引擎:建議使用 varchar 類型。對於 InnoDB 數據表,內部的行存儲格式沒有區分固定長度和可變長度列(全部數據行都使用指向數據列值的頭指針),所以在本質上,使用固定長度的 chart 列不必定比使用可變長度 varchar 列性能要好。於是,主要的性能因素是數據行使用的存儲總量。因爲 chart 平均佔用的空間多於 varchar,所以使用 varchar 來最小化須要處理的數據行的存儲總量和磁盤 I/O 是比較好的。
4)示例
> create table vc ( v varchar(4), c char(4) ); Query OK, 0 rows affected (0.06 sec) > insert into vc values ('ab ', 'ab '); Query OK, 1 row affected (0.06 sec) > select length(v),length(c) from vc; +-----------+-----------+ | length(v) | length(c) | +-----------+-----------+ | 4 | 2 | +-----------+-----------+ 1 row in set (0.00 sec) > SELECT concat(v, '+'), concat(c, '+') from vc; +----------------+----------------+ | concat(v, '+') | concat(c, '+') | +----------------+----------------+ | ab + | ab+ | +----------------+----------------+ 1 rows in set (0.00 sec)
1)binary 和 varbinary 相似於 char 和 varchar,不一樣的是它們包含二進制字符串而不包含非二進制字符串。
2)示例
> create table t ( c binary(3) ); Query OK, 0 rows affected (0.03 sec) > insert into t set c = 'a'; Query OK, 1 row affected (0.04 sec) > select *, hex(c), c = 'a', c = 'a\0', c = 'a\0\0' from t; +------+--------+---------+-----------+-------------+ | c | hex(c) | c = 'a' | c = 'a\0' | c = 'a\0\0' | +------+--------+---------+-----------+-------------+ | a | 610000 | 0 | 0 | 1 | +------+--------+---------+-----------+-------------+ 1 row in set (0.00 sec)
1)通常在保存少許字符串的時候,咱們會選擇 char 或者 varchar;而在保存較大文本時,一般會選擇使用 text 或者 blob。兩者之間的主要差異是 blob 能用來保存二進制數據,好比照片;而 text 只能保存字符數據,好比一篇文章或者日記。
2)MySQL 中,text 是一個字符串大型對象,是一個能夠存儲大量數據的容器,它能容納不一樣大小的數據。text 類型實際是個類型系列(tinytext、text、mediumtext、longtext),除了在存儲的最大信息量上不一樣外,他們是等同的。
類型 | 字節 |
---|---|
tinytext | 255B |
text | 65K |
mediumtext | 16M |
longtext | 4G |
3)MySQL 中,blob 是一個二進制字符串大型對象,是一個能夠存儲大量數據的容器,它能容納不一樣大小的數據。blob 類型實際是個類型系列(tinyblob、blob、mediumblob、longblob),除了在存儲的最大信息量上不一樣外,他們是等同的。
類型 | 字節 |
---|---|
tinyblob | 255B |
blob | 65K |
mediumblob | 16M |
longblob | 4G |
4)blob 和 text 值會引發一些性能問題,特別是在執行了大量的刪除操做時
刪除操做會在數據表中留下很大的「空洞」,之後填入這些「空洞」的記錄在插入的性能上會有影響。爲了提升性能,建議按期使用 optimize table 功能對這類表進行碎片整理,避免由於「空洞」致使性能問題。
> create table t (id varchar(100), context text); Query OK, 0 rows affected (0.04 sec) > insert into t values (1, repeat('haha', 100)); Query OK, 1 row affected (0.01 sec) > insert into t values (2, repeat('haha', 100)); Query OK, 1 row affected (0.01 sec) > insert into t values (3, repeat('haha', 100)); Query OK, 1 row affected (0.01 sec) > insert into t select * from t; Query OK, 3 rows affected (0.07 sec) Records: 3 Duplicates: 0 Warnings: 0 ... > insert into t select * from t; Query OK, 196608 rows affected (6.19 sec) Records: 196608 Duplicates: 0 Warnings: 0
退出到操做系統下,查看錶 t 的物理文件大小,這裏數據文件顯示爲 155MB。
$ du -sh t.* 16K t.frm 155Mt.MYD 8.0Kt.MYI
從表 t 中刪除 id 爲 「1」 的數據,這些數據佔總數據量的 1/3。
> delete from t where id = 1; Query OK, 131072 rows affected (3.44 sec)
再退出到操做系統下,查看錶 t 的物理文件大小,能夠發現,表t的數據文件仍然爲155MB,並無由於數據刪除而減小。
$ du -sh t.* 16K t.frm 155Mt.MYD 8.0Kt.MYI
接下來對錶進行 optimize(優化)操做。
# optimize table 表名; > optimize table t; +--------+----------+----------+----------+ | Table | Op | Msg_type | Msg_text | +--------+----------+----------+----------+ | test.t | optimize | status | OK | +--------+----------+----------+----------+ 1 row in set (2.88 sec)
再次查看錶 t 的物理文件大小,能夠發現,表的數據文件大大縮小,「空洞」空間已經被回收。
$ du -sh t.* 16K t.frm 104Mt.MYD 8.0Kt.MYI
5)可使用合成的(Synthetic)索引來提升大文本字段(blob 或 text)的查詢性能
簡單來講,合成索引就是根據大文本字段的內容創建一個散列值,並把這個值存儲在單獨的數據列中,接下來就能夠經過檢索散列值找到數據行了。可是,要注意這種技術只能用於精確匹配的查詢(散列值對於相似「<」或「>=」等範圍搜索操做符是沒有用處的)。可使用 MD5() 函數生成散列值,也可使用 SHA1() 或 CRC32(),或者使用本身的應用程序邏輯來計算散列值。請記住數值型散列值能夠很高效率地存儲。一樣,若是散列算法生成的字符串帶有尾部空格,就不要把它們存儲在 char 或 varchar 列中,它們會受到尾部空格去除的影響。合成的散列索引對於那些 blob 或 text 數據列特別有用。用散列標識符值查找的速度比搜索 blob 列自己的速度快不少。
> create table t (id varchar(100), context blob, hash_value varchar(40)); Query OK, 0 rows affected (0.06 sec) > insert into t values (1, repeat('beijing', 2), md5(context)); Query OK, 1 row affected (0.09 sec) > insert into t values (2, repeat('beijing', 2), md5(context)); Query OK, 1 row affected (0.04 sec) > insert into t values (3, repeat('beijing 2008', 2), md5(context)); Query OK, 1 row affected (0.08 sec) > select * from t; +------+--------------------------+----------------------------------+ | id | context | hash_value | +------+--------------------------+----------------------------------+ | 1 | beijingbeijing | 09746eef633dbbccb7997dfd795cff17 | | 2 | beijingbeijing | 09746eef633dbbccb7997dfd795cff17 | | 3 | beijing 2008beijing 2008 | 1c0ddb82cca9ed63e1cacbddd3f74082 | +------+--------------------------+----------------------------------+ 3 rows in set (0.00 sec)
若是要查詢 context 值爲 「beijing 2008beijing 2008」 的記錄,則能夠經過相應的散列值來查詢。
> select * from t where hash_value = md5(repeat('beijing 2008', 2)); +------+--------------------------+----------------------------------+ | id | context | hash_value | +------+--------------------------+----------------------------------+ | 3 | beijing 2008beijing 2008 | 1c0ddb82cca9ed63e1cacbddd3f74082 | +------+--------------------------+----------------------------------+ 1 row in set (0.01 sec)
上面的例子展現了合成索引的用法,因爲這種技術只能用於精確匹配,在必定程度上減小了 I/O,從而提升了查詢效率。
若是須要對 blob 或者 clob 字段進行模糊查詢,MySQL 提供了前綴索引,也就是隻爲字段的前 n 列建立索引。
> create index idx_blob on t(context(100)); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 > desc select * from t where context like 'beijing%' \G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t partitions: NULL type: range possible_keys: idx_blob key: idx_blob key_len: 103 ref: NULL rows: 3 filtered: 100.00 Extra: Using where 1 row in set, 1 warning (0.00 sec)
能夠發現,對 context 前 100 個字符進行模糊查詢,就能夠用到前綴索引。注意,這裏的查詢條件中,「%」 不能放在最前面,不然索引將不會被使用。
6)在沒必要要的時候避免檢索大型的 blob 或 text 值
7)把 blob 或 text 列分離到單獨的表中
1)取值範圍
2)存儲空間
enum 裏面能夠包含 0~65535 個成員。根據成員的不一樣,存儲上也有所不一樣。
成員個數 | 字節 |
---|---|
1~255 | 1 |
255~65535 | 2 |
3)示例
> create table t ( gender enum('M', 'F')); Query OK, 0 rows affected (0.06 sec) > insert into t values ('M'), ('1'), ('f'), (null); Query OK, 4 rows affected (0.06 sec) Records: 4 Duplicates: 0 Warnings: 0 > select * from t; +--------+ | gender | +--------+ | M | | M | | F | | NULL | +--------+ 4 rows in set (0.00 sec)
1)取值範圍
2)存儲空間
set 裏面能夠包含 0~64 個成員。根據成員的不一樣,存儲上也有所不一樣。
成員個數 | 字節 |
---|---|
1~8 | 1 |
9~16 | 2 |
17~24 | 3 |
25~32 | 4 |
33~64 | 8 |
3)與 enum 的區別
存儲空間
選取成員個數
插入值選取
插入值超出範圍處理方式
4)示例
> create table t (col set('a', 'b', 'c', 'd')); Query OK, 0 rows affected (0.11 sec) > insert into t values ('a,b'), ('a,d,a'), ('a,b'), ('a,c'), ('a'); Query OK, 5 rows affected (0.02 sec) Records: 5 Duplicates: 0 Warnings: 0 > select * from t; +------+ | col | +------+ | a,b | | a,d | | a,b | | a,c | | a | +------+ 5 rows in set (0.00 sec)