为什么嵌套循环块会出现在实际的执行计划中?
Why nested loop block appear in acutal exection plan?
我在一个测试社交网站上工作。我被要求为查询创建索引,以获取用户 follows.I 对索引不熟悉的页面,因此我创建了三个 table 并在其中填充了 4500000 条记录以进行测试。三个table除了主键和索引外其他都是一样的。 tables如图所示:
我对三个 table 使用相同的查询来获取用户关注的页面。查询是:
Select top 10 PageID from UserFollowPages where UserID='something' order by ID
第一个 table 有一个由 PageID 和 UserID 组成的唯一聚集索引。
第二个 table 有一个由 PageID 和 UserID 列组成的唯一非聚集索引。第二个 table 也有由 ID 列组成的聚簇索引。
第三个 table 具有仅由 UserID 组成的非聚集索引。它还有一个由ID组成的聚簇索引。
我执行三个 table 的查询并包括实际执行计划。三个 table 的结果如图所示。
第一个 table 中第一个查询的结果:
来自第二个 table 的第二个查询的结果:
第三个 table 的第三个查询的结果:
我有两个问题:
为什么第三个查询的实际执行计划中会出现嵌套循环(内连接)块?
我应该使用三个索引中的哪一个,知道三个查询执行的时间几乎相同(几乎 0.5 秒)?
1。嵌套循环
很简单。您在 UserId 上有一个非聚集索引 (NCI),在 ID 本身上有一个聚集索引。
SQL 服务器使用 NCI 根据您的 WHERE
子句过滤您的行。之后,索引 returns 所有需要的页面和行。 SQL 服务器现在将使用这些信息在聚簇索引中进行聚簇查找,以检索所有其他需要的信息(所有其他列)。如果您只想查询 UserID
本身,它就会消失。
Select UserID from UserFollowPages where UserID='something'
只是因为所有信息都包含在一个索引中。您可以通过在 NCI 上使用包含的列使用 INCLUDE(pageId, Id)
来避免这种情况(如果确实有必要避免它)。
2。使用哪一个
由于都非常小,不好判断。这取决于您查询 table 的方式。为此,我需要更多信息。
其实你应该评估一下,你的table写了多少,查询的频率是多少。如果您的 table 被写入 1 次并读取 100 万次,那么最好为所有需要的用例提供更多索引。
如果您的 table 写入了 100 次,读取了 10 次,我建议您忽略索引,因为它们只会浪费您的电量和磁盘 space(在大多数情况下都是这种情况)。
鉴于您总是使用 UserID 查询 table,我建议您应该使用第三个 table 中的结构。 ID
上的聚集索引(因为它是顺序的)和 UserId
上的 NCI,包括 PageId
.
我在一个测试社交网站上工作。我被要求为查询创建索引,以获取用户 follows.I 对索引不熟悉的页面,因此我创建了三个 table 并在其中填充了 4500000 条记录以进行测试。三个table除了主键和索引外其他都是一样的。 tables如图所示:
我对三个 table 使用相同的查询来获取用户关注的页面。查询是:
Select top 10 PageID from UserFollowPages where UserID='something' order by ID
第一个 table 有一个由 PageID 和 UserID 组成的唯一聚集索引。
第二个 table 有一个由 PageID 和 UserID 列组成的唯一非聚集索引。第二个 table 也有由 ID 列组成的聚簇索引。
第三个 table 具有仅由 UserID 组成的非聚集索引。它还有一个由ID组成的聚簇索引。
我执行三个 table 的查询并包括实际执行计划。三个 table 的结果如图所示。
第一个 table 中第一个查询的结果:
来自第二个 table 的第二个查询的结果:
第三个 table 的第三个查询的结果:
我有两个问题:
为什么第三个查询的实际执行计划中会出现嵌套循环(内连接)块?
我应该使用三个索引中的哪一个,知道三个查询执行的时间几乎相同(几乎 0.5 秒)?
1。嵌套循环
很简单。您在 UserId 上有一个非聚集索引 (NCI),在 ID 本身上有一个聚集索引。
SQL 服务器使用 NCI 根据您的 WHERE
子句过滤您的行。之后,索引 returns 所有需要的页面和行。 SQL 服务器现在将使用这些信息在聚簇索引中进行聚簇查找,以检索所有其他需要的信息(所有其他列)。如果您只想查询 UserID
本身,它就会消失。
Select UserID from UserFollowPages where UserID='something'
只是因为所有信息都包含在一个索引中。您可以通过在 NCI 上使用包含的列使用 INCLUDE(pageId, Id)
来避免这种情况(如果确实有必要避免它)。
2。使用哪一个
由于都非常小,不好判断。这取决于您查询 table 的方式。为此,我需要更多信息。
其实你应该评估一下,你的table写了多少,查询的频率是多少。如果您的 table 被写入 1 次并读取 100 万次,那么最好为所有需要的用例提供更多索引。 如果您的 table 写入了 100 次,读取了 10 次,我建议您忽略索引,因为它们只会浪费您的电量和磁盘 space(在大多数情况下都是这种情况)。
鉴于您总是使用 UserID 查询 table,我建议您应该使用第三个 table 中的结构。 ID
上的聚集索引(因为它是顺序的)和 UserId
上的 NCI,包括 PageId
.