计算空值时哪个sql语句更快?

时间:2014-01-24 15:46:31

标签: sql oracle

我需要进行查询以确定是否未填写3列。我应该在表中创建一个列作为标志,注意3列是空的吗?我的直觉告诉我,我不应该制作一个额外的专栏。我只是想知道我是否会因此而获得任何性能提升。这是为oracle服务器。

select count(*) from my_table t where t.not_available = 1;

select count(*) from my_table t where t.col1 is null and t.col2 is null and t.col3 is null;

6 个答案:

答案 0 :(得分:1)

我认为你正在做一个预成熟的优化。

在表中添加额外的列会增加每条记录的大小。这通常意味着表将占用磁盘上更多的空间。大表大小意味着更长的全表扫描。

添加索引可能有所帮助。但是,与他们相关的成本。如果索引有帮助,则无需添加其他列,因为Oracle支持功能索引。因此,您可以索引表达式。

在大多数情况下,您的查询将执行全表扫描或完整索引扫描,除非某些条件很少。

换句话说,要真正回答你的问题,需要理解:

  • 记录布局
  • 三列中值的分布
  • 可能影响访问的任何其他因素,例如分区列

答案 1 :(得分:1)

只有当性能让您没有其他选择时,才应该使用额外的冗余列。在这种情况下,你应该避免它。如果这个陈述的表现太差,只需在(col1,col2,col3,1)上引入一个索引。

这是一个为什么在索引中放入第4个常量值1可能是一个好主意的例子。

首先是一个包含1000行的表,其中只有1行(456)的所有三列都为NULL:

SQL> create table my_table (id,col1,col2,col3,fill)
  2  as
  3   select level
  4        , nullif(level,456)
  5        , nullif(level,456)
  6        , nullif(level,456)
  7        , rpad('*',100,'*')
  8     from dual
  9  connect by level <= 1000
 10  /

Table created.

下面的索引没有对包含三个NULLS的行编制索引:

SQL> create index my_table_i1 on my_table(col1,col2,col3)
  2  /

Index created.

并将在我的测试用例中使用全表扫描(可能是您的主键索引的完整索引扫描)

SQL> exec dbms_stats.gather_table_stats(user,'my_table')

PL/SQL procedure successfully completed.

SQL> set autotrace on
SQL> select count(*) from my_table t where t.col1 is null and t.col2 is null and t.col3 is null
  2  /

  COUNT(*)
----------
         1

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 228900979

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

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

   2 - filter("T"."COL1" IS NULL AND "T"."COL2" IS NULL AND "T"."COL3"
              IS NULL)


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
         37  consistent gets
          0  physical reads
          0  redo size
        236  bytes sent via SQL*Net to client
        247  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

但是如果我在索引中添加常量1:

SQL> set autotrace off
SQL> drop index my_table_i1
  2  /

Index dropped.

SQL> create index my_table_i2 on my_table(col1,col2,col3,1)
  2  /

Index created.

SQL> exec dbms_stats.gather_table_stats(user,'my_table')

PL/SQL procedure successfully completed.

然后它会使用索引,你的语句将会飞

SQL> set autotrace on
SQL> select count(*) from my_table t where t.col1 is null and t.col2 is null and t.col3 is null
  2  /

  COUNT(*)
----------
         1

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 623815834

---------------------------------------------------------------------------------
| Id  | Operation         | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |             |     1 |    12 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |             |     1 |    12 |            |          |
|*  2 |   INDEX RANGE SCAN| MY_TABLE_I2 |     1 |    12 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------

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

   2 - access("T"."COL1" IS NULL AND "T"."COL2" IS NULL AND "T"."COL3"
              IS NULL)
       filter("T"."COL2" IS NULL AND "T"."COL3" IS NULL)


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          2  consistent gets
          0  physical reads
          0  redo size
        236  bytes sent via SQL*Net to client
        247  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

答案 2 :(得分:0)

SQL执行速度取决于您未在问题中列出的众多因素。

因此,我认为您应该检查特定服务器上的执行计划,以获得两种情况的第一手基准。

参见例如here有关如何在Oracle上显示执行计划的信息..

答案 3 :(得分:0)

如果WHERE子句中的列允许使用索引,那么很可能会更快。但是,如果没有列被索引,那么我希望第一个查询更好。

但检查计划始终是最好的了解方法。

答案 4 :(得分:0)

我会在not_available上创建索引,然后查询。

CREATE INDEX index_name
ON table_name (not_available)

答案 5 :(得分:0)

这样的事情对你有帮助吗?

select count(NVL2(t.col1||t.col2||t.col3),NULL,1) FROM my_table t;
相关问题