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()判斷。
相關文章
- MySQL中的NULL和空串比較MySqlNull
- 檢視oracle資料庫中,哪些表的欄位是null值比較多Oracle資料庫Null
- sql server中對日期欄位值的比較SQLServer
- MySQL 大欄位問題MySql
- mysql 查詢欄位為null或者非nullMySqlNull
- MySQL-去掉不為null的欄位MySqlNull
- MySQL中需要注意的欄位長度問題MySql
- Oracle dblink比較兩個庫中的表欄位Oracle
- 比較所有的欄位型別型別
- MySQL null值欄位是否使用索引的總結MySqlNull索引
- oracle分割槽表線上重定義欄位not null問題OracleNull
- MySQL資料庫中庫、表名、欄位的大小寫問題MySql資料庫
- MySQL把字串欄位轉換為日期型別進行比較MySql字串型別
- SQL中欄位比較型別不匹配錯誤:‘cannot be cast to’SQL型別AST
- mysql-欄位設定Default值問題MySql
- MYSQL timestamp NOT NULL插入NULL的報錯問題MySqlNull
- MySQL欄位究竟是否需要設定成not nullMySqlNull
- 在Struts中應用Validator進行兩個欄位的比較的方法。
- MySQL的主鍵和欄位型別問題總結MySql型別
- 同一張表的兩個欄位比較查詢
- sql中的安全問題nullSQLNull
- 關於oracle中blob欄位的錄入問題Oracle
- spring data mongo比較兩個欄位查詢SpringGo
- 【mysql--求解求2個或以上欄位為NULL 的記錄】MySqlNull
- 解決SQL Server中CHAR欄位空格問題SQLServer
- MySQL中JSON欄位的使用技巧MySqlJSON
- MySQL 中 JSON 欄位的使用技巧MySqlJSON
- Mysql中的Btree與Hash索引比較MySql索引
- 關於建表欄位是否該使用not null這個問題你怎麼看?Null
- 資料庫欄位問題資料庫
- 版本號比較大小問題
- Java 字串比較、拼接問題Java字串
- json轉化保留null欄位JSONNull
- Mybatis-Plus 更新欄位為 NULLMyBatisNull
- MySQL 中的 distinct 和 group by 的效能比較MySql
- 面試題:對NotNull欄位插入Null值 有啥現象?面試題Null
- php比較運算子的安全問題PHP
- sql 統計多個欄位的和(如果欄位中含有 null 的處理)SQLNull