在给定某些其他标准的情况下,按日期检索单个最新记录的最有效方法是什么

时间:2013-12-29 17:32:17

标签: sql oracle query-optimization

如果一个表有一些字段作为其复合键,并且有一个日期,我需要找到匹配除日期之前的所有字段的记录。所有领域都有一个独特的索引。可能有1000多条记录在密钥上匹配,但我只需要紧接在日期之前的记录。

以前,系统每天都会插入一行,所以我们只能访问日期记录 - 1是直接查找。然而,这导致数据库呈指数级增长,无法继续(我们现在超过500M行,只需要~7万个)。

例如,这是当前查询的简化版本:

select
    i.quantity
from inventory i
where i.inventory_date = :inventory_date - 1
and   i.company_id = :company_id
and   i.client_id = :client_id
and   i.product_id = :product_id;

这就是我打算改变它的原因。不幸的是,上面的查询以线性时间运行(对唯一索引进行单行查找),而下面的代码在进行过滤之前占用每一行(对唯一索引进行范围扫描)。在现实世界中,我们谈论的是一秒钟而不是十秒钟。

select
    quantity,
    inventory_date
from (
    select
        i.quantity,
        i.inventory_date,
        max(i.inventory_date) over (partition by i.company_id, i.client_id, i.product_id) max_inv_date
    from inventory i
    where i.inventory_date < :inventory_date
    and   i.company_id = :company_id
    and   i.client_id = :client_id
    and   i.product_id = :product_id
)
where inventory_date = max_inv_date;

是否有更好(或至少表现更好)的方式来编写上述查询?

1 个答案:

答案 0 :(得分:3)

对于第一个查询:

select i.quantity
from inventory i
where i.inventory_date = :inventory_date - 1
and   i.company_id = :company_id
and   i.client_id = :client_id
and   i.product_id = :product_id;

最佳指数为inventory(company_id, client_id, product_id, inventory_date, quantity)。索引的前三个元素可以采用不同的顺序。并且,在日期之后可以添加其他列。为了使索引最有用,这三列必须是第一个。此查询不需要“线性”查找时间,也不需要。

要获取日期的最新值,请保持相同的索引并执行:

select i.*
from (select i.quantity
      from inventory i
      where i.company_id = :company_id and
            i.client_id = :client_id and
            i.product_id = :product_id and
            i.inventory_date < :inventory_date
      order by i.inventory_date desc
     ) i
where rownum = 1;