我使用两种不同的方法来检查数据库字段column_b
是否不是NULL
。哪个更快,为什么?
第一次查询
SELECT * FROM my_table
WHERE column_b IS NOT NULL;
第二次查询
SELECT * FROM my_table
WHERE column_b = column_b;
column_b
上没有索引。
答案 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)
如果您使用的是对象,它们并不总是一样:
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)