MySQL数据类型:UNSIGNED注意事项
1. UNSIGNED
UNSIGNED屬性就是將數字類型無符號化,與C、C++這些程序語言中的unsigned含義相同。例如,INT的類型范圍是-2 147 483 648 ~ 2 147 483 647, INT UNSIGNED的范圍類型就是0 ~ 4 294 967 295。
在MYSQL中整型范圍:
類型???????????????? 大小??????????? 范圍(有符號)???????????????????????????? ?范圍(無符號) 用途
TINYINT?????????? 1 字節??? (-128,127)?????????????????????????????????? ?(0,255) 小整數值
SMALLINT??????? 2 字節??? (-32 768,32 767)?????????????????????????? (0,65 535) 大整數值
MEDIUMINT???? 3 字節??? (-8 388 608,8 388 607)????????????????? (0,16 777 215) 大整數值
INT或INTEGER? 4 字節??? (-2 147 483 648,2 147 483 647)???? (0,4 294 967 295) 大整數值
源文檔 <http://www.cnblogs.com/bukudekong/archive/2011/06/27/2091590.html>
?
看起來這是一個不錯的屬性選項,特別是對于主鍵是自增長的類型,因為一般來說,用戶都希望主鍵是非負數。然而在實際使用中,UNSIGNED可能會帶來一些負面的影響,示例如下:
mysql> CREATE TABLE t ( a INT UNSIGNED, b INT UNSIGNED )
?
ENGINE=INNODB;
?
Query OK, 0 rows affected (0.06 sec)
?
mysql> INSERT INTO t SELECT 1,2;
?
Query OK, 1 row affected (0.00 sec)
?
Records: 1 Duplicates: 0 Warnings: 0
?
mysql> SELECT * FROM t\G;
?
*************************** 1. row ***************************
?
a: 1
?
b: 2
?
1 row in set (0.00 sec)
我們創建了一個表t,存儲引擎為InnoDB。表t上有兩個UNSIGNED的INT類型。輸入(1,2)這一行數據,目前看來都沒有問題,接著運行如下語句:
SELECT a - b FROM t
這時結果會是什么呢?會是-1嗎?答案是不確定的,可以是-1,也可以是一個很大的正值,還可能會報錯。在Mac操作系統中(windows中也會),MySQL數據庫提示如下錯誤:
mysql> SELECT a-b FROM t;
?
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(`test`.`t`.`a` - `test`.`t`.`b`)'
這個錯誤乍看起來非常奇怪,提示BIGINT UNSIGNED超出了范圍,但是我們采用的類型都是INT UNSIGNED啊!而在另一臺Linux操作系統中,運行的結果卻是:
mysql> SELECT a -b FROM t\G;
?
*************************** 1. row ***************************
?
a - b: 4294967295
?
1 row in set (0.00 sec)
在發生上述這個問題的時候,有開發人員跑來和筆者說,他發現了一個MySQL的Bug,MySQL怎么會這么“傻”呢?在聽完他的敘述之后,我寫了如下的代碼并告訴他,這不是MySQL的Bug,C語言同樣也會這么“傻”。
#include
?
int main(){
?
unsigned int a;
?
unsigned int b;
?
a = 1;
?
b = 2;
?
printf(a - b: %d\n,a-b);
?
printf(a - b: %u\n,a-b);
?
return 1;
?
}
上述代碼的運行結果是:
a - b: -1
?
a - b: 4294967295
可以看到,在C語言中a-b也可以返回一個非常巨大的整型數,這個值是INT UNSIGNED的最大值。難道C語言也發生了Bug?這怎么可能呢?
在實際的使用過程中,MySQL給開發人員的印象就是存在很多Bug,只要結果出乎預料或者有開發人員不能理解的情況發生時,他們往往把這歸咎于 MySQL的 Bug。和其他數據庫一樣,MySQL的確存在一些Bug,其實并不是MySQL數據庫的Bug比較多,去看一下Oracle RAC的Bug,那可能就更多了,它可是Oracle的一款旗艦產品。因此,不能簡單地認為這個問題是MySQL的Bug。
對于上述這個問題,正如上述所分析的,如果理解整型數在數據庫中的表示方法,那么這些就非常好理解了,這也是為什么之前強調需要看一些計算機組成原理方面相關書籍的原因。將上面的C程序做一些修改:
#include
?
int main(){
?
unsigned int a;
?
unsigned int b;
?
a = 1;
?
b = 2;
?
printf(a - b: %d,%x\n,a-b,a-b);
?
printf(a - b: %u,%x\n,a-b,a-b);
?
return 1;
?
}
這次不僅打印出a-b的結果,也打印出a-b的十六進制結果,運行程序后的結果如下所示:
a - b: -1,ffffffff
?
a - b: 4294967295,ffffffff
可以看到結果都是0xFFFFFFFF,只是0xFFFFFFFF可以代表兩種值:對于無符號的整型值,其是整型數的最大值,即4 294 967 295;對于有符號的整型數來說,第一位代表符號位,如果是1,表示是負數,這時應該是取反加1得到負數值,即-1。
這個問題的核心是,在MySQL數據庫中,對于UNSIGNED數的操作,其返回值都是UNSIGNED的。而正負數這個問題在《MySQL技術內幕:InnoDB存儲引擎》中有更深入的分析,有興趣的可以進一步研究。
那么,怎么獲得-1這個值呢?這并不是一件難事,只要對SQL_MODE這個參數進行設置即可,例如:
mysql>SET sql_mode='NO_UNSIGNED_SUBTRACTION';
?
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)
后面會對SQL_MODE進一步討論,這里不進行深入的討論。筆者個人的看法是盡量不要使用UNSIGNED,因為可能會帶來一些意想不到的效果。 另外,對于INT類型可能存放不了的數據,INT UNSIGNED同樣可能存放不了,與其如此,還不如在數據庫設計階段將INT類型提升為BIGINT類型。
?
以上文字摘自<http://tech.it168.com/a2012/0808/1382/000001382732.shtml>
本人遇到的類似問題:(linux上)
當(a-b)在where子句后時也會出現相同的情況
以下是php使用Mysql查詢的結果(每組的第一行是第二行[1]-[2]的結果)
86374
?????????????????????? a?????????????????????????????????????? b
Array (? [1] => 1351843032? [2] => 1351756658? )
?
-2567
Array ( [1] => 1351843032? [2] => 1351845599? )
?
86374
Array ([1] => 1351843032? [2] => 1351756658 )
?
86374
Array (? [1] => 1351843032? [2] => 1351756658? )
?
-105849
Array (? [1] => 1351650809? [2] => 1351756658 )
?
86374
Array (? [1] => 1351843032 [2] => 1351756658? )
?
86374
Array ( [1] => 1351843032? [2] => 1351756658? )
下面在mysql語句中查詢select * from table where (a-b)>86374;
結果(按正常思路來講,結果應該為空,但在Linux是卻現出以下結果 ):
Array ( [1] => 1351843032? [2] => 1351845599? )
Array ( [1] => 1351650809? [2] => 1351756658? )
而這個結果恰是[1]-[2]為負數的那兩行。
結論:如果使用unsigne并且在where子句后出現兩 列相減值小于0((a-b)<0),在查詢時,linux上的Mysql會將負數轉換成unsigned后再進行查詢( (-2576+4294967295+1)>86374,? (-105849+4294967295+1)>86374 )。
總結
以上是生活随笔為你收集整理的MySQL数据类型:UNSIGNED注意事项的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows mysql-64位 数据
- 下一篇: Jenkins自动化部署容器