我需要进行查询以确定是否未填写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;
答案 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)
答案 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;