一 介紹 存儲引擎決定了表的類型,而表記憶體放的數據也要有不同的類型,每種數據類型都有自己的寬度,但寬度是可選的 詳細參考: http://www.runoob.com/mysql/mysql data types.html http://dev.mysql.com/doc/refman/5.7/en ...
一 介紹
存儲引擎決定了表的類型,而表記憶體放的數據也要有不同的類型,每種數據類型都有自己的寬度,但寬度是可選的
詳細參考:
- http://www.runoob.com/mysql/mysql-data-types.html
- http://dev.mysql.com/doc/refman/5.7/en/data-type-overview.html
mysql常用數據類型概覽:
#1. 數字:
整型:tinyinit int bigint
小數:
float :在位數比較短的情況下不精準
double :在位數比較長的情況下不精準
0.000001230123123123
存成:0.000001230000
decimal:(如果用小數,則用推薦使用decimal)
精準
內部原理是以字元串形式去存
#2. 字元串:
char(10):簡單粗暴,浪費空間,存取速度快
root存成root000000
varchar:精準,節省空間,存取速度慢
sql優化:創建表時,定長的類型往前放,變長的往後放
比如性別 比如地址或描述信息
>255個字元,超了就把文件路徑存放到資料庫中。
比如圖片,視頻等找一個文件伺服器,資料庫中只存路徑或url。
#3. 時間類型:
最常用:datetime
#4. 枚舉類型與集合類型
二 數值類型
1、整數類型
整數類型:TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT
作用:存儲年齡,等級,id,各種號碼等
tinyint[(m)] [unsigned] [zerofill]
小整數,數據類型用於保存一些範圍的整數數值範圍:
有符號:
-128 ~ 127
無符號:
0 ~ 255
PS: MySQL中無布爾值,使用tinyint(1)構造。
int[(m)][unsigned][zerofill]
整數,數據類型用於保存一些範圍的整數數值範圍:
有符號:
-2147483648 ~ 2147483647
無符號:
0 ~ 4294967295
bigint[(m)][unsigned][zerofill]
大整數,數據類型用於保存一些範圍的整數數值範圍:
有符號:
-9223372036854775808 ~ 9223372036854775807
無符號:
0 ~ 18446744073709551615
有符號和無符號tinyint
1.tinyint預設為有符號
mysql> create table t1(x tinyint); #預設為有符號,即數字前有正負號
mysql> desc t1;
mysql> insert into t1 values
-> (-129),
-> (-128),
-> (127),
-> (128);
mysql> select * from t1;
+------+
| x |
+------+
| -128 | #-129存成了-128
| -128 | #有符號,最小值為-128
| 127 | #有符號,最大值127
| 127 | #128存成了127
+------+
2.設置無符號tinyint
mysql> create table t2(x tinyint unsigned);
mysql> insert into t2 values
-> (-1),
-> (0),
-> (255),
-> (256);
mysql> select * from t2;
+------+
| x |
+------+
| 0 | -1存成了0
| 0 | #無符號,最小值為0
| 255 | #無符號,最大值為255
| 255 | #256存成了255
+------+
有符號和無符號int
1.int預設為有符號
mysql> create table t3(x int); #預設為有符號整數
mysql> insert into t3 values
-> (-2147483649),
-> (-2147483648),
-> (2147483647),
-> (2147483648);
mysql> select * from t3;
+-------------+
| x |
+-------------+
| -2147483648 | #-2147483649存成了-2147483648
| -2147483648 | #有符號,最小值為-2147483648
| 2147483647 | #有符號,最大值為2147483647
| 2147483647 | #2147483648存成了2147483647
+-------------+
2.設置無符號int
mysql> create table t4(x int unsigned);
mysql> insert into t4 values
-> (-1),
-> (0),
-> (4294967295),
-> (4294967296);
mysql> select * from t4;
+------------+
| x |
+------------+
| 0 | #-1存成了0
| 0 | #無符號,最小值為0
| 4294967295 | #無符號,最大值為4294967295
| 4294967295 | #4294967296存成了4294967295
+------------+
有符號和無符號bigint
1.有符號bigint
mysql> create table t6(x bigint);
mysql> insert into t5 values
-> (-9223372036854775809),
-> (-9223372036854775808),
-> (9223372036854775807),
-> (9223372036854775808);
mysql> select * from t5;
+----------------------+
| x |
+----------------------+
| -9223372036854775808 |
| -9223372036854775808 |
| 9223372036854775807 |
| 9223372036854775807 |
+----------------------+
2.無符號bigint
mysql> create table t6(x bigint unsigned);
mysql> insert into t6 values
-> (-1),
-> (0),
-> (18446744073709551615),
-> (18446744073709551616);
mysql> select * from t6;
+----------------------+
| x |
+----------------------+
| 0 |
| 0 |
| 18446744073709551615 |
| 18446744073709551615 |
+----------------------+
用zerofill測試整數類型的顯示寬度
mysql> create table t7(x int(3) zerofill);
mysql> insert into t7 values
-> (1),
-> (11),
-> (111),
-> (1111);
mysql> select * from t7;
+------+
| x |
+------+
| 001 |
| 011 |
| 111 |
| 1111 | #超過寬度限制仍然可以存
+------+
註意:對於整型來說,數據類型後面的寬度並不是存儲長度限制,而是顯示限制,假如:int(8),那麼顯示時不夠8位則用0來填充,夠8位則正常顯示,通過zerofill來測試,存儲長度還是int的4個位元組長度。預設的顯示寬度就是能夠存儲的最大的數據的長度,比如:int無符號類型,那麼預設的顯示寬度就是int(10),有符號的就是int(11),因為多了一個符號,所以我們沒有必要指定整數類型的數據,沒必要指定寬度,因為預設的就能夠將你存的原始數據完全顯示
int的存儲寬度是4個Bytes,即32個bit,即2**32
無符號最大值為:4294967296-1
有符號最大值:2147483648-1
有符號和無符號的最大數字需要的顯示寬度均為10,而針對有符號的最小值則需要11位才能顯示完全,所以int類型預設的顯示寬度為11是非常合理的
最後:整形類型,其實沒有必要指定顯示寬度,使用預設的就ok
說到這裡我想提一下MySQL的mode設置,看我這篇博客:https://www.cnblogs.com/clschao/articles/9962347.html,看完博客應該就能理解MySQL的mode了。
2、浮點型
定點數類型 DEC,等同於DECIMAL
浮點類型:FLOAT DOUBLE
作用:存儲薪資、身高、溫度、體重、體質參數等
1.FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]
定義:
單精度浮點數(非準確小數值),m是整數部分+小數部分的總個數,d是小數點後個數。m最大值為255,d最大值為30,例如:float(255,30)
有符號:
-3.402823466E+38 to -1.175494351E-38,
1.175494351E-38 to 3.402823466E+38
無符號:
1.175494351E-38 to 3.402823466E+38
精確度:
**** 隨著小數的增多,精度變得不准確 ****
2.DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]
定義:
雙精度浮點數(非準確小數值),m是整數部分+小數部分的總個數,d是小數點後個數。m最大值也為255,d最大值也為30
有符號:
-1.7976931348623157E+308 to -2.2250738585072014E-308
2.2250738585072014E-308 to 1.7976931348623157E+308
無符號:
2.2250738585072014E-308 to 1.7976931348623157E+308
精確度:
****隨著小數的增多,精度比float要高,但也會變得不准確 ****
3.decimal[(m[,d])] [unsigned] [zerofill]
定義:
準確的小數值,m是整數部分+小數部分的總個數(負號不算),d是小數點後個數。 m最大值為65,d最大值為30。比float和double的整數個數少,但是小數位數都是30位
精確度:
**** 隨著小數的增多,精度始終準確 ****
對於精確數值計算時需要用此類型
decimal能夠存儲精確值的原因在於其內部按照字元串存儲。
精度從高到低:decimal、double、float
decimal精度高,但是整數位數少
float和double精度低,但是整數位數多
float已經滿足絕大多數的場景了,但是什麼導彈、航線等要求精度非常高,所以還是需要按照業務場景自行選擇,如果又要精度高又要整數位數多,那麼你可以直接用字元串來存。
mysql> create table t1(x float(256,31));
ERROR 1425 (42000): Too big scale 31 specified for column 'x'. Maximum is 30.
mysql> create table t1(x float(256,30));
ERROR 1439 (42000): Display width out of range for column 'x' (max = 255)
mysql> create table t1(x float(255,30)); #建表成功
Query OK, 0 rows affected (0.02 sec)
mysql> create table t2(x double(255,30)); #建表成功
Query OK, 0 rows affected (0.02 sec)
mysql> create table t3(x decimal(66,31));
ERROR 1425 (42000): Too big scale 31 specified for column 'x'. Maximum is 30.
mysql> create table t3(x decimal(66,30));
ERROR 1426 (42000): Too-big precision 66 specified for 'x'. Maximum is 65.
mysql> create table t3(x decimal(65,30)); #建表成功
Query OK, 0 rows affected (0.02 sec)
mysql> show tables;
+---------------+
| Tables_in_db1 |
+---------------+
| t1 |
| t2 |
| t3 |
+---------------+
3 rows in set (0.00 sec)
mysql> insert into t1 values(1.1111111111111111111111111111111); #小數點後31個1
Query OK, 1 row affected (0.01 sec)
mysql> insert into t2 values(1.1111111111111111111111111111111);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t3 values(1.1111111111111111111111111111111);
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> select * from t1; #隨著小數的增多,精度開始不准確
+----------------------------------+
| x |
+----------------------------------+
| 1.111111164093017600000000000000 |
+----------------------------------+
1 row in set (0.00 sec)
mysql> select * from t2; #精度比float要準確點,但隨著小數的增多,同樣變得不准確
+----------------------------------+
| x |
+----------------------------------+
| 1.111111111111111200000000000000 |
+----------------------------------+
1 row in set (0.00 sec)
mysql> select * from t3; #精度始終準確,d為30,於是只留了30位小數
+----------------------------------+
| x |
+----------------------------------+
| 1.111111111111111111111111111111 |
+----------------------------------+
1 row in set (0.00 sec)
3、位類型(瞭解,不講~~)
BIT(M)可以用來存放多位二進位數,M範圍從1~64,如果不寫預設為1位。
註意:對於位欄位需要使用函數讀取
bin()顯示為二進位
hex()顯示為十六進位
mysql> create table t9(id bit);
mysql> desc t9; #bit預設寬度為1
+-------+--------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------+------+-----+---------+-------+
| id | bit(1) | YES | | NULL | |
+-------+--------+------+-----+---------+-------+
mysql> insert into t9 values(8);
mysql> select * from t9; #直接查看是無法顯示二進位位的
+------+
| id |
+------+
| |
+------+
mysql> select bin(id),hex(id) from t9; #需要轉換才能看到
+---------+---------+
| bin(id) | hex(id) |
+---------+---------+
| 1 | 1 |
+---------+---------+
mysql> alter table t9 modify id bit(5);
mysql> insert into t9 values(8);
mysql> select bin(id),hex(id) from t9;
+---------+---------+
| bin(id) | hex(id) |
+---------+---------+
| 1 | 1 |
| 1000 | 8 |
+---------+---------+
三 日期類型
類型:DATE,TIME,DATETIME ,IMESTAMP,YEAR
作用:存儲用戶註冊時間,文章發佈時間,員工入職時間,出生時間,過期時間等
YEAR
YYYY(範圍:1901/2155)2018
DATE
YYYY-MM-DD(範圍:1000-01-01/9999-12-31)例:2018-01-01
TIME
HH:MM:SS(範圍:'-838:59:59'/'838:59:59')例:12:09:32
DATETIME
YYYY-MM-DD HH:MM:SS(範圍:1000-01-01 00:00:00/9999-12-31 23:59:59 Y)例: 2018-01-01 12:09:32
TIMESTAMP
YYYYMMDD HHMMSS(範圍:1970-01-01 00:00:00/2037 年某時)
year:
mysql> create table t10(born_year year); #無論year指定何種寬度,最後都預設是year(4)
mysql> insert into t10 values
-> (1900),
-> (1901),
-> (2155),
-> (2156);
mysql> select * from t10;
+-----------+
| born_year |
+-----------+
| 0000 |
| 1901 |
| 2155 |
| 0000 |
+-----------+
date,time,datetime:
mysql> create table t11(d date,t time,dt datetime);
mysql> desc t11;
+-------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| d | date | YES | | NULL | |
| t | time | YES | | NULL | |
| dt | datetime | YES | | NULL | |
+-------+----------+------+-----+---------+-------+
mysql> insert into t11 values(now(),now(),now());
mysql> select * from t11;
+------------+----------+---------------------+
| d | t | dt |
+------------+----------+---------------------+
| 2017-07-25 | 16:26:54 | 2017-07-25 16:26:54 |
+------------+----------+---------------------+
timestamp:
mysql> create table t12(time timestamp);
mysql> insert into t12 values();
mysql> insert into t12 values(null);
mysql> select * from t12;
+---------------------+
| time |
+---------------------+
| 2017-07-25 16:29:17 |
| 2017-07-25 16:30:01 |
+---------------------+
============註意啦,註意啦,註意啦===========
1. 單獨插入時間時,需要以字元串的形式,按照對應的格式插入
2. 插入年份時,儘量使用4位值
3. 插入兩位年份時,<=69,以20開頭,比如50, 結果2050
>=70,以19開頭,比如71,結果1971
mysql> create table t12(y year);
mysql> insert into t12 values
-> (50),
-> (71);
mysql> select * from t12;
+------+
| y |
+------+
| 2050 |
| 1971 |
+------+
============綜合練習===========
mysql> create table student(
-> id int,
-> name varchar(20),
-> born_year year,
-> birth date,
-> class_time time,
-> reg_time datetime);
mysql> insert into student values
-> (1,'sb1',"1995","1995-11-11","11:11:11","2017-11-11 11:11:11"),
-> (2,'sb2',"1997","1997-12-12","12:12:12","2017-12-12 12:12:12"),
-> (3,'sb3',"1998","1998-01-01","13:13:13","2017-01-01 13:13:13");
mysql> select * from student;
+------+------+-----------+------------+------------+---------------------+
| id | name | born_year | birth | class_time | reg_time |
+------+------+-----------+------------+------------+---------------------+
| 1 | sb1 | 1995 | 1995-11-11 | 11:11:11 | 2017-11-11 11:11:11 |
| 2 | sb2 | 1997 | 1997-12-12 | 12:12:12 | 2017-12-12 12:12:12 |
| 3 | sb3 | 1998 | 1998-01-01 | 13:13:13 | 2017-01-01 13:13:13 |
+------+------+-----------+------------+------------+---------------------+
mysql的日期格式對字元串採用的是'放鬆'政策,可以以字元串的形式插入。
在實際應用的很多場景中,MySQL的這兩種日期類型都能夠滿足我們的需要,存儲精度都為秒,但在某些情況下,會展現出他們各自的優劣。下麵就來總結一下兩種日期類型的區別。
1.DATETIME的日期範圍是1001——9999年,TIMESTAMP的時間範圍是1970——2038年。
2.DATETIME存儲時間與時區無關,TIMESTAMP存儲時間與時區有關,顯示的值也依賴於時區。在mysql伺服器,操作系統以及客戶端連接都有時區的設置。
3.DATETIME使用8位元組的存儲空間,TIMESTAMP的存儲空間為4位元組。因此,TIMESTAMP比DATETIME的空間利用率更高。
4.DATETIME的預設值為null;TIMESTAMP的欄位預設不為空(not null),預設值為當前時間(CURRENT_TIMESTAMP),如果不做特殊處理,並且update語句中沒有指定該列的更新值,則預設更新為當前時間。
工作中一般都用datetime就可以了。
mysql> create table t1(x datetime not null default now()); # 需要指定傳入空值時預設取當前時間
Query OK, 0 rows affected (0.01 sec)
mysql> create table t2(x timestamp); # 無需任何設置,在傳空值的情況下自動傳入當前時間
Query OK, 0 rows affected (0.02 sec)
mysql> insert into t1 values();
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2 values();
Query OK, 1 row affected (0.00 sec)
mysql> select * from t1;
+---------------------+
| x |
+---------------------+
| 2018-07-07 01:26:14 |
+---------------------+
1 row in set (0.00 sec)
mysql> select * from t2;
+---------------------+
| x |
+---------------------+
| 2018-07-07 01:26:17 |
+---------------------+
1 row in set (0.00 sec)
四 字元串類型
類型:char,varchar
作用:名字,信息等等
#官網:https://dev.mysql.com/doc/refman/5.7/en/char.html
#註意:char和varchar括弧內的參數指的都是字元的長度
#char類型:定長,簡單粗暴,浪費空間,存取速度快
字元長度範圍:0-255(一個中文是一個字元,是utf8編碼的3個位元組)
存儲:
存儲char類型的值時,會往右填充空格來滿足長度
例如:指定長度為10,存>10個字元則報錯(嚴格模式下),存<10個字元則用空格填充直到湊夠10個字元存儲
檢索:
在檢索或者說查詢時,查出的結果會自動刪除尾部的空格,如果你想看到它補全空格之後的內容,除非我們打開pad_char_to_full_length SQL模式(SET sql_mode = 'strict_trans_tables,PAD_CHAR_TO_FULL_LENGTH';)
#varchar類型:變長,精準,節省空間,存取速度慢
字元長度範圍:0-65535(如果大於21845會提示用其他類型 。mysql行最大限製為65535位元組,字元編碼為utf-8:https://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html)
存儲:
varchar類型存儲數據的真實內容,不會用空格填充,如果'ab ',尾部的空格也會被存起來
強調:varchar類型會在真實數據前加1-2Bytes的首碼,該首碼用來表示真實數據的bytes位元組數(1-2Bytes最大表示65535個數字,正好符合mysql對row的最大位元組限制,即已經足夠使用)
如果真實的數據<255bytes則需要1Bytes的首碼(1Bytes=8bit 2**8最大表示的數字為255)
如果真實的數據>255bytes則需要2Bytes的首碼(2Bytes=16bit 2**16最大表示的數字為65535)
檢索:
尾部有空格會保存下來,在檢索或者說查詢時,也會正常顯示包含空格在內的內容
下麵我們來進行一些測試,在測試之前,我們需要學一下mysql給我們提供的兩個方法:
length(欄位):查看該欄位數據的位元組長度
char_length(欄位):查看該欄位數據的字元長度
創建一個t1表,包含一個char類型的欄位
create table t1(id int,name char(4));
超過長度:
嚴格模式下(報錯):
mysql> insert into t1 values('xiaoshabi');
ERROR 1406 (22001): Data too long for column 'name' at row 1
非嚴格模式下(警告):
mysql> set sql_mode='NO_ENGINE_SUBSTITUTION';
Query OK, 0 rows affected (0.00 sec)
mysql> create table t1(id int,name char(4));
Query OK, 0 rows affected (0.40 sec)
mysql> insert into t2 values('xiaoshabi');
Query OK, 1 row affected, 1 warning (0.11 sec)
查看一下結果:
mysql> select * from t1;
+------+------+
| id | name |
+------+------+
| 1 | xiao | #只有一個xiao
+------+------+
1 row in set (0.00 sec)
varchar類型和上面的效果是一樣的,嚴格模式下也會報錯。
如果沒有超過長度,那麼char類型時mysql會使用空格來補全自己規定的char(4)的4個字元,varchar不會,我們來做個對比
例如:
#再創建一個含有varchar類型的表t2
然後插入幾條和t1裡面相同的數據
mysql>insert into t1 values(2,'a'),(3,'bb'),(4,'ccc'),(5,'d');
mysql>create table t2(id int,name varchar(4));
mysql> insert into t2 values(1,'xiao'),(2,'a'),(3,'bb'),(4,'ccc'),(5,'d');
查看一下t1表和t2表的內容
mysql> select * from t1;
+------+------+
| id | name |
+------+------+
| 1 | xiao |
| 2 | a |
| 3 | bb |
| 4 | ccc |
| 5 | d |
+------+------+
5 rows in set (0.00 sec)
mysql> select * from t2;
+------+------+
| id | name |
+------+------+
| 1 | xiao |
| 2 | a |
| 3 | bb |
| 4 | ccc |
| 5 | d |
+------+------+
5 rows in set (0.00 sec)
好,兩個表裡面數據是一樣的,每一項的數據長度也是一樣的,那麼我們來驗證一下char的自動空格在後面補全的存儲方式和varchar的不同
通過mysql提供的一個char_length()方法來查看一下所有數據的長度
mysql> select char_length(name) from t1;
+-------------------+
| char_length(name) |
+-------------------+
| 4 |
| 1 |
| 2 |
| 3 |
| 1 |
+-------------------+
5 rows in set (0.00 sec)
mysql> select char_length(name) from t2;
+-------------------+
| char_length(name) |
+-------------------+
| 4 |
| 1 |
| 2 |
| 3 |
| 1 |
+-------------------+
5 rows in set (0.00 sec)
通過查看結果可以看到,兩者顯示的數據長度是一樣的,不是說好的char會補全嗎,我設置的欄位是char(4),那麼長度應該都是4才對啊?這是因為mysql在你查詢的時候自動幫你把結果裡面的空格去掉了,如果我們想看到它存儲數據的真實長度,需要設置mysql的模式,通過一個叫做PAD_CHAR_TO_FULL_LENGTH的模式,就可以看到了,所以我們把這個模式加到sql_mode裡面:
mysql> set sql_mode='PAD_CHAR_TO_FULL_LENGTH';
Query OK, 0 rows affected (0.00 sec)
然後我們在查看一下t1和t2數據的長度:
mysql> select char_length(name) from t1;
+-------------------+
| char_length(name) |
+-------------------+
| 4 |
| 4 |
| 4 |
| 4 |
| 4 |
+-------------------+
5 rows in set (0.00 sec)
mysql> select char_length(name) from t2;
+-------------------+
| char_length(name) |
+-------------------+
| 4 |
| 1 |
| 2 |
| 3 |
| 1 |
+-------------------+
5 rows in set (0.00 sec)
通過結果可以看到,char類型的數據長度都是4,這下看到了兩者的不同了吧,至於為什麼mysql會這樣搞,我們後面有解釋的,先看現象就可以啦。
現在我們再來看一個問題,就是當你設置的類型為char的時候,我們通過where條件來查詢的時候會有一個什麼現象:
mysql> select * from t1 where name='a';
+------+------+
| id | name |
+------+------+
| 2 | a |
+------+------+
1 row in set (0.00 sec)
ok,結果沒問題,我們在where後面的a後面加一下空格再來試試:
mysql> select * from t1 where name='a ';
+------+------+
| id | name |
+------+------+
| 2 | a |
+------+------+
1 row in set (0.00 sec)
ok,能查到,再多加一些空格試試,加6個空格,超過了設置的char(4)的4:
mysql> select * from t1 where name='a ';
+------+------+
| id | name |
+------+------+
| 2 | a |
+------+------+
1 row in set (0.00 sec)
ok,也是沒問題的
總結:通過>,=,>=,<,<=作為where的查詢條件的時候,char類型欄位的查詢是沒問題的。
但是,當我們將where後面的比較符號改為like的時候,(like是模糊匹配的意思,我們前面見過,show variables like '%char%';來查看mysql字元集的時候用過)
其中%的意思是匹配任意字元(0到多個字元都可以匹配到),還有一個符號是_(匹配1個字元),這兩個字元其實就像我們學的正則匹配裡面的通配符,那麼我們通過這些符號進行一下模糊查詢,看一下,char類型進行模糊匹配的時候,是否還能行,看例子:
mysql> select * from t1 where name like 'a';
Empty set (0.00 sec)
發現啥也沒查到,因為char存儲的數據是4個字元長度的,不滿4個是以空格來補全的,你在like後面就只寫了一個'a',是無法查到的。
我們試一下上面的通配符來查詢:
mysql> select * from t1 where name like 'a%';
+------+------+
| id | name |
+------+------+
| 2 | a |
+------+------+
1 row in set (0.00 sec)
這樣就能看到查詢結果了
試一下_是不是匹配1個字元:
mysql> select * from t1 where name like 'a_';
Empty set (0.00 sec)
發現一個_果然不行,我們試試三個_。
mysql> select * from t1 where name like 'a___';
+------+------+
| id | name |
+------+------+
| 2 | a |
+------+------+
1 row in set (0.00 sec)
發現果然能行,一個_最多匹配1個任意字元。
如果多寫了幾個_呢?
mysql> select * from t1 where name like 'a_____';
Empty set (0.00 sec)
查不到結果,說明_匹配的是1個字元,但不是0-1個字元。
測試結果總結:
針對char類型,mysql在存儲的時候會將不足規定長度的數據使用後面(右邊補全)補充空格的形式進行補全,然後存放到硬碟中,但是在讀取或者使用的時候會自動去掉它給你補全的空格內容,因為這些空格並不是我們自己存儲的數據,所以對我們使用者來說是無用的。
char和varchar性能對比:
以char(5)和varchar(5)來比較,加入我要存三個人名:sb,ssb1,ssbb2
char:
優點:簡單粗暴,不管你是多長的數據,我就按照規定的長度來存,5個5個的存,三個人名就會類似這種存儲:sb ssb1 ssbb2,中間是空格補全,取數據的時候5個5個的取,簡單粗暴速度快
缺點:貌似浪費空間,並且我們將來存儲的數據的長度可能會參差不齊
varchar:
varchar類型不定長存儲數據,更為精簡和節省空間
例如存上面三個人名的時候類似於是這樣的:sbssb1ssbb2,連著的,如果這樣存,請問這三個人名你還怎麼取出來,你知道取多長能取出第一個嗎?(超哥,我能看出來啊,那我只想說:滾犢子!)
不知道從哪開始從哪結束,遇到這樣的問題,你會想到怎麼解決呢?還記的嗎?想想?socket?tcp?struct?把數據長度作為消息頭。
所以,varchar在存數據的時候,會在每個數據前面加上一個頭,這個頭是1-2個bytes的數據,這個數據指的是後面跟著的這個數據的長度,1bytes能表示28=256,兩個bytes表示216=65536,能表示0-65535的數字,所以varchar在存儲的時候是這樣的:1bytes+sb+1bytes+ssb1+1bytes+ssbb2,所以存的時候會比較麻煩,導致效率比char慢,取的時候也慢,先拿長度,再取數據。
優點:節省了一些硬碟空間,一個acsii碼的字元用一個bytes長度就能表示,但是也並不一定比char省,看一下官網給出的一個表格對比數據,當你存的數據正好是你規定的欄位長度的時候,varchar反而占用的空間比char要多。
Value | CHAR(4) |
Storage Required | VARCHAR(4) |
Storage Required |
---|---|---|---|---|
'' |
' ' |
4 bytes | '' |
1 byte |
'ab' |
'ab ' |
4 bytes | 'ab' |
3 bytes |
'abcd' |
'abcd' |
4 bytes | 'abcd' |
5 bytes |
'abcdefgh' |
'abcd' |
4 bytes | 'abcd' |
5 bytes |
缺點:存取速度都慢
總結:
所以需要根據業務需求來選擇用哪種類型來存
其實在多數的用戶量少的工作場景中char和varchar效率差別不是很大,最起碼給用戶的感知不是很大,並且其實軟體級別的慢遠比不上硬體級別的慢,所以你們公司的運維發現項目慢的時候會加記憶體、換nb的硬碟,項目的效率提升的會很多,但是我們作為專業人士,我們應該提出來這樣的技術點來提高效率。
但是對於InnoDB數據表,內部的行存儲格式沒有區分固定長度和可變長度列(所有數據行都使用指向數據列值的頭指針),因此在本質上,使用固定長度的CHAR列不一定比使用可變長度VARCHAR列性能要好。因而,主要的性能因素是數據行使用的存儲總量。由於CHAR平均占用的空間多於VARCHAR,因此使用VARCHAR來最小化需要處理的數據行的存儲總量和磁碟I/O是比較好的。
所以啊,兩個選哪個都可以,如果是大型併發項目,追求高性能的時候,需要結合你們伺服器的硬體環境來進行測試,看一下char和varchar哪個更好,這也能算一個優化的點吧~~~~
#官網:https://dev.mysql.com/doc/refman/5.7/en/char.html
CHAR 和 VARCHAR 是最常使用的兩種字元串類型。
一般來說
CHAR(N)用來保存固定長度的字元串,對於 CHAR 類型,N 的範圍 為 0 ~ 255
VARCHAR(N)用來保存變長字元類型,對於 VARCHAR 類型,N 的範圍為 0 ~ 65 535
CHAR(N)和 VARCHAR(N) 中的 N 都代表字元長度,而非位元組長度。
ps:對於 MySQL 4.1 之前的版本,如 MySQL 3.23 和 MySQL 4.0,CHAR(N)和 VARCHAR (N)中的 N 代表位元組長度。
#CHAR類型
對於 CHAR 類型的字元串,MySQL 資料庫會自動對存儲列的右邊進行填充(Right Padded)操作,直到字元串達到指定的長度 N。而在讀取該列時,MySQL 資料庫會自動將 填充的字元刪除。有一種情況例外,那就是顯式地將 SQL_MODE 設置為 PAD_CHAR_TO_ FULL_LENGTH,例如:
mysql> CREATE TABLE t ( a CHAR(10));
Query OK, 0 rows affected (0.03 sec)
mysql> INSERT INTO t SELECT 'abc';
Query OK, 1 row affected (0.03 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT a,HEX(a),LENGTH(a) FROM t\G;
*************************** 1. row ***************************
a: abc
HEX(a): 616263
LENGTH (a): 3
1 row in set (0.00 sec)
mysql> SET SQL_MODE='PAD_CHAR_TO_FULL_LENGTH';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT a,HEX(a),LENGTH(a) FROM t\G;
*************************** 1. row ***************************
a: abc
HEX(a): 61626320202020202020
LENGTH (a): 10
1 row in set (0.00 sec)
在上述這個例子中,先創建了一張表 t,a 列的類型為 CHAR(10)。然後通過 INSERT語句插入值“abc”,因為 a 列的類型為 CHAR 型,所以會自動在後面填充空字元串,使其長 度為 10。接下來在通過 SELECT 語句取出數據時會將 a 列右填充的空字元移除,從而得到 值“abc”。通過 LENGTH 函數看到 a 列的字元長度為 3 而非 10。
接著我們將 SQL_MODE 顯式地設置為 PAD_CHAR_TO_FULL_LENGTH。這時再通過 SELECT 語句進行查詢時,得到的結果是“abc ”,abc 右邊有 7 個填充字元 0x20,並通 過 HEX 函數得到了驗證。這次 LENGTH 函數返回的長度為 10。需要註意的是,LENGTH 函數返回的是位元組長度,而不是字元長度。對於多位元組字元集,CHAR(N)長度的列最多 可占用的位元組數為該字元集單字元最大占用位元組數 *N。例如,對於 utf8 下,CHAR(10)最 多可能占用 30 個位元組。通過對多位元組字元串使用 CHAR_LENGTH 函數和 LENGTH 函數, 可以發現兩者的不同,示例如下:
mysql> SET NAMES gbk;
Query OK, 0 rows affected (0.03 sec)
mysql> SELECT @a:='MySQL 技術內幕 '; Query OK, 0 rows affected (0.03 sec)
mysql> SELECT @a,HEX(@a),LENGTH(@a),CHAR_LENGTH(@a)\G; ***************************** 1. row **************************** a: MySQL 技術內幕
HEX(a): 4D7953514CBCBCCAF5C4DAC4BB
LENGTH (a): 13
CHAR_LENGTH(a): 9
1 row in set (0.00 sec)
變 量 @ a 是 g b k 字 符 集 的 字 符 串 類 型 , 值 為 “ M y S Q L 技 術 內 幕 ”, 十 六 進 制 為 0x4D7953514CBCBCCAF5C4DAC4BB,LENGTH 函數返回 13,即該字元串占用 13 位元組, 因為 gbk 字元集中的中文字元占用兩個位元組,因此一共占用 13 位元組。CHAR_LENGTH 函數 返回 9,很顯然該字元長度為 9。
#VARCHAR類型
VARCHAR 類型存儲變長欄位的字元類型,與 CHAR 類型不同的是,其存儲時需要在 首碼長度列表加上實際存儲的字元,該字元占用 1 ~ 2 位元組的空間。當存儲的字元串長度小 於 255 位元組時,其需要 1 位元組的空間,當大於 255 位元組時,需要 2 位元組的空間。所以,對 於單位元組的 latin1 來說,CHAR(10)和 VARCHAR(10)最大占用的存儲空間是不同的, CHAR(10)占用 10 個位元組這是毫無疑問的,而 VARCHAR(10)的最大占用空間數是 11 位元組,因為其需要 1 位元組來存放字元長度。
-------------------------------------------------
註意 對於有些多位元組的字元集類型,其 CHAR 和 VARCHAR 在存儲方法上是一樣的,同樣 需要為長度列表加上字元串的值。對於 GBK 和 UTF-8 這些字元類型,其有些字元是以 1 位元組 存放的,有些字元是按 2 或 3 位元組存放的,因此同樣需要 1 ~ 2 位元組的空間來存儲字元的長 度。
-------------------------------------------------
雖然 CHAR 和 VARCHAR 的存儲方式不太相同,但是對於兩個字元串的比較,都只比 較其值,忽略 CHAR 值存在的右填充,即使將 SQL _MODE 設置為 PAD_CHAR_TO_FULL_ LENGTH 也一樣,例如:
mysql> CREATE TABLE t ( a CHAR(10), b VARCHAR(10));
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t SELECT 'a','a';
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT a=b FROM t\G;
*************************** 1. row ***************************
a=b: 1
1 row in set (0.00 sec)
mysql> SET SQL_MODE='PAD_CHAR_TO_FULL_LENGTH';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT a=b FROM t\G;
*************************** 1. row ***************************
a=b: 1
1 row in set (0.00 sec)
其他的字元串類型:BINARY、VARBINARY、BLOB、TEXT
BINARY 和 VARBINARY 類似於 CHAR 和 VARCHAR,不同的是它們包含二進位字元串而不要非二進位字元串。也就是說,它們包含位元組字元串而不是字元字元串。這說明它們沒有字元集,並且排序和比較基於列值位元組的數值值。
BLOB 是一個二進位大對象,可以容納可變數量的數據。有 4 種 BLOB 類型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它們區別在於可容納存儲範圍不同。
有 4 種 TEXT 類型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。對應的這 4 種 BLOB 類型,可存儲的最大長度不同,可根據實際情況選擇。
BLOB:
1._BLOB和_text存儲方式不同,_TEXT以文本方式存儲,英文存儲區分大小寫,而_Blob是以二進位方式存儲,不分大小寫。
2._BLOB存儲的數據只能整體讀出。
3._TEXT可以指定字元集,_BLO不用指定字元集。
五 枚舉類型與集合類型
欄位的值只能在給定範圍中選擇,如單選框,多選框,如果你在應用程式或者前端不做選項限制,在MySQL的欄位裡面也能做限制
enum 單選 只能在給定的範圍內選一個值,如性別 sex 男male/女female
set 多選 在給定的範圍內可以選擇一個或一個以上的值(愛好1,愛好2,愛好3...)
枚舉類型(enum)
An ENUM column can have a maximum of 65,535 distinct elements. (The practical limit is less than 3000.)
示例:
CREATE TABLE shirts (
name VARCHAR(40),
size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
);
INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),('polo shirt','small');
集合類型(set)
A SET column can have a maximum of 64 distinct members.
示例:
CREATE TABLE myset (col SET('a', 'b', 'c', 'd'));
INSERT INTO myset (col) VALUES ('a,d'), ('d,a'), ('a,d,a'), ('a,d,d'), ('d,a,d');
mysql> create table consumer(
-> name varchar(50),
-> sex enum('male','female'),
-> level enum('vip1','vip2','vip3','vip4','vip5'), #在指定範圍內,多選一
-> hobby set('play','music','read','study') #在指定範圍內,多選多
-> );
mysql> insert into consumer values
-> ('xiaogui','male','vip5','read,study'),
-> ('taibai','female','vip1','girl');
mysql> select * from consumer;
+------+--------+-------+------------+
| name | sex | level | hobby |
+------+--------+-------+------------+
| xiaogui | male | vip5 | read,study |
| taibai | female | vip1 | |
+------+--------+-------+------------+