我是否需要第二个表来存储此数据库逻辑?

时间:2010-01-02 12:37:43

标签: sql tsql view triggers

首先,这个数据库问题可能与数据库无关,但我使用的是Sql Server 2008,如果它有针对此问题的专门解决方案,但如果您不是MS Sql Server人员请继续阅读..请:)


好的,我在一个包含游戏数据的日志文件中读到。例如。当一个玩家连接,断开连接,做东西等等。没什么太难的。效果很好。

现在,有两个日志文件条目类型是

  • NewConnection
  • LostConnection

我正在努力追踪的是当前连接的玩家,以及游戏。 所以我最初想到的是创建第二个表,其中包含每个玩家最新的连接。当玩家断开/失去连接时,我会从第二个表中删除此条目。

例如

Table 1: LogEntries
LogEntryId INT PK NOT NULL
EntryTypeId TINYINT NOT NULL
PlayerId INT NOT NULL
....

Table 2: ConnectedPlayers
LogEntryId INT FK (back to LogEntries table) NOT NULL

然后,我想我可以使用触发器将此插入缓存数据到ConnectedPlayers表中。不要忘记,如果它是一个触发器,它需要handle multiple records,更新和删除。

但我不确定这是不是最好的方法。就像,我可以拥有索引视图吗?

我很想知道别人对此的看法。

哦,还有一件事:为了简单起见,我们假设当播放器掉线/延迟/调制解调器芯片等时,应用程序足够聪明地知道这一点并且将其记录为LostConnection条目。没有虚假用户被报告为连接,当他们真的意外断开连接等等时


UPDATE:

我在想,也许我可以使用view代替? (我可以索引这个视图,如果我想,也:) :)通过Partitioning我的结果,我可以得到最新的事件类型,每个玩家..事件是NewConnection或者LostConnection。然后只抓住那些最新的NewConnection ..这意味着他们已连接。没有第二个表/触发器/额外插入.NET代码/任何需要的......

例如..

SELECT LogEntryId, EntryTypeId, PlayerId
FROM
    (SELECT LogEntryId, EntryTypeId, PlayerId
         RANK() OVER (PARTITION BY PlayerId ORDER BY LogEntryId DESC) AS MostRecentRank
     FROM LogEntries
     WHERE (EntryTypeId = 2 -- NewConnection
            OR EntryTypeId = 4 -- LostConnection)
     ) SubQuery
WHERE MostRecentRank = 1

听起来怎么样?

5 个答案:

答案 0 :(得分:1)

您不需要第二个表,但是您需要一个日期列,我假设它是日志数据的一部分。我会规范化数据并避免过早优化的诱惑。确保为关键列编制索引,主要是查询时的LogEntryDate和PlayerId列。

然后,使用标准聚合查询确定每个用户的最新日志条目,然后筛选出未连接的用户。您可以通过仅选择过去24小时(或上周或对您的应用程序有意义的任何内容)的日志条目来进一步优化此操作。

select l.* 
from ( 
    select PlayerId, max(LogEntryDate) as MaxLogEntryDate
    from LogEntries
    where EntryTypeId in (2,4) 
        and LogEntryDate > GetDate() - 7 --only look at the last week, as connections older than that have timed out
    group by PlayerId
) lm
inner join LogEntries l on lm.PlayerId = l.PlayerId and lm.MaxLogEntryDate = l.LogEntryDate
where l.EntryTypeId = 2 --new connections only

如果您发现自己仍未达到查询速度,则会查看优化策略。您似乎不愿意在应用程序层中缓存,因此您的索引视图提议将起作用。您可以使用上面的查询作为此基础,以创建包含布尔IsConnected列的播放器视图。

注意:如果您没有收到每个日志条目的日期,但游戏会生成LogEntryId,那么它应该可以替代日期。如果您在插入时生成LogEntryId,我会提醒您不要依赖它,因为只需要一次乱序导入就可以抛弃所有数据。

答案 1 :(得分:0)

根据原始表 LogEntries 的大小,这几乎看起来有点过分。

触发器必须随着对原始表的每次更改而更新,如果使用正确的索引,当您需要数据时,简单查询可以为您提供这些结果。

因此我会反对辅助表的选项。

答案 2 :(得分:0)

我会创建一个is_connected标志,login_time,这就是它。 您可以使用简单的MySQL查询每10/60秒检查一次,并将数据缓存到文件中。

其中is_connected = 1,按login_time限制订购10/20/100 ...

第二张桌子看起来太多而且毫无用处。额外的缓存(如果需要,在一个巨大的数据库中......)可以在文件上完成。

答案 3 :(得分:0)

我个人会使用一个视图来获取每个玩家最新的NewConnection或LostConnection(以较新者为准),这意味着您需要在日志中添加某种日期时间戳或者ID不断增加,以及然后筛选进一步丢弃所有LostConnection条目。这将使所有玩家都拥有NewConnection而没有更新的LostConnection,因此它们已连接。

这种方法可能遇到的问题是日志表可能很大。我可能会尝试使用timestamp列上的索引或您用来确定“最新”条目的列的性能测试。

答案 4 :(得分:0)

据我所知,你真正需要的是

玩家(ID) 游戏(ID) 连接(PlayerID,GameID,LastActivity DateTime) ..

@interestingTime是当前

之前的一段时间
select PlayerID, GameID
from Connection
where LastActivity > @interestingTime

为您提供所有当前连接的玩家。

select PlayerID, GameID
from Connection
where LastActivity <= @interestingTime

让你失去联系。