Sql server 为什么嵌套循环块出现在实际执行计划中?

Sql server 为什么嵌套循环块出现在实际执行计划中?,sql-server,database-design,indexing,Sql Server,Database Design,Indexing,我在一个测试社交网站上工作。我被要求为查询创建索引,以获取用户关注的页面。我对索引不熟悉,所以我创建了三个表,并用4500000条记录填充它们进行测试。除了主键和索引外,这三个表是相同的。这些表格如图所示: 我对这三个表使用相同的查询来获取用户所关注的页面。查询是: Select top 10 PageID from UserFollowPages where UserID='something' order by ID 第一个表有一个由PageID和UserID组成的唯一聚集索引 第二

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

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

Select top 10 PageID from UserFollowPages where UserID='something' order by ID  
第一个表有一个由PageID和UserID组成的唯一聚集索引

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

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

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

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

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

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

我有两个问题:

  • 为什么在第三个查询的实际执行计划中会显示嵌套循环(内部联接)块

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

  • 1.嵌套循环 这很简单。用户ID上有一个非聚集索引(NCI),ID本身有一个聚集索引

    SQL Server使用NCI根据
    WHERE
    -子句筛选行。之后,索引返回所有需要的页面和行。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上的聚集索引(因为它是顺序的)和用户ID上的NCI,包括PageId)。您的意思是将PageId作为包含列吗?不完全是。这取决于你的用例。你真的是根据ID订购的吗?如果这是您的正常用例,那么忘记include,只进行集群查找。如果您只需要基于UserId的pageID,那么请考虑包含。希望这描述了您的问题所需的一切。:-)视情况而定。如果您使用UserID查询它,那么我建议在(UserID,PageId)上有一个聚集索引。如果它是(PageId,UserId),它将不会从中受益。另一件事可以是索引碎片化/重组。PageId/UserID的组合可能会导致某些重组。举个例子,一个用户有20个pageId,后面跟着另一个用户(按此顺序)。如果向第一个用户添加新的pageId,则可能会导致重新组织,因为其他行需要向后移动,以便为中间的新行获得一些空间。