我有一个非常缓慢而简单的查询,我正在努力改进,其目的是在第一次获得单位失败的日期,并且如下:
select unit_id, min(fail_Date) fail_Date
from failures
having min(fail_date) between '24-aug-2012' and '25-aug-2012'
group by unit_id
你可能猜测Unit_id不是唯一的,是识别失败单位的外键,在这个表中,如果多次失败,我有同一单位的多条记录。
我知道这不是最好的方法,但我无法控制表格,我必须按原样使用它们。
此表包含fail_date和unit_id的索引。
尽管如此,这个查询需要10秒钟,我想只是问,我怎样才能让它更快?但后来我以这种方式查询值,它只需要0.03秒:
with fail_dates as
(select unit_id, fail_date
from failures
where fail_date between '24-aug-2012' and '25-aug-2012')
select f.unit_id, min(f.fail_Date) fail_Date
from fail_dates
inner join failures f
on fail_dates.unit_id= f.unit_id
group by f.unit_id,fail_dates.fail_date
having min(f.fail_Date) = fail_dates.fail_date
它们都返回完全相同的记录,但第二个记录的速度提高了10倍, 现在我的问题是,这两个查询真的相同吗???为什么第二个更快?
谢谢你!答案 0 :(得分:3)
我的结论发生了变化,这个答案已经在很大程度上重写了。
起初我认为你的2个查询是不同的,但在阅读你的评论并重新检查第二个查询后,我意识到它确实会给出相同的结果。两个查询仅返回最早失败在2天范围内的单位。
您的第一个查询很慢,因为它在逻辑上必须查看每个单元的所有失败日期。它可能正在执行全表(或索引)扫描。
您的第二个查询要快得多,因为它只计算在目标日期范围内出现故障的单位的最小失败日期。我猜它是在前沿使用带有失败日期的索引来识别目标范围内出现故障的单元。然后,它可以在前沿使用带有单位ID的索引来查找相关单位的最小失败日期。
以下查询应该等同于您的查询,并且它有可能比第二个查询快一点,但我不会指望它。我说它可能会更快,因为这个查询可以在找到任何具有早期失败日期的记录时立即消除该单元,而您的第二个查询必须在逻辑上查看该单元的所有失败日期。只要这个查询不比你的第二个查询慢,我会选择这个,因为我认为逻辑更直接,更容易理解。
select unit_id,
min(fail_Date) fail_Date
from failures f
where fail_date between '24-aug-2012' and '25-aug-2012'
and not exists (
select 1
from failures f2
where f2.unit_id=f1.unit_id
and f2.fail_date < '24-aug-2012'
)
group by unit_id
答案 1 :(得分:2)
我认为如果将其重新编写为
,则可以改进原始查询select unit_id, min(fail_Date) fail_Date
from failures
where fail_date between '24-aug-2012' and '25-aug-2012'
group by unit_id
我希望这与第二次查询一样好。此查询和第二个查询运行得更快的原因是因为您首先通过仅选择那些在所需范围内具有FAIL_DATE的记录来对表进行子集 - 这可能允许使用索引。原始查询必须扫描整个表,因为没有WHERE子句来帮助它只选择感兴趣的记录。
您可能希望查看两个查询的EXPLAIN PLAN输出,以了解它们的评估方式。
分享并享受。
答案 2 :(得分:1)
如果不仔细观察它们,我会说它们在某种意义上是等效的,现在它们会返回相同的行。不要指望继续。
但是第二个版本中的公用表表达式(CTE)中有一个非常严格的WHERE子句,只选择行两天。限制性WHERE子句应该大大减少GROUP BY和HAVING必须完成的工作。
你应该能够通过查看execution plan(pdf,白皮书)来确定。