对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)=0then
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这个字段的原因。
版权声明:本文为博主原创文章,未经博主允许不得转载。