测试NULL字段的最快方法(空值检测)

时间:2017-09-22 14:05:11

标签: sql oracle null

我使用两种不同的方法来检查数据库字段column_b是否不是NULL。哪个更快,为什么?

第一次查询

SELECT * FROM my_table
WHERE column_b IS NOT NULL;

第二次查询

SELECT * FROM my_table
WHERE column_b = column_b;

column_b上没有索引。

2 个答案:

答案 0 :(得分:12)

对于标准的标量数据类型,它们在Oracle上都是相同的(我尝试过12c和11g),因为你获得了相同的执行计划的两倍。 (see MT0's answer for an edge case when this isn't true

证明:

CREATE TABLE my_table (columnb NUMBER);

EXPLAIN PLAN FOR
SELECT *
FROM my_table
WHERE columnb IS NOT NULL;

SELECT *
FROM TABLE (dbms_xplan.display);

EXPLAIN PLAN FOR
SELECT *
FROM my_table
WHERE columnb = columnb;

SELECT *
FROM TABLE (dbms_xplan.display);

在这两种情况下,我都会:

Plan hash value: 3804444429

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          |     1 |    13 |     2   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| MY_TABLE |     1 |    13 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("COLUMNB" IS NOT NULL)

现在,即使您确实添加了索引....

CREATE INDEX my_index ON my_table (columnb);

...您仍然可以为两个查询获得相同的计划:

Plan hash value: 887433238

-----------------------------------------------------------------------------
| Id  | Operation        | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT |          |     1 |    13 |     1   (0)| 00:00:01 |
|*  1 |  INDEX FULL SCAN | MY_INDEX |     1 |    13 |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("COLUMNB" IS NOT NULL)

如果列为NOT NULL

,该怎么办?

我们试试这个:

DROP INDEX my_index; -- Get back to the initial situation
ALTER TABLE my_table MODIFY columnb NUMBER NOT NULL;

我现在得到的计划就是这些,在两种情况下,整个谓词都已被删除:

Plan hash value: 3804444429

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          |     1 |    13 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| MY_TABLE |     1 |    13 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------

结论

由于你没有从“聪明”的方法中获得任何好处,所以根本不要这样做,并将IS NOT NULL谓词写得更清楚。

顺便说一下,这是一个非常有趣的问题和优化类型I've blogged about it and about similar optimisations more in depth here

答案 1 :(得分:2)

如果您使用的是对象,它们并不总是一样:

SQL Fiddle

Oracle 11g R2架构设置

CREATE TYPE coord AS OBJECT (
  x NUMBER,
  y NUMBER,
  ORDER MEMBER FUNCTION match (l coord) RETURN INTEGER
);
/
CREATE TYPE BODY coord AS 
  ORDER MEMBER FUNCTION match (l coord) RETURN INTEGER IS 
  BEGIN 
    RETURN ( x   * 100 + y )
         - ( l.x * 100 + l.y);
  END;
END;
/

CREATE TABLE table_name ( col1, col2 ) AS
  SELECT 1, coord( 2, 3 ) FROM DUAL UNION ALL
  SELECT 2, coord( 0, 2 ) FROM DUAL UNION ALL
  SELECT 3, coord( NULL, 2 ) FROM DUAL UNION ALL
  SELECT 4, NULL FROM DUAL
/

查询1

SELECT *
FROM   table_name
WHERE  col2 IS NOT NULL

<强> Results

| COL1 |                       COL2 |
|------|----------------------------|
|    1 | oracle.sql.STRUCT@10394576 |
|    2 | oracle.sql.STRUCT@11ddf9d5 |
|    3 | oracle.sql.STRUCT@595e9c7d |

解释计划

 Plan Hash Value  : 3383972830 

---------------------------------------------------------------------------
| Id  | Operation           | Name       | Rows | Bytes | Cost | Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |            |    3 |   123 |    3 | 00:00:01 |
| * 1 |   TABLE ACCESS FULL | TABLE_NAME |    3 |   123 |    3 | 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 1 - filter(SYS_OP_NOEXPAND("COL2") IS NOT NULL)

查询2

SELECT *
FROM   table_name
WHERE  col2 = col2

<强> Results

| COL1 |                       COL2 |
|------|----------------------------|
|    1 | oracle.sql.STRUCT@35c56f09 |
|    2 | oracle.sql.STRUCT@1f0e893f |

解释计划

 Plan Hash Value  : 3383972830 

---------------------------------------------------------------------------
| Id  | Operation           | Name       | Rows | Bytes | Cost | Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |            |    1 |    41 |    3 | 00:00:01 |
| * 1 |   TABLE ACCESS FULL | TABLE_NAME |    1 |    41 |    3 | 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 1 - filter("COORD"."MATCH"("COL2","COL2")=0)