数据库设计:这是位置记录的好习惯吗?

时间:2012-05-09 17:49:27

标签: database database-design entity-relationship

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

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

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

Database Model

3 个答案:

答案 0 :(得分:4)

作为一个原则问题,如果您已经测量性能,确定实际瓶颈并且结论非规范化实际上有帮助(足以抵消数据损坏的风险),则仅在模型中包含冗余

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

索引是非常强大,如果做得好的话。 ItemLocationLog {idItem, dateTime}上的索引应该有助于快速SELECT MAX(dateTime) FROM ItemLocationLog WHERE idItem = ?

请查看Use The Index, Luke!,了解该主题的精彩内容。

答案 1 :(得分:1)

不要针对您不了解的问题进行预优化。

从涵盖ItemLocationLog的{​​{1}}表开始。然后idItem - 假设你的PK是一个自动增量列。 如果 这还不够快,请尝试SELECT TOP 1 idItemLocationLog from ItemLocationLog order by idItemLocationLog DESC加上idItem的索引。如果仍然不够快,那么您可以开始考虑严格的非规范化,例如在dateTime上保留最后一个已知位置引用。

有些人真的很惊讶RDBMS在检索数据方面有多好。你不应该!

答案 2 :(得分:1)

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

enter image description here

-- 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是主键的一部分

enter image description here

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

-- 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
;

enter image description here