[英]Which sql statement is faster when counting nulls?
我需要进行查询以确定是否未填写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;
我认为你正在做一个预成熟的优化。
在表中添加额外的列会增加每条记录的大小。 这通常意味着表将占用磁盘上更多的空间。 大表大小意味着更长的全表扫描。
添加索引可能有帮助。 但是,与他们相关的成本。 如果索引有帮助,则无需添加其他列,因为Oracle支持功能索引。 因此,您可以索引表达式。
在大多数情况下,您的查询将执行全表扫描或完整索引扫描,除非某些条件很少。
换句话说,要真正回答你的问题,需要了解:
只有当性能让您没有其他选择时,才应该使用额外的冗余列。 在这种情况下,你应该避免它。 如果此语句的性能太差,只需在(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
如果WHERE子句中的列允许使用索引,那么很可能会更快。 但是,如果没有列被索引,那么我希望第一个查询更好。
但检查计划始终是最好的了解方式。
我会在not_available上创建索引,然后查询。
CREATE INDEX index_name
ON table_name (not_available)
这样的事情对你有帮助吗?
select count(NVL2(t.col1||t.col2||t.col3),NULL,1) FROM my_table t;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.