0

在下图中,您可以看到我正在尝试做的简化版本。我必须跟踪某些项目的位置,但我还必须有效地检索任何给定项目的最新位置。执行此操作的最简单方法是查询 ItemLocationLog 并搜索该项目的最新日期,但由于该表一定非常大,我想知道这是否有效(我猜索引 dateTime 字段会有所帮助,但我没有经验来确定多少)。

我想到的另一种方法是为 Item 上的日志表添加一个外键(如图所示,字段“lastLocation”),它始终指向最新的日志条目,因此可以省去搜索. 另一种选择是将外键添加到 Item 上的 Location 并在每次为任何给定项目添加日志条目时更新它。

我确信这是一个简单解决方案的常见问题,但由于我没有这方面的经验,我对自己的方法持怀疑态度。此类场景的最佳实践是什么?是否可以添加对 Item 表的引用以避免昂贵的查询,或者查询是否足够微不足道,我应该只从日志表本身获取这些信息?

数据库模型

4

3 回答 3

4

原则上,如果您已经测量了性能,确定了实际瓶颈并得出非规范化实际上会有所帮助的结论(足以抵消数据损坏的风险),则仅在模型中包含冗余。

奇怪的是,它不会在你的情况下。B-Tree 索引如何工作的一个特点是搜索 MAX 基本上与搜索精确值一样快。如果 INT 小于 DBMS 上的 DATETIME,您可能会从更好的缓存中获得一点提升,但不会太多。

如果操作正确,索引功能非常强大。并且索引ItemLocationLog {idItem, dateTime}应该便于闪电般快速SELECT MAX(dateTime) FROM ItemLocationLog WHERE idItem = ?

看看使用索引,卢克!有关该主题的精彩介绍。

于 2012-05-09T20:07:52.123 回答
1

不要针对您不知道自己遇到的问题进行预优化。

ItemLocationLog从覆盖表的索引开始idItem。然后SELECT TOP 1 idItemLocationLog from ItemLocationLog order by idItemLocationLog DESC- 假设您的 PK 是一个自动增量列。 如果这还不够快,请尝试使用idItemplus上的索引dateTime。如果这仍然不够快,那么您可以开始考虑剧烈的非规范化,例如将最后一个已知的位置参考保持在Item.

有些人对 RDBMS 在检索数据方面的出色表现感到非常惊讶。你不应该!

于 2012-05-09T19:48:44.090 回答
1

先试试这个(示例用于 PostgeSQL)。

在此处输入图像描述

-- Latest location of ItemID = 75
select
      a.ItemID
    , b.LocationID
    , ValidFrom
from Item         as a
join ItemLocation as b on b.ItemID     = a.ItemID
                      and b.ValidFrom  = (select max(x.ValidFrom) from ItemLocation as x
                                                                  where x.ItemID = a.ItemID) 
join Location     as c on b.LocationID = c.LocationID
where a.ItemID = 75 ;


-- Earliest location of ItemID = 75
select
      a.ItemID
    , b.LocationID
    , ValidFrom
from Item         as a
join ItemLocation as b on b.ItemID     = a.ItemID
                      and b.ValidFrom  = (select min(x.ValidFrom) from ItemLocation as x
                                                                  where x.ItemID = a.ItemID) 
join Location     as c on b.LocationID = c.LocationID
where a.ItemID = 75 ;

这可能看起来很吓人,但速度很快,ItemID是主键的一部分

在此处输入图像描述

如果您需要在任何时间点列出所有项目

-- Location of all items for point in time ('2012-05-01 11:00:00') 
select
      a.ItemID
    , b.LocationID
    , ValidFrom
from Item         as a
join ItemLocation as b on b.ItemID     = a.ItemID
                      and b.ValidFrom  = (select max(x.ValidFrom)
                                            from ItemLocation as x
                                           where x.ItemID = a.ItemID
                                             and x.ValidFrom <= '2012-05-01 11:00:00') 
join Location     as c on c.LocationID = b.LocationID
;

在此处输入图像描述

于 2012-05-09T21:17:53.110 回答