開門見山直接說問題腔寡,前一段時(shí)候生產(chǎn)上進(jìn)行數(shù)據(jù)庫的變更绅项,導(dǎo)致了在短時(shí)間內(nèi)業(yè)務(wù)的異常曲尸,最后通過將CHAR類型修改為VARCHAR2類型后解決了該問題赋续。
一、問題背景
舉一個(gè)類似的例子另患,我們有一個(gè)學(xué)生表STUDNET纽乱,表結(jié)構(gòu)與數(shù)據(jù)如下,系統(tǒng)升級(jí)前只支持本科生的管理昆箕,系統(tǒng)升級(jí)后要添加研究生的管理功能鸦列,但是學(xué)號(hào)的位數(shù)不一致,所以由原來的CHAR(5)修改為CHAR(7)鹏倘,后面發(fā)現(xiàn)本科生管理功能不能正常時(shí)候薯嗤,后將CHAR(5)修改為VARCHAR2(7)后恢復(fù)使用。
表結(jié)構(gòu):
SQL> desc student;
Name Null? Type
----------------------------------------- -------- ----------------------------
STU_ID NOT NULL CHAR(7)
STU_NAME VARCHAR2(10)
STU_GENDER VARCHAR2(5)
數(shù)據(jù):
SQL> select * from student;
STU_ID STU_NAME STU_G
------- ---------- -----
1001 小明 男
1002 小剛 男
2001001 小米 女
2001002 小敏 女
二纤泵、問題干擾
對(duì)于CHAR和VARCHAR的數(shù)據(jù)類型的問題有一點(diǎn)數(shù)據(jù)庫基礎(chǔ)的同學(xué)應(yīng)該都知道骆姐,CHAR是定長(zhǎng),VARCHAR是變長(zhǎng)捏题,但是在問題的分析上我們受到了一些表面現(xiàn)象的干擾诲锹,通過PLSQL或者SQLPLUS對(duì)如下語句進(jìn)行查詢,發(fā)現(xiàn)無論條件是1001還是1001_都可以查詢到數(shù)據(jù)涉馅,這也會(huì)給經(jīng)驗(yàn)不足的開發(fā)人員一定的干擾归园,理所當(dāng)然的認(rèn)為程序去跑該SQL也沒有問題,但是后面我們發(fā)現(xiàn)業(yè)務(wù)通過Mybatis執(zhí)行該SQL沒有查詢到對(duì)應(yīng)的數(shù)據(jù)稚矿。
SQL> select * from student where stu_id='1001';
STU_ID STU_NAME STU_G
------- ---------- -----
1001 小明 男
SQL> select * from student where stu_id='1001 ';
STU_ID STU_NAME STU_G
------- ---------- -----
1001 小明 男
三庸诱、問題解決
1.我們知道CHAR類型是定長(zhǎng),如果長(zhǎng)度不足該字段定義的長(zhǎng)度晤揣,那會(huì)自動(dòng)在后面補(bǔ)足空格桥爽,在PLSQL或者SQLPLUS中對(duì)CHAR類型列進(jìn)行查詢時(shí),會(huì)自動(dòng)補(bǔ)齊查詢條件中的空格(換一種說法也可以理解為查詢的值和被查詢的值都進(jìn)行了末端去空格處理)昧识。
2.但是在程序去操作數(shù)據(jù)庫時(shí)钠四,如使用Mybatis或Hibernate去查詢數(shù)據(jù)時(shí)就不會(huì)做一些額外的操作,所以執(zhí)行下列語句時(shí)會(huì)查不到對(duì)應(yīng)的數(shù)據(jù)跪楞,原因是1000與1001___不相等缀去。
select * from student where stu_id='1001';
3.那解決這個(gè)問題的思路有兩個(gè),一個(gè)是按照如下方式改寫SQL甸祭,將CHAR類型的列中后面的空格去掉缕碎,另一種方案是將CHAR類型改為VARCHAR2類型,我個(gè)人推薦第二種池户。
SQL> select * from student where trim(stu_id)='1001';
STU_ID STU_NAME STU_G
------- ---------- -----
1001 小明 男
四咏雌、學(xué)習(xí)知識(shí)
1.CHAR與VARCHAR的比較
- 首先凡怎,CHAR為定長(zhǎng),VARCHAR為變長(zhǎng)赊抖,在空間上VARCHAR會(huì)比較節(jié)省空間统倒。其次,在查詢效率上氛雪,CHAR會(huì)比VARVHAR快一些房匆,因?yàn)樘幚鞻ARVHAR類型還會(huì)有一些額外的操作。
- 我看還有一種說法是說如果VARCHAR類型的列存儲(chǔ)的內(nèi)容長(zhǎng)度經(jīng)常改變會(huì)發(fā)生“行遷移”的現(xiàn)象注暗,所以會(huì)導(dǎo)致VARCHAR效率比較慢坛缕,這種說法我不是很同意,因?yàn)榧词勾嬖贑HAR類型的列的內(nèi)容長(zhǎng)度不變捆昏,如果該行其他的列的長(zhǎng)度經(jīng)常更改也會(huì)造成“行遷移”赚楚。
2.VARCHAR與VARCHAR2的比較
目前在ORACLE中VARCHAR是VARCHAR2的同義詞。標(biāo)準(zhǔn)的VARCHAR類型可以存儲(chǔ)空字符串骗卜,ORACLE自己設(shè)計(jì)了一個(gè)VARCHAR2的數(shù)據(jù)類型宠页,它將存儲(chǔ)空字符串的特性改為存儲(chǔ)NULL值。