SQL中的null,SQLnull

來源:互聯網
上載者:User

SQL中的null,SQLnull

對Oracle SQL中的null小結如下:

1.1       null

Ø null 值計算的結果仍是null

Ø null 是一個未分配的、未知的,或不適用的值

Ø null不是0,也不是空格

 

1.1.1       null值的運算

null參數的算術運算式的結果仍然為null

SQL>  select '*'||1/null||'*' res1,'*'||1*null||'*' res2, '*'||(1-null)||'*' res3 from dual;

RE RE RE

-- -- --

** ** **

SQL>select null/0 from dual;

    NULL/0

----------

SQL>select 1/0 from dual;

select1/0 from dual

        *

ERROR atline 1:

ORA-01476:divisor is equal to zero

模數

SQL>select  '*'||mod(9,null)||'*' res fromdual;

RE

--

**

 從NULL/0沒有報錯的情況,我們可以推測出,Oracle發現算術運算式中有null時,並沒有真正地計算該運算式,而是直接返回了null。

SQL>select 1 from dual where null!=null;

no rowsselected

SQL>select 1 from dual where null = null;

no rowsselected

SQL>select 1 from dual;

                 1

----------

                 1

不管是null!=null 還是null=null計算的結果都為false(實際上是返回了null, null在邏輯中表現為false),可見,不管是算術運算還是邏輯運算,只要null參與,結果就是null

1.1.2       null值與字串串連

null與字元型欄位串連時,表現為什麼都沒有"",相當於零個字元

 SQL>select '*'||null||'*' from dual;

'*

--

**

注意: 如果在實驗時出現中文亂碼,請確認資料庫服務nls_database_parameters,伺服器echo $NLS_LANG/ set NLS_LANG,以及用戶端v$nls_parameters的編碼設定是否一致。

1.1.3       null的查詢方式

SQL> select * from emp where comm is null;

其他的查詢方式會先過濾過列的null值所在行的記錄,即null不參與is null /is not null之外的查詢

 

SQL>select count(*) from emp;

  COUNT(*)

----------

                14

SQL>select count(*) from emp where comm<=500;

  COUNT(*)

----------

                 3

SQL>select count(*) from emp where comm>500;

  COUNT(*)

----------

                 1

 

1.1.4       null所在列的排序

在order by 排序中,null值最大

SQL>select ename, comm from emp order by comm;

 

TURNER                                    0

ALLEN                      300

WARD                      500

MARTIN                                1400

SCOTT

KING

ADAMS

JAMES

FORD

MILLER

BLAKE

JONES

SMITH

 

CLARK

14 rowsselected.

1.1.5       is null不走索引

在SQL的最佳化中有時會遇到SQL語句有索引也應該走索引,但最終卻沒有走索引的情況,這裡的is null就是其中的一種情況。

create table n1(sid integer,sname varchar2(120));

插入1W條記錄,第1W條的sname值為null

begin

  for i in 1..9999 loop

    insert into n1 values(i,'name'||i);

    if mod(i,100)=0 then

      commit;

    end if;

  end loop;

  insert into n1(sid) values(10000);

  commit;

end;

查詢sname列值走的是索引範圍掃描

SQL> explain plan for select * from n1 where sname = 'name1';Explained.SQL> select * from table(dbms_xplan.display);Plan hash value: 3644017351--------------------------------------------------------------------------------| Id  | Operation | Name | Rows| Bytes | Cost (%CPU)| Time|--------------------------------------------------------------------------------|   0 | SELECT STATEMENT ||     1 |    75 |     2   (0)| 00:00:01||*  1 |  INDEX RANGE SCAN| N1_SNAME_IND |     1 |    75 |     2   (0)| 00:00:01|--------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------   1 - access("SNAME"='name1')Note-----   - dynamic sampling used for this statement (level=2)


is null方式查詢,雖然sname中為null的記錄1W行中只有一行,但還是沒有走索引,也就是說is null不走索引。

SQL> explain plan for select * from n1 where sname is null;Explained.SQL> select * from table(dbms_xplan.display);Plan hash value: 2416923229--------------------------------------------------------------------------| Id  | Operation  | Name | Rows  | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------|   0 | SELECT STATEMENT  | |     1 |    75 |     9   (0)| 00:00:01 ||*  1 |  TABLE ACCESS FULL| N1 |     1 |    75 |     9   (0)| 00:00:01 |--------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------   1 - filter("SNAME" IS NULL)Note-----   - dynamic sampling used for this statement (level=2)17 rows selected.


如果實際情況確實需要is null查詢走索引呢?可通過建立聯合索引的方式來實現。

drop index n1_sname ;

create index n1_sname_ind on n1(sname,sid);

 

SQL> explain plan for select * from n1 where  sid is not null and sname is null ;

SQL> select * from table(dbms_xplan.display);Plan hash value: 3644017351-------------------------------------------------------------------------------| Id  | Operation | Name | Rows| Bytes | Cost (%CPU)| Time|-------------------------------------------------------------------------------|   0 | SELECT STATEMENT ||     1 |    75 |     3   (0)| 00:00:01||*  1 |  INDEX RANGE SCAN| N1_SNAME_IND |     1 |    75 |     3   (0)| 00:00:01|-------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------   1 - access("SNAME" IS NULL)       filter("SID" IS NOT NULL)Note-----   - dynamic sampling used for this statement (level=2)18 rows selected.

可以看到建立聯合索引後,SQL查詢所耗費的資源明顯降低。

需要注意的是我們查詢最頻繁最經常使用列,比如sname要放在聯合索引的第一列;同時要走聯合索引,需要where後面的條件出現聯合索引包含的所有的欄位,這也是為什麼加了sid這個欄位的原因。




 

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.