可扩展的方式来跟踪用户活动

时间:2013-01-15 22:15:17

标签: sql-server asp.net-mvc scalability

我正在研究人力资源系统,我需要保留用户个人资料中所有观点的跟踪记录,因为每个招聘人员对候选人资料的看法都有限。我主要担心的是我的方法的可扩展性,如下所示: 我目前创建了一个包含2列的表,查看候选人的ID以及查看候选人的招聘人员的ID,每个视图只计算一次,因此如果再次看到相同的候选人,则不会插入任何记录。

根据数据库中的招聘人员和候选人的数量,我可以有把握地说我的表会变得非常快,并且最糟糕的是我必须在每个请求上查询我的表,因为我必须在UI中显示数字招聘人员所看到的候选人。考虑到可扩展性,哪种方法最好?


我会稍微解释一下这个案子: 我们有公司,每家公司都有很多招聘人员。

ViewsAssigner_Identifier表

  • Id:int PK
  • Company_Id:int FK NON-CLUSTERED
  • Views_Assigned:int NON-CLUSTERED
  • 日期:日期非集群

CandidateViewCounts表

  • Id:int PK
  • Recruiter_id:int FK NON-CLUSTERED?
  • Candidate_id:int FK NON-CLUSTERED?
  • ViewsAssigner_Identifier_Id:int FK NON-CLUSTERED?
  • DateViewed:date NON-CLUSTERED

我将通过[ViewsAssigner_Identifier_id]

查询所有[Candidate_id]的选择

我们希望按公司搜索而非Recruiter,因为同一公司的所有招聘人员都使用相同的[Views_Assigned]给公司。换句话说,第一个查看候选人的Recuiter将被存储在“CandidateViewCounts”表中,并且不会存储查看同一候选人的后续Recruit。

结果: 我需要通过[ViewsAssigner_Identifier_id]检索所有[Candidate_Id]的列表,然后我可以将所有这些候选ID整合。

查询示例:

SELECT [Candidate_Id] FROM [dbo]。[CandidateViewCounts] WHERE [ViewsAssigner_Identifier_id] = 1

有任何建议吗?

2 个答案:

答案 0 :(得分:3)

如果您认为每个招聘人员可能会查看每个候选人一次,那么您最多会谈论60,000 * 2,000,000行。这是一个很大的数字,但它们不是很宽的行;正如ErikE解释的那样,你可以在每个页面上获得很多行,所以即使是表格扫描的总I / O也不会像它听起来那么糟糕。

也就是说,出于维护原因,只要您不通过CandidateID进行搜索,您可能希望在RecruiterID上对此表进行分区。例如,您的分区方案可能有一个分区用于RecruiterID在1到2000之间,一个分区用于2001 - >这样就可以最大化每个分区的行数,并可以相应地规划文件空间(您可以将每个分区放在自己的文件组中,分离I / O)。

另一点是这样的:如果你想查询诸如“对这个候选人有多少观点(我们不关心哪些招聘人员)”这样的查询?或者“这个招聘人员看了多少候选人(我们不关心哪些候选人)?”那么你可以考虑索引视图。 E.g。

CREATE VIEW dbo.RecruiterViewCounts
WITH SCHEMABINDING
AS
  SELECT RecruiterID, COUNT_BIG(*)
    FROM dbo.tablename;
GO
CREATE UNIQUE CLUSTERED INDEX pk_rvc ON dbo.RecruiterViewCounts(RecruiterID);
GO

CREATE VIEW dbo.CandidateViewCounts
WITH SCHEMABINDING
AS
  SELECT CandidateID, COUNT_BIG(*)
    FROM dbo.tablename;
GO
CREATE UNIQUE CLUSTERED INDEX pk_cvc ON dbo.CandidateViewCounts(CandidateID);
GO

现在,这些聚簇索引的维护成本很高,因此您需要针对它们测试写入工作负载。但是他们应该非常快速地进行这两个查询,而不必寻找你的大表,并且可能为非常繁忙的招聘人员或非常受欢迎的候选人阅读多个页面。

答案 1 :(得分:1)

如果您的表格聚集在RecruiterID上,那么您的搜索速度非常快,而且我认为根本没有性能问题。

在你所描述的如此狭窄的表格中,找出任何一个招聘人员所查看的个人资料应该只需99%的时间阅读。 (假设fillfactor = 80,页面分割最小;行宽假设两个int列= 16个字节+开销,调用20个字节;每页8040个字节;假设他们得到4个视图,平均每个招聘人员2.5行=每个数据页面有128个招聘人员)。表中的总行数无关紧要,因为它可以搜索到聚簇索引。是的,它必须遍历树,但它仍然会非常快。只要每个候选人必须计算一次意见,就没有更好的方法。如果只是总观看次数,则可以改为计算。

我认为你不用担心。如果您担心系统可能会增长到每秒数万个请求,并且您将获得某种限制热点活动,只要在任何一个时间点访问的招聘人员不会巧合地将顺序ID分配给他们,你会好的。

这里的一个重要原则是你要避免任何必须从上到下扫描桌面的东西。只要您始终按RecruiterIDRecruiterID, CandidateID进行搜索,就可以避免这种情况。您希望仅通过CandidateID进行搜索的那一刻,如果没有其他索引,您将遇到麻烦。在CandidateID上添加非聚集索引会使表占用的空间增加一倍(聚簇的一半,非聚簇的一半),但这没什么大不了的。然后按CandidateID搜索将同样快,因为非聚集索引将正确覆盖查询,并且不需要书签查找。

<强>更新

这是对您在问题更新中提供的大量新信息的回复。

首先,您的CandidateViewCounts表名称不正确。这更像是CandidateFirstViewedByRecruiterAtCompany。它只能间接回答你的问题,这是关于公司的问题,而不是招聘人员,所以我认为你所描述的情景确实需要一个CompanyCandidateViewed表:

CompanyID int FK
CandidateID int FK
PRIMARY KEY CLUSTERED (CompanyID, CandidateID)

存储查看候选人的招聘人员的公司ID以及CandidateID。简单!现在我的原始答案仍然适合您,只需将RecruiterIDCompanyID交换。

如果您确实想要跟踪哪些招聘人员查看了哪些候选人,请在RecruiterCandidateViewed表中进行(并存储所有招聘人员 - >候选人观点)。这可以在以后查询或在数据仓库中查询。但是上述表格将满足您的实时OLTP需求。

另外,我想提一下,您可能将标识列放在不需要它们的表中。您应该避免使用标识列,除非该列将在另一个表中用作FK(并不总是那样,因为有时在正确的数据建模中为了防止可能的非规范化,您必须在FK中使用复合键)。例如,您的ViewsAssigner_Identifier表在我看来需要一些帮助(当然我没有这里的所有信息,可能不在基础上)。如果CompanyDate是该表最重要的,请将它们组合在一起,并尽可能地删除标识列。