MySQL中NULL欄位的比較問題
最近有人問我MySQL中一個欄位不論=NULL還是<>NULL都匹配不了資料,是在框架層實現的還是在儲存引擎層實現的,我說你看看如果InnoDB表和MyISAM表都有這個現象,那就比較可能是在框架層。
當然這個答案跟沒有回答一樣,我們可以從程式碼上看看具體的實現部分。
1、 現象描述
表結構
CREATE TABLE `t` ( `c` char(32) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=gbk |
插入兩行資料
insert into t (c) values(`a`),(null); |
查詢
mysql> select * from t where c=null; Empty set (0.00 sec)
mysql> select * from t where c<>null; Empty set (0.00 sec)
mysql> select * from t where c is not null; +——+ | c | +——+ | a | +——+ 1 row in set (0.00 sec) |
說明:從上面的三個查詢可以看出,使用=null和<>null都無法返回資料,只能通過is或is not 來比較。
2、程式碼相關
我們知道大概的流程,是引擎返回索引過濾後的結果,在框架層再依次判斷記錄是否符合條件。判斷條件是否滿足是在函式evaluate_join_record (sql_select.cc)中。
if (select_cond)
{
select_cond_result= test(select_cond->val_int()); /* check for errors evaluating the condition */
if (join->thd->is_error())
return NESTED_LOOP_ERROR;
}
if (!select_cond || select_cond_result)
{ ... }
第三行的select_cond->val_int(),就是判斷where的條件是否相同。其中select_cond的型別Item是一個虛類。我們從val_int()的函式註釋中看到這樣一句話“In case of NULL value return 0 and set null_value flag to TRUE.”,確認了這個是在框架層作的,而且是有意為之。
一路追查到這個函式int Arg_comparator::compare_string (sql/item_cmpfunc.cc),這個函式是用語判斷兩個字串是否相同。
int Arg_comparator::compare_string() { String *res1,*res2; if ((res1= (*a)->val_str(&value1))) { if ((res2= (*b)->val_str(&value2))) { if (set_null) owner->nullvalue= 0; return sortcmp(res1,res2,cmp_collation.collation); } } if (set_null) owner->nullvalue= 1; return -1; }
|
函式返回值為0時表示相同,否則不同。
其中a是左值,b是右值。即如果輸入的是 where ‘i’=c, 則a的值是’i’。從第4行和第6行的兩個if看到,當a和b中有一個是null的時候,不進入sortcmp,而是直接return -1。
3、驗證修改
宣告:這個只是為了驗證結論修改,純屬練手,實際上現有的策略並沒有問題。
int Arg_comparator::compare_string()
{
String *res1,*res2;
res1= (*a)->val_str(&value1);
res2= (*b)->val_str(&value1);
if (!res1 && !res2)
{
return 0;
}
else if ((!res1 && res2) || (res1 && !res2))
{
return 1;
}
else
{
return sortcmp(res1,res2,cmp_collation.collation);
}
}
重新編譯後執行效果如下
mysql> select * from t where c=null; +————–+ | c | +————–+ | NULL | +————–+ 1 row in set (0.00 sec)
mysql> select * from t where c<>null; +————–+ | c | +————–+ | a | +————–+ 1 row in set (0.00 sec)
|
記得改回去。。。 ^_^
4、相關說明
a) Arg_comparator::compare_string() 這個函式只用於定義兩個char[]的判斷規則,因此修改後的執行程式中,非字串欄位判斷仍為原來的規則,即=null和<>null都認為不匹配。
b) 標準判斷是否為null的用法是 where c is null和is not null。此時使用的判斷函式為Item_func_isnull::val_int()和Item_func_isnotnull::val_int() , 這兩個函式比較簡單,直接用args[0]->is_null()判斷。
相關文章
- 檢視oracle資料庫中,哪些表的欄位是null值比較多Oracle資料庫Null
- MySQL 大欄位問題MySql
- MySQL-去掉不為null的欄位MySqlNull
- MySQL null值欄位是否使用索引的總結MySqlNull索引
- MYSQL timestamp NOT NULL插入NULL的報錯問題MySqlNull
- MySQL把字串欄位轉換為日期型別進行比較MySql字串型別
- SQL中欄位比較型別不匹配錯誤:‘cannot be cast to’SQL型別AST
- MySQL欄位究竟是否需要設定成not nullMySqlNull
- NSDate 時間比較中的時區問題.
- 同一張表的兩個欄位比較查詢
- json轉化保留null欄位JSONNull
- MySQL 中 JSON 欄位的使用技巧MySqlJSON
- MySQL中JSON欄位的使用技巧MySqlJSON
- [20231020]增加欄位的問題.txt
- Mysql中的Datetime和Timestamp比較MySql
- 關於建表欄位是否該使用not null這個問題你怎麼看?Null
- Mybatis-Plus 更新欄位為 NULLMyBatisNull
- sql 統計多個欄位的和(如果欄位中含有 null 的處理)SQLNull
- 版本號比較大小問題
- Java 字串比較、拼接問題Java字串
- Mysql中的Btree與Hash索引比較MySql索引
- php比較運算子的安全問題PHP
- MySQL 中的 distinct 和 group by 的效能比較MySql
- 面試題:對NotNull欄位插入Null值 有啥現象?面試題Null
- mysql 求分組中位數、環比、同比、中位數的環比、同比MySql
- [20210208]lob欄位與查詢的問題.txt
- 記錄一次因 mysql 欄位取名不規範導致的問題MySql
- MySql 查詢某一天日期格式欄位走索引問題MySql索引
- MySQL中IS NULL、IS NOT NULL、!=不能用索引?胡扯!MySqlNull索引
- MySQL欄位的取值範圍MySql
- PostgreSQL與MySQL的比較 - hackrMySql
- 使用perl比較mysql的版本MySql
- MySQL 欄位約束MySql
- 前端:說說工作中解決過的印象比較深刻的問題前端
- MySQL欄位新增註釋,但不改變欄位的型別MySql型別
- 為什麼資料庫欄位要使用NOT NULL?資料庫Null
- MySQL中TEXT與BLOB欄位型別的區別MySql型別
- resultMap 和 resultType 的欄位對映覆蓋問題
- 巧用 Base62 解決欄位太短的問題