【发布时间】:2021-04-19 18:02:04
【问题描述】:
我有以下查询在 14 秒内运行(这对我来说似乎过多):
select top 20 App.Id
from
App
inner join Base on Base.Id = App.BaseId
WHERE App.TermId = 1190676
ORDER BY App.Id
apps.Id 是主键 (int)。 Base.Id 是主键 (int)。 App.TermId 和 App.BaseId 是非聚集索引。 App.Term 也是此查询中未使用的表的外键。
Base.Id、App.BaseId 和 App.TermId 上的索引碎片少于 0.5%。
Table Base 有 71,879 条记录,App 有 16,238,898 条记录。如果上面的查询没有顶级条件,则只会返回 796,661。
如果我删除内连接,查询将在不到 1 秒的时间内运行。
我对阅读执行计划了解不多,但似乎寻找索引 Base.Id 的成本最高(70%),但为 0.0s。而聚集索引扫描的成本为 30%,但耗时 18.5 秒。
我已经跑了:
DBCC CHECKTABLE ('dbo.Base', REPAIR_REBUILD)
DBCC CHECKTABLE ('dbo.App', REPAIR_REBUILD)
14 秒听起来合理吗?我还能调查什么?我可以分享执行计划中的其他有用信息吗?
.sqlPlan 可以在这里找到: https://pastebin.com/UxDvsPRk
12:52 我用以下方法进行了测试,上面的查询慢了 1 秒:
CREATE NONCLUSTERED INDEX [ix_dbo_App_TermId_BaseId] ON dbo.App
(
TermId, BaseId
)
1:14 根据建议,我将索引更新为:
CREATE NONCLUSTERED INDEX [ix_dbo_App_TermId_BaseId] ON dbo.App
(
TermId, BaseId
)
include (Id)
...查询仍然很慢。但是,现在它似乎只有在 ORDER BY 存在时才会变慢。连接本身不到 1 秒。
【问题讨论】:
-
你想要
ANY 20的行为吗?您的TOP不应该与ORDER BY结合使用以获得可预测的输出吗?执行计划是什么样的(请将 .sqlplan 发布到 pastetheplan.com,而不是图片)? -
没有看到计划,对于这个查询,我想
App (TermId, Id)和Base (Id)上的索引将是最有用的(注意列顺序)。然后你会得到一个非常快速的合并连接 -
@AaronBertrand 我已将 pastebin 添加到我的帖子中。我已经提供了订单。见:pastebin.com/UxDvsPRk
-
分享计划的更好方法是将计划 XML 上传到 Paste The Plan。这样,图形计划和 XML 都可以轻松查看。
-
为了澄清@Charlieface 的意思,您需要一个复合索引,一个从 2 列键控出来的索引。他是绝对正确的。您可以通过将 App.TermID 设置为 App.BaseId 索引上的包含列来稍微捏造一下,但我想对此进行测试以确定。
标签: sql-server indexing sql-server-2016