原文地址http://www.cnblogs.com/xrq730/p/5260294.html,轉載請註明出處,謝謝!html
前言mysql
好久沒寫文章,也有博友在個人有些文章中留言,但願我能夠寫一些文章,公司項目一直很忙,可是天天也儘可能騰出一些時間寫一些東西,主要針對工做中一些經常使用的知識點系統性的梳理(可能咱們在工做中只是純粹的使用而已,不會去進行總結、概括)。sql
本文寫的內容是MySQL數據類型,以前寫MySQL系列文章的時候一直忽略的一個知識點,如今想來,咱們學習一門語言,無非從兩個方面入手:數據庫
但願經過一篇文章的梳理,能夠把MySQL數據結構這塊都概括清楚。數據結構
整型函數
先從最基本的數據類型整型提及,首先用一張表格概括一下:工具
數據類型 | 字節數 | 帶符號最小值 | 帶符號最大值 | 不帶符號最小值 | 不帶符號最大值 |
TINYINT | 1 | -128 | 127 | 0 | 255 |
SMALLINT | 2 | -32768 | 32767 | 0 | 65535 |
MEDIUMINT | 3 | -8388608 | 8388607 | 0 | 16777215 |
INT | 4 | -2147483648 | 2147483647 | 0 | 4294967295 |
BIGINT | 8 | -9223372036854775808 | 9223372036854775807 | 0 | 18446744073709551616 |
即便是帶符號的BIGINT,其實也已是一個天文數字了,什麼概念,9223372036854775807咱們隨便舉下例子:學習
因此從實際開發的角度,咱們必定要爲合適的列選取合適的數據類型,即到底用不用獲得這種數據類型?舉個例子:大數據
要知道,MySQL本質上是一個存儲,以Java爲例,可使用byte類型的地方使用了long類型問題不大,由於絕大多數的對象在程序中都是短命對象,方法執行完畢這塊內存區域就被釋放了,7個字節實際上不存在浪不浪費一說。可是MySQL做爲一個存儲,8字節的BIGINT放那兒就放那兒了,佔據的空間是實實在在的。編碼
最後舉個例子:
1 drop table if exists test_tinyint; 2 create table test_tinyint ( 3 num tinyint 4 ) engine=innodb charset=utf8; 5 6 insert into test_tinyint values(-100); 7 insert into test_tinyint values(255);
執行第7行的代碼時候報錯"Out of range value for column 'num' at row 1",即很清楚的咱們能夠看到插入的數字範圍越界了,這也一樣反映出MySQL中整型默認是帶符號的。
把第3行的num字段定義改成"num tinyint unsigned"第7的插入就不會報錯了,可是第6行的插入-100又報錯了,由於無符號整型是沒法表示負數的。
整型(N)形式
在開發中,咱們會碰到有些定義整型的寫法是int(11),這種寫法從我我的開發的角度看我認爲是沒有多大用,不過做爲一個知識點作一下講解吧。
int(N)咱們只須要記住兩點:
下面舉個例子,寫一段SQL:
drop table if exists test_int_width; create table test_int_width ( a int(5), b int(5) unsigned, c int(5) unsigned zerofill, d int(8) unsigned zerofill ) engine=innodb charset=utf8; insert into test_int_width values(1, 1, 1, 1111111111); select * from test_int_width;
從上面的兩點,咱們應該預期結果應該是1,1,00001,1111111111
咱們看一下結果:
不符合預期是吧,由於這個問題我也有過困擾,後來查了一下貌似是Navicat工具自己的問題,咱們使用控制檯就不會有這個問題了:
不過實際工做場景中反正我是沒有碰到過指定zerofill的,也不知道具體應用場景,若是有使用這種寫法的朋友能夠留言告知具體在哪一種場景下用到了這種寫法。
浮點型
整型以後,下面是浮點型,在MySQL中浮點型有兩種,分別爲float、double,它們三者用一張表格總結一下:
數據類型 | 字節數 | 備註 |
float | 4 | 單精度浮點型 |
double | 8 | 雙精度浮點型 |
下面仍是用SQL來簡單看一下float和double型數據,以float爲例,double同理:
drop table if exists test_float; create table test_float ( num float(5, 2) ) engine=innodb charset=utf8; insert into test_float values(1.233); insert into test_float values(1.237); insert into test_float values(10.233); insert into test_float values(100.233); insert into test_float values(1000.233); insert into test_float values(10000.233); insert into test_float values(100000.233); select * from test_float;
顯示結果爲:
從這個結果咱們總結一下float(M,D)、double(M、D)的用法規則:
當咱們不指定M、D的時候,會按照實際的精度來處理。
定點型
介紹完float、double兩種浮點型,咱們介紹一下定點型的數據類型decimal類型,有了浮點型爲何咱們還須要定點型?寫一段SQL看一下就明白了:
drop table if exists test_decimal; create table test_decimal ( float_num float(10, 2), double_num double(20, 2), decimal_num decimal(20, 2) ) engine=innodb charset=utf8; insert into test_decimal values(1234567.66, 1234567899000000.66, 1234567899000000.66); insert into test_decimal values(1234567.66, 12345678990000000.66, 12345678990000000.66);
運行結果爲:
看到float、double類型存在精度丟失問題,即寫入數據庫的數據未必是插入數據庫的數據,而decimal不管寫入數據中的數據是多少,都不會存在精度丟失問題,這就是咱們要引入decimal類型的緣由,decimal類型常見於銀行系統、互聯網金融系統等對小數點後的數字比較敏感的系統中。
最後講一下decimal和float/double的區別,我的總結主要體如今兩點上:
日期類型
接着咱們看一下MySQL中的日期類型,MySQL支持五種形式的日期類型:date、time、year、datetime、timestamp,用一張表格總結一下這五種日期類型:
數據類型 | 字節數 | 格式 | 備註 |
date | 3 | yyyy-MM-dd | 存儲日期值 |
time |
3 | HH:mm:ss | 存儲時分秒 |
year | 1 | yyyy | 存儲年 |
datetime | 8 | yyyy-MM-dd HH:mm:ss | 存儲日期+時間 |
timestamp | 4 | yyyy-MM-dd HH:mm:ss | 存儲日期+時間,可做時間戳 |
下面咱們仍是用SQL來驗證一下:
drop table if exists test_time; create table test_time ( date_value date, time_value time, year_value year, datetime_value datetime, timestamp_value timestamp ) engine=innodb charset=utf8; insert into test_time values(now(), now(), now(), now(), now());
看一下插入後的結果:
MySQL的時間類型的知識點比較簡單,這裏重點關注一下datetime與timestamp兩種類型的區別:
在實際工做中,一張表每每咱們會有兩個默認字段,一個記錄建立時間而另外一個記錄最新一次的更新時間,這種時候可使用timestamp類型來實現:
create_time timestamp default current_timestamp comment "建立時間", update_time timestamp default current_timestamp on update current_timestamp comment "修改時間",
char和varchar類型
最後看一下經常使用到的字符型,說到MySQL字符型,咱們最熟悉的應該就是char和varchar了,關於char和varchar的對比,我總結一下:
關於第一點、第二點,稍後專門開一個篇幅解釋,關於第三點,寫一下SQL驗證一下:
drop table if exists test_string; create table test_string ( char_value char(5), varchar_value varchar(5) ) engine=innodb charset=utf8; insert into test_string values('a', 'a'); insert into test_string values(' a', ' a'); insert into test_string values('a ', 'a '); insert into test_string values(' a ', ' a ');
使用length函數來看一下結果:
驗證了咱們的結論,char類型數據並不會取最後的空格。
varchar型數據佔用空間大小及可容納最大字符串限制探究
接上一部分,咱們這部分來探究一下varchar型數據實際佔用空間大小是如何計算的以及最大可容納的字符串爲多少,首先要給出一個結論:這部分和具體編碼方式有關,且MySQL版本我如今使用的是5.7,固然5.0以後的都是能夠的。
先寫一段SQL建立表,utf8的編碼格式:
drop table if exists test_varchar; create table test_varchar ( varchar_value varchar(100000) ) engine=innodb charset=utf8;
執行報錯:
Column length too big for column 'varchar_value' (max = 21845); use BLOB or TEXT instead
按照提示,咱們把大小改成21845,執行依然報錯:
Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
改成21844就不會有問題,所以在utf8編碼下咱們能夠知道varchar(M),M最大=21844。那麼gbk呢:
drop table if exists test_varchar; create table test_varchar ( varchar_value varchar(100000) ) engine=innodb charset=gbk;
一樣的報錯:
Column length too big for column 'varchar_value' (max = 32767); use BLOB or TEXT instead
把大小改成32766,也是和utf8編碼格式同樣的報錯:
Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
可見gbk的編碼格式下,varchar(M)最大的M=32765,那麼爲何會有這樣的區別呢,分點詳細解釋一下:
一樣的,上面是表中只有varchar型數據的狀況,若是表中同時存在int、double、char這些數據,須要把這些數據所佔據的空間減去,才能計算varchar(M)型數據M最大等於多少。
varchar、text和blob
最後講一講text和blob兩種數據類型,它們的設計初衷是爲了存儲大數據使用的,由於以前說了,MySql單行最大數據量爲64K。
先說一下text,text和varchar是一組既有區別又有聯繫的數據類型,其聯繫在於當varchar(M)的M大於某些數值時,varchar會自動轉爲text:
因此過大的內容varchar和text沒有區別,同事varchar(M)和text的區別在於:
varchar和text兩種數據類型,使用建議是能用varchar就用varchar而不用text(存儲效率高),varchar(M)的M有長度限制,以前說過,若是大於限制,可使用mediumtext(16M)或者longtext(4G)。
至於text和blob,簡單過一下就是text存儲的是字符串而blob存儲的是二進制字符串,簡單說blob是用於存儲例如圖片、音視頻這種文件的二進制數據的。