【发布时间】:2014-06-30 10:56:36
【问题描述】:
我有一个像这样工作的 oracle 查询:
SELECT *
FROM VW_REQUIRED r
JOIN VW_ACTUAL a ON a.person_id = r.person_id AND a.target_id = r.target_id
必需是详细说明所有必需培训材料的视图,实际是详细说明给定课程最近学习的视图。这些查询中的每一个都需要不到 2 秒的时间来生成 10k 到 100k 行。
我想做的是这样的:
SELECT *
FROM VW_REQUIRED r
WHERE NOT EXISTS ( SELECT 1 FROM VW_ACTUAL a WHERE a.person_id = r.person_id AND a.target_id = r.target_id)
而且需要超过 20 秒(我没有让它完成,因为那显然太长了。
所以我决定做一些不同的事情,我将原始的 JOIN 设置为左连接,这样它就会向我显示所有必需的培训,并且只有存在时才会显示实际的培训。
这行得通,而且速度仍然非常快。
但我想要一份没有实际培训的课程列表(即我们需要开始工作并接受培训的人......)
当我尝试像
SELECT *
FROM VW_REQUIRED r
LEFT JOIN VW_ACTUAL a ON a.person_id = r.person_id AND a.target_id = r.target_id
WHERE r.person_id = null
我没有返回任何行。我不确定是否可以过滤掉没有实际结果的行。通常我会使用WHERE NOT EXISTS,但它的性能非常慢(而且我认为我不能在视图上放置索引......)
我已经设法进行了一些可行的更改,但它看起来很老套,我确信有更好的解决方案。
SELECT
who, where_from, mand, target_id, grace_period, date_taken
FROM (
SELECT
r.person_id who,
r.where_from where_from,
r.mand mand,
r.target_id target_id
r.grace_period grace_period,
nvl(a.date_taken, to_date('1980/01/01','yyyy/mm/dd')) date_taken
FROM VW_REQUIRED r
LEFT JOIN VW_ACTUAL a ON a.person_id = r.person_id AND a.target_id = r.target_id
)
WHERE date_taken = to_date('1980/01/01','yyyy/mm/dd')
【问题讨论】:
-
这是一个可怕的黑客攻击。 @LajosVerdes 提供的解决方案更干净,甚至应该更快。您是否 100% 确定您尝试过他提出的查询(将
r.person_id替换为a.person_id并使用IS NULL而不是= NULL)?
标签: sql oracle optimization not-exists