在下图中,您可以看到我正在尝试做的简化版本。我必须跟踪某些项目的位置,但我还必须有效地检索任何给定项目的最新位置。最简单的方法是查询ItemLocationLog并搜索该项的最新日期,但由于这个表必然非常大,我想知道这是否有效(我猜索引dateTime字段会有所帮助) ,但我没有经验来确定多少)。
我想到的另一种方法是在Item上为日志表添加一个外键(如图所示,字段为“lastLocation”),它总是指向最新的日志条目,因此它将是备用的我的搜索。另一种选择是在项目上添加外键,并在每次为任何给定项目添加日志条目时更新它。
我确信这是一个简单解决方案的常见问题,但由于我没有这方面的经验,我对自己的方法持怀疑态度。这类场景的最佳做法是什么?是否可以添加对Item表的引用以避免代价高昂的查询,或者查询是否足够简单以至于我应该从日志表本身获取此信息?
答案 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)。
-- 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
;