MySQL的CHAR和VARCHAR注意事項(xiàng)以及binary和varbinary存儲(chǔ)方式是怎樣的,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。
在鳳慶等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都做網(wǎng)站、成都網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作定制網(wǎng)站制作,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計(jì),全網(wǎng)整合營銷推廣,成都外貿(mào)網(wǎng)站建設(shè),鳳慶網(wǎng)站建設(shè)費(fèi)用合理。
版本使用5.7 存儲(chǔ)引擎INNODB 行格式Dynamic
從概念上講他們用于存放字符型數(shù)據(jù),其允許的范圍:
1、char 0-255 bytes,固定長度,不夠的長度用ASCII 0X20進(jìn)行補(bǔ)足。
2、varchar 0-65535(2^8-1)bytes,注意是整個(gè)表所有的varchar字段的長度,所謂 可變長度,就是按需分配空間。
下面就幾個(gè)問題進(jìn)行討論:
第一個(gè)問題:varchar的可變長度
那么這里引出了第一個(gè)問題,可變長度,在INNODB(Dynamic 行格式),在行頭使用,1-2個(gè)字節(jié)
來存儲(chǔ)這個(gè)可變長度及:
variable field lengths (1-2 bytes* var )
(具體參考http://blog.itpub.net/7728585/viewspace-2071787/)
2個(gè)字節(jié)也剛好是65535的長度,這是INNODB對(duì)MYSQL的一個(gè)實(shí)現(xiàn)方法,同時(shí)如果使用5.7 INNODB
online DDL進(jìn)行modify varchar column的長度,在1-255 和 256-65535之間都可以迅速完成,但是
如果跨越比如改變一個(gè)varchar 字段的長度從250 到 300 注意是字節(jié),就會(huì)出現(xiàn)需要使用
inpace或者copy等方法,那就非常慢了,原因也在這里因?yàn)樯婕暗叫蓄^的擴(kuò)張了,以前是一
個(gè)字節(jié)來存儲(chǔ)長度,而改變后需要二個(gè)字節(jié),當(dāng)然也就需要重新組織表,而如果不跨越就不
會(huì)改變表的組織方式,也就值需要修改數(shù)據(jù)字典和frm文件而已,當(dāng)然瞬間完成,下面來做
一個(gè)測(cè)試。對(duì)于UTF8字符集,它的這個(gè)點(diǎn)是255/3=85。
注意使用版本5.7 引擎為innodb 行格式為Dynamic,并且這一列不能有索引,如果有索引
索引會(huì)帶入而外的操作,也是比較慢的
mysql> select count(*) from testshared3;
+----------+
| count(*) |
+----------+
| 1048576 |
+----------+
1 row in set (0.35 sec)
mysql> show create table testshared3;
+-------------+----------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------------+----------------------------------------------------------------------------------------------------------------------------------+
| testshared3 | CREATE TABLE `testshared3` (
`id` int(11) DEFAULT NULL,
`name` varchar(13) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------------+----------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
mysql> alter table testshared3 change name name varchar(85) ;
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
可以看到雖然有1048576行的數(shù)據(jù)但是modify還是瞬間完成了。但是如果從85改到86如何呢?
mysql> alter table testshared3 ALGORITHM=INPLACE, change name name varchar(86) ;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
mysql> alter table testshared3 change name name varchar(86) ;
Query OK, 1048576 rows affected (15.68 sec)
Records: 1048576 Duplicates: 0 Warnings: 0
可以看到使用了15秒多,而且ALGORITHM=COPY。
第二個(gè)問題:關(guān)于char和varchar 左空格存儲(chǔ)以及顯示的不同
mysql> create table testvc(name1 varchar(5),name2 char(5));
Query OK, 0 rows affected (0.08 sec)
mysql> insert into testvc values('gao ','gao ');
Query OK, 1 row affected (0.01 sec)
mysql> select concat(name1,')'),concat(name2,')') from testvc;
+-------------------+-------------------+
| concat(name1,')') | concat(name2,')') |
+-------------------+-------------------+
| gao ) | gao) |
+-------------------+-------------------+
1 row in set (0.06 sec)
可以看到varchar可以正常顯示gao后面的空格,而char卻不行,那么他們內(nèi)部到底是如何存儲(chǔ)的,我們需要
用二進(jìn)制方式查看一下:
(下面是我解析好的,具體的方法參考http://blog.itpub.net/7728585/viewspace-2071787/需要用到我自己
寫的幾個(gè)小工具)
04 --varchar 長度
00 --NULL位圖
00
0010
0024
00000089a25
40000002e0c1bd9
000001640110
67616f20 --varchar(5) 'gao '
67616f2020 --char(5) 'gao '
這里我們可以明顯看到varchar的長度為4,當(dāng)存儲(chǔ)varchar的'gao '的時(shí)候存儲(chǔ)的是0X67616f20也就是ASCII的'gao ',當(dāng)存儲(chǔ)char類型的'gao '
的時(shí)候?yàn)?X67616f2020,可以看到他后面有兩個(gè)0X20,也就是ASCII的空格那么我們可以知道char(5)會(huì)對(duì)不夠的字節(jié)全部補(bǔ)上ASCII 0X20,這也就是
為什么輸出的時(shí)候空格不在了,因?yàn)榱薱har字段中存儲(chǔ)的時(shí)候尾部的0X20作為了補(bǔ)足的字符,而VARCHAR中卻不是這樣0X20作為了實(shí)際的字符,也就
是空格那么輸出就有了。
第三個(gè)問題:比較和varchar以及char尾部的空格。
在MYSQL文檔中描述:
This means that all CHAR, VARCHAR, and TEXT values in MySQL are compared without regard to any trailing spaces
“Comparison”in this context does not include the LIKEpattern-matching operator
For those cases where trailing pad characters are stripped or comparisons ignore them, if a column has
an index that requires unique values, inserting into the column values that differ only in number of trailing
pad characters will result in a duplicate-key error.
也就是除了LIKE的比較操作,都會(huì)忽略尾部空格不管是VARCHAR CHAR 還是TEXT,并且如果字段是唯一鍵,唯一性判斷的時(shí)候
也會(huì)忽略空格。
還是剛才的表我們?cè)趘archar 的name1上加上唯一索引。
mysql> alter table testvc add unique key(name1);
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
我們剛才插入的數(shù)據(jù)為
insert into testvc values('gao ','gao ');
mysql> select * from testvc where name1='gao ';
+-------+-------+
| name1 | name2 |
+-------+-------+
| gao | gao |
+-------+-------+
1 row in set (0.00 sec)
mysql> select * from testvc where name1='gao';
+-------+-------+
| name1 | name2 |
+-------+-------+
| gao | gao |
+-------+-------+
1 row in set (0.00 sec)
可以看到不管存儲(chǔ)有沒有0X20空格,也不管條件=后面是否有0X20空格
都會(huì)查詢出來,我們來測(cè)試一下插入
mysql> insert into testvc values('gao','gao10');
ERROR 1062 (23000): Duplicate entry 'gao' for key 'name1'
mysql> insert into testvc values('gao ','gao10');
ERROR 1062 (23000): Duplicate entry 'gao ' for key 'name1'
不管我插入的是'gao'還是'gao '都是重復(fù)的值,證明的文檔的說法,另外
這個(gè)問題在ORACLE中是不存在,MYSQL也比較奇怪。很多ORACLE的概念在MYSQL
中需要打一個(gè)問號(hào)。
ORACLE:
SQL> create table testui1(name varchar2(20));
Table created
SQL> create unique index testuiq_IDX on testui1(name);
Index created
SQL> insert into testui1 values('gao');
1 row inserted
SQL> insert into testui1 values('gao ');
1 row inserted
SQL> insert into testui1 values('gao ');
1 row inserted
SQL> commit;
Commit complete
接下來看看LIKE:
varchar:
mysql> select * from testvc where name1 like 'gao %';
+-------+-------+
| name1 | name2 |
+-------+-------+
| gao | gao |
+-------+-------+
1 row in set (0.00 sec)
mysql> select * from testvc where name1='gao ';
+-------+-------+
| name1 | name2 |
+-------+-------+
| gao | gao |
+-------+-------+
1 row in set (0.00 sec)
char:
mysql> select * from testvc where name2 like 'gao %';
Empty set (0.00 sec)
mysql> select * from testvc where name2='gao ';
+-------+-------+
| name1 | name2 |
+-------+-------+
| gao | gao |
+-------+-------+
1 row in set (0.00 sec)
這里 char name2 like 'gao %' 沒有出來數(shù)據(jù),而varchar name1 like 'gao %'
出來了數(shù)據(jù)也正是證明了我們對(duì)存儲(chǔ)格式的剖析,因?yàn)閏har對(duì)尾部的0X20空格在
存儲(chǔ)的時(shí)候已經(jīng)去掉了,但是VARCHAR沒有,只要LIKE是嚴(yán)格匹配就會(huì)出來這樣的
效果。
最后來看看MYSQL的binary和varbinary格式,這種格式就是說明其存儲(chǔ)和比較都使用二進(jìn)制格式,也就是按照一個(gè)
字節(jié)一個(gè)字節(jié)的比較ASCII值,官方描述如下:
they contain byte strings rather than character strings. This
means that they have no character set, and sorting and comparison are based on the numeric values of
the bytes in the values.
他們的意義和char和varchar相似,但是有一點(diǎn),其比較方法和存儲(chǔ)方法不太一樣
binary 使用0X00也就是\0補(bǔ)足不夠的字節(jié),而其比較也是嚴(yán)格和存儲(chǔ)中的格式進(jìn)行
匹配不存在char和varchar那樣對(duì)空格的處理
mysql> insert into testbin3 values('a ','a ');
Query OK, 1 row affected (0.03 sec)
mysql> desc testbin3;
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| name1 | varbinary(10) | YES | | NULL | |
| name2 | binary(10) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> select * from testbin3 where name1='a ';
+-------+------------+
| name1 | name2 |
+-------+------------+
| a | a |
+-------+------------+
1 row in set (0.00 sec)
mysql> select * from testbin3 where name2='a ';
Empty set (0.00 sec)
mysql> select * from testbin3 where name2='a \0\0\0\0\0\0\0\0';
+-------+------------+
| name1 | name2 |
+-------+------------+
| a | a |
+-------+------------+
1 row in set (0.00 sec)
可以看到varbinary使用'a '可以查詢到記錄但是binary使用'a '不能查到,為什么呢?
我們看看他的內(nèi)部存儲(chǔ)
00000089a25f
0000002e0c66bc
0000012a0110
6120 --binary 'a '
612000000000000000 --varbinary 'a '
可以看到varbinary使用8個(gè)0X00進(jìn)行補(bǔ)足,既然他嚴(yán)格按照而進(jìn)行進(jìn)行匹配那么我們這樣可以
查出數(shù)據(jù):
mysql> select * from testbin3 where name2='a \0\0\0\0\0\0\0\0';
+-------+------------+
| name1 | name2 |
+-------+------------+
| a | a |
+-------+------------+
1 row in set (0.00 sec)
當(dāng)然unique也是嚴(yán)格按照而進(jìn)行進(jìn)行比較
增加一個(gè)unique key 在binary 上
mysql> alter table testbin3 add unique key(name2);
mysql> insert into testbin3 values('a ','a \0\0\0\0\0\0\0\0');
ERROR 1062 (23000): Duplicate entry 'a ' for key 'name2'
可以看到重復(fù)的行
關(guān)于MYSQL的CHAR和VARCHAR注意事項(xiàng)以及binary和varbinary存儲(chǔ)方式是怎樣的問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。
網(wǎng)站標(biāo)題:MYSQL的CHAR和VARCHAR注意事項(xiàng)以及binary和varbinary存儲(chǔ)方式是怎樣的
本文來源:http://www.rwnh.cn/article16/gsppdg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)公司、網(wǎng)頁設(shè)計(jì)公司、電子商務(wù)、自適應(yīng)網(wǎng)站、營銷型網(wǎng)站建設(shè)、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)