Oracle 10g - 优化WHERE IS NOT NULL

时间:2009-04-06 13:58:18

标签: oracle optimization null

我们有Oracle 10g,我们需要查询1个表(没有连接)并过滤掉其中1个列为空的行。当我们这样做 - WHERE OurColumn不是NULL - 我们在一张非常大的桌子上得到一个全表扫描 - BAD BAD BAD。该列上有一个索引但在此实例中会被忽略。这有什么解决方案吗?

由于

9 个答案:

答案 0 :(得分:23)

优化器认为全表扫描会更好。

如果只有几个NULL行,则优化器是正确的。

如果您完全确定索引访问速度会更快(即,75%行的col1 IS NULL行数超过SELECT /*+ INDEX (t index_name_on_col1) */ * FROM mytable t WHERE col1 IS NOT NULL ),请提示您的查询:

75%

为什么INDEX SCAN

因为使用ROWID检索索引未涵盖的值意味着4上的隐藏联接,其成本约为表扫描的25%倍。

如果索引范围包含的行数超过Tony Andrews,则表扫描通常会更快。

25%所述,聚类因子是衡量此值的更准确方法,但{{1}}仍然是一个很好的经验法则。

答案 1 :(得分:16)

优化器将根据全表扫描的相对成本和使用索引做出决策。这主要归结为必须读取多少块以满足查询。在另一个答案中提到的25%/ 75%经验法则是简单的:在某些情况下,即使获得1%的行,全表扫描也是有意义的 - 即,如果这些行恰好分布在许多块周围。

例如,请考虑此表:

SQL> create table t1 as select object_id, object_name from all_objects;

Table created.
SQL> alter table t1 modify object_id null;

Table altered.

SQL> update t1 set object_id = null
  2  where mod(object_id,100) != 0
  3  /

84558 rows updated.

SQL> analyze table t1 compute statistics;

Table analyzed.

SQL> select count(*) from t1 where object_id is not null;

  COUNT(*)
----------
       861    

如您所见,T1中只有大约1%的行具有非null object_id。但是由于我建造桌子的方式,这些861行将在桌子周围或多或少地均匀分布。因此,查询:

select * from t1 where object_id is not null;
即使优化器使用了索引,

也可能访问T1中的几乎每个块来获取数据。那么有必要省去索引并进行全表扫描!

帮助识别这种情况的关键统计数据是索引聚类因子:

SQL> select clustering_factor from user_indexes where index_name='T1_IDX';

CLUSTERING_FACTOR
-----------------
              460

此值460非常高(与索引中的861行相比),并建议使用全表扫描。请参阅this DBAZine article on clustering factors

答案 2 :(得分:2)

如果您正在执行select *,那么执行表扫描而不是使用索引是有意义的。如果您知道自己感兴趣的列,则可以使用这些列加上应用IS NOT NULL条件的列来创建覆盖索引。

答案 3 :(得分:1)

它可能取决于您在桌面上的索引类型。

大多数B树索引存储空条目。位图索引执行存储空条目。

所以,如果你有:

  

从mytable中选择*   mycolumn为null

并且您在mycolumn上有一个标准的B树索引,然后查询不能使用索引,因为“null”不在索引中。

(如果索引针对多个列,并且其中一个索引列不为null,则索引中将有一个条目。)

答案 4 :(得分:0)

在该列上创建索引。

为了确保使用索引,它应该位于索引和where。

中的其他列

ocdecio回答:

  

如果您正在执行select *,那么执行表扫描而不是使用索引是有意义的。

这不是严格正确的;如果存在适合您的where子句的索引,则将使用索引,并且查询优化器决定使用该索引比执行表扫描更快。如果没有索引或没有合适的索引,则必须进行表扫描。

答案 5 :(得分:0)

还有必要检查Oracle的桌面统计数据是否是最新的。它可能不知道全表扫描会更慢。

答案 6 :(得分:0)

Oracle数据库根本不在常规(b-tree)索引中索引空值,因此它不能使用它,也不能强制oracle数据库使用它。

BR

答案 7 :(得分:0)

使用提示只能作为解决方法而不是解决方案。

正如其他答案中所提到的,空值在B-TREE索引中不可用。

由于您知道此列中大部分都是空值,因此您是否可以将空值替换为范围。

这实际上取决于您的列和数据的性质,但通常情况下,如果您的列是日期类型,例如:

where mydatecolumn is not null 可以在规则中翻译说:我想要所有有日期的行。

然后你绝对可以这样做: 其中mydatecolumn< = sysdate(在oracle中)

这将返回所有带有日期和ommit null值的行,同时利用该列上的索引而不使用任何提示。

答案 8 :(得分:-1)

请参阅http://www.oracloid.com/2006/05/using-index-for-is-null/

如果您的索引位于一个字段上,则不会使用它。尝试在索引中添加虚拟字段或常量:

create index tind on t(field_to_index, 1);