【问题标题】:Why nested loop block appear in acutal exection plan?为什么嵌套循环块出现在实际执行计划中?
【发布时间】:2015-09-19 20:45:45
【问题描述】:

我在一个测试社交网站上工作。我被要求为获取用户关注的页面的查询创建索引。我是索引的新手,所以我创建了三个表并用 4500000 条记录填充它们以进行测试。除了主键和索引之外,这三个表是相同的。表格如图所示:

我对三个表使用相同的查询来获取用户关注的页面。查询是:

Select top 10 PageID from UserFollowPages where UserID='something' order by ID  

第一个表有一个由 PageID 和 UserID 组成的唯一聚集索引。

第二个表有一个由 PageID 和 UserID 列组成的唯一非聚集索引。第二个表也有由 ID 列组成的聚集索引。

第三个表具有仅由 UserID 组成的非聚集索引。它还有一个由 ID 组成的聚集索引。

我对三个表执行查询并包含实际的执行计划。三个表格的结果如图所示。

第一个表的第一个查询结果:

第二个表中第二个查询的结果:

第三个表的第三个查询结果:

我有两个问题:

  1. 为什么在第三个查询的实际执行计划中显示了一个嵌套循环(内连接)块?

  2. 我应该使用三个索引中的哪一个,知道这三个查询的执行时间几乎相同(大约 0.5 秒)?

【问题讨论】:

    标签: sql-server database-design indexing


    【解决方案1】:

    1。嵌套循环

    这很简单。您在 UserId 上有一个非聚集索引 (NCI),在 ID 本身上有一个聚集索引。

    SQL Server 使用 NCI 根据您的 WHERE-clause 过滤您的行。之后,索引返回所有需要的页面和行。 SQL Server 现在将使用这些信息在聚集索引中进行聚集查找,以检索所有其他需要的信息(所有其他列)。如果您只想查询UserID 本身,它将消失。

    Select UserID from UserFollowPages where UserID='something'
    

    只是因为所有信息都包含在一个索引中。您可以通过在 NCI 上使用 INCLUDE(pageId, Id) 使用包含的列来避免这种情况(如果确实有必要避免这种情况)。

    2。使用哪个

    由于它们都非常小,因此不太容易确定。这取决于您查询表的方式。我需要更多信息。

    事实上,你应该评估一下,你的表写了多少,查询的频率。如果您的表被写入 1 次并读取 100 万次,那么最好为所有需要的用例提供更多索引。 如果您的表被写入 100 次并读取 10 次,我建议您忽略索引,因为它们只会浪费您的电源和磁盘空间(在大多数情况下是在这种情况下)。

    鉴于您总是使用 UserID 查询表,我建议您应该使用第三个表中的构造。 ID 上的聚集索引(因为它是连续的)和 UserId 上的 NCI,包括 PageId

    【讨论】:

    • 抱歉提交太快了。 ;-) 在我写第二部分之前,希望你能提供一些东西来阅读。已经提交了
    • 对于您的建议(ID 上的聚集索引(因为它是连续的)和 UserId 上的 NCI,包括 PageId。)您的意思是将 PageID 作为包含列吗?
    • 并非如此。好吧,这取决于您的用例。你真的是根据ID订购的吗?如果这是您的正常用例,请忘记包含,只需进行集群查找。如果您只想要基于 UserId 的 pageID,请考虑包含。
    • 谢谢,希望这描述了您的问题所需的一切。 :-)
    • 视情况而定。如果您使用 UserID 查询它,那么我建议在 (UserId, PageId) 上有一个聚集索引。如果它是 (PageId, UserId) 它不会从中受益。另一件事可能是索引碎片/重组。 PageId/UserID 的组合可能会导致一些重组。举个例子,一个用户有 20 个 pageId,然后是另一个用户(按此顺序)。如果您向第一个用户添加新的 pageId,则可能会导致重组,因为其他行需要向后移动以便为中间的新行留出一些空间。
    猜你喜欢
    • 1970-01-01
    • 2020-05-13
    • 2017-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    • 2020-11-07
    相关资源
    最近更新 更多