对于在WHERE子句中使用is null
和is 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))
如何避免全表扫描并使用索引来优化查询?
由于
答案 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_id
时a.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))
这不会影响性能,但会产生不同的结果集,符合代码的明显意图。