如果一个表有一些字段作为其复合键,并且有一个日期,我需要找到匹配除日期之前的所有字段的记录。所有领域都有一个独特的索引。可能有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;
是否有更好(或至少表现更好)的方式来编写上述查询?
答案 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;