Oracle 11g - 优化WHERE IS NOT NULL和IS NULL

时间:2017-04-12 06:47:52

标签: database oracle optimization oracle11g null

对于在WHERE子句中使用is nullis not null的语句,我有一个关于查询优化的问题。

例如,我有以下查询:

select name, firstname, adresse1, adresse2, town
from users u, adresses a
where u.user_id = a.user_id
and ((a.user_id is null)
or a.user_id is not null and a.adresse_type = 1))

如何避免全表扫描并使用索引来优化查询?

由于

4 个答案:

答案 0 :(得分:0)

您可以像这样简化where子句。你当前的where子句在没有大括号的情况下看起来很模糊。

我假设你想要所有用户id为null的记录。如果Userid不为null,则需要adresse_type为1的记录。

select name, firstname, adresse1, adresse2, town
from users u
inner join
adresses a
on u.user_id = a.user_id
and not (
    a.user_id is not null 
and a.adresse_type <> 1)

答案 1 :(得分:0)

不确定你能不能保持原样 首先,这没有找到任何东西 where u.user_id = a.user_ida.user_id is null 使while的其余部分与那些无关。

Oracle不会对NULL列进行索引,因此除了表扫描之外,user_id is null不能满足任何其他方式。您可以在user_id上构建一个计算列,其中包含NULL的一些标记值,并在其上构建索引,或者只构建一个基于函数的索引,该索引执行相同操作(将null替换为其他值)。

答案 2 :(得分:0)

我不确定你的查询是否正确,但仍然是问题,据我所知你可以在索引中使用null值,但是你必须在索引中添加另一个列/值,这个列/值不应该是NULL。例如,您可以尝试

create index addresses_idx01 on addresses (user_id, 1); 

那就是说,我认为你的问题不太明确,索引也不相关(假设user_id在两个表中都不能为NULL)。 据我所知,您的查询应该等同于:

SELECT NAME, FIRSTNAME, ADRESSE1, ADRESSE2, TOWN
FROM USERS U
INNER JOIN ADRESSES A ON U.USER_ID = A.USER_ID
WHERE  /* A.USER_ID IS NULL
        OR A.USER_ID IS NOT NULL AND */ A.ADRESSE_TYPE = 1

我认为/ *和* /之间的部分应该没用。

也许你想写:

SELECT NAME, FIRSTNAME, ADRESSE1, ADRESSE2, TOWN
FROM USERS U
LEFT JOIN ADRESSES A ON U.USER_ID = A.USER_ID
WHERE  A.USER_ID IS NULL
        OR /*A.USER_ID IS NOT NULL AND */ A.ADRESSE_TYPE = 1

同样,/ *和* /之间的部分应该没用。

答案 3 :(得分:-1)

  

“如何避免全表扫描并使用索引优化查询?”

USERS表上没有过滤器,因此全表扫描是该表的唯一访问路径。

您在a.user_id = u.user_id上有一个内部联接到ADRESSES表,因此a.user_id is null在此查询中永远不会成为现实。因此,问题变成是否值得使用索引来获得此连接?除非你有比用户更多的地址(比如说多20倍),否则没有。 ADRESSES上的全表扫描和散列连接可能是最好的路径。

如果您确实拥有多种广告,那么您可以从adresses(user_id, adresse_type)上的索引中获取值。在构建这样的索引之前,您应该确保经常运行查询以证明维护索引的开销。

但这一切都在猜测。性能调优是指标的问题,在不了解有关数据量和偏差的相关指标的情况下,建议优化是没有意义的。

关键是,全表扫描通常是访问数据集的最有效方式。使用索引不一定是优化。

最后,也许您应该在查询中使用OUTER JOIN:

select u.name, u.firstname, a.adresse1, a.adresse2, a.town
from users u
     left join adresses a
on u.user_id = a.user_id
where (a.user_id is null
      or (a.user_id is not null and a.adresse_type = 1))

这不会影响性能,但会产生不同的结果集,符合代码的明显意图。