3

我正在开发一个人力资源系统,我需要跟踪用户个人资料上的所有视图,因为每个招聘人员对候选人个人资料的视图都是有限的。我主要关心的是我的方法的可扩展性,如下所示:我目前创建了一个包含 2 列的表,即被查看的候选人的 id 和查看候选人的招聘人员的 id,每个视图只计算一次,所以如果您再次看到相同的候选人,不会插入任何记录。

根据数据库中招聘人员和候选人的数量,我可以肯定地说我的表格会增长得非常快,更糟糕的是,我必须在每次请求时查询我的表格,因为我必须在 UI 中显示候选人的数量招聘人员查看过。考虑到可扩展性,哪种方法最好?


我将再解释一下这个案例:我们有公司,每家公司都有很多招聘人员。

ViewsAssigner_Identifier 表

  • 编号:int PK
  • Company_Id:int FK 非集群
  • Views_Assigned: int 非集群
  • 日期:日期非集群

CandidateViewCounts 表

  • 编号:int PK
  • Recruiter_id: int FK NON-CLUSTERED ?
  • Candidate_id: int FK NON-Clustered ?
  • ViewsAssigner_Identifier_Id: int FK NON-CLUSTERED ?
  • DateViewed:日期非聚集

我将通过 [ViewsAssigner_Identifier_id] 查询所有 [Candidate_id] 的 Select

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

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

查询示例:

从 [dbo].[CandidateViewCounts] 中选择 [Candidate_Id],其中 [ViewsAssigner_Identifier_id] = 1

有什么建议吗?

4

2 回答 2

3

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

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

另一点是:如果您要运行诸如“对该候选人有多少意见(我们不在乎哪些招聘人员)之类的查询?” 或者“这个招聘人员查看了多少候选人(我们不在乎哪些候选人)?” 那么你可以考虑索引视图。例如

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

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

于 2013-01-15T22:40:38.720 回答
1

如果您的表聚集在 上,RecruiterID您将有一个非常快速的搜索,并且在我看来根本没有性能问题。

在您所描述的如此狭窄的表格中,查找为任何一位招聘人员查看的个人资料应该需要一次阅读 99+% 的时间。(假设填充因子 = 80,页面拆分最少;行宽假设两int列 = 16 字节 + 开销,称其为 20 字节;每页 8040 字节左右;假设每个招聘人员平均获得 4 次查看 2.5 行 = 每个数据大约 128 个招聘人员页)。表中的总行数无关紧要,因为它可以查找聚集索引。是的,它必须遍历树,但它仍然会非常快。只要每个候选人必须计算一次意见,就没有更好的方法了。如果它只是总观看次数,您可以改为计数。

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

这里的大原则是您要避免任何必须从上到下扫描表格的事情。只要您始终按RecruiterID或搜索,就可以避免这种情况RecruiterID, CandidateID。当您想CandidateID单独搜索时,如果没有额外的索引,您将遇到麻烦。添加非聚集索引CandidateID将使您的表占用的空间增加一倍(一半用于聚集,一半用于非聚集),但这没什么大不了的。然后搜索CandidateID将同样快,因为非聚集索引将正确覆盖查询,并且不需要书签查找。

更新

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

首先,您的CandidateViewCounts表命名不正确。它更像是CandidateFirstViewedByRecruiterAtCompany。它只能间接回答您的问题,即关于公司而不是招聘人员的问题,所以在我看来,您所描述的场景确实需要一张CompanyCandidateViewed桌子:

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

存储查看候选人的招聘人员的 CompanyID 和 CandidateID。简单的!现在我原来的答案仍然适用于你,只需RecruiterIDCompanyID.

如果您确实想跟踪哪些招聘人员查看了哪些候选人,请在RecruiterCandidateViewed表格中执行此操作(并存储所有招聘人员->候选人视图)。这可以稍后或在数据仓库中查询。但是您的实时 OLTP 需求将通过上述表格得到满足。

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

于 2013-01-15T22:22:20.437 回答