具有相同外键的左连接表:哈希键探测占 50%
left join tables which have same foreign key: hash key probe takes 50%
我们有 3 张桌子:
- 表 0,包含 ID(= 主键)
- Table1,除其他外,包含指向 table0
中 ID 的可为 null 的 FK
- Table2,其中包含指向 table0
中 ID 的可空 FK
我们的查询运行速度太慢,即使已正确编制索引也是如此。在查看执行计划(SQL Server 2014)时,他在左外连接上浪费了很多时间。 SQL 服务器改为使用 "Hash Match",使其成为内部连接,成本为 47%(如果我没有在 where 子句中明确设置 [FI].[pId] = [FPF].[PId]
,则成本为 50%)。
execution plan
解释说他对 [FI].[pId] 使用 "hash key probe"。
SELECT [FI].[ID], [FI].[Name], [FI].[Data]
FROM [dbo].[Table1] AS [FI] WITH (NOLOCK)
LEFT JOIN [Table2] AS [FPF] WITH (NOLOCK) ON [FI].[pId] = [FPF].[pId]
WHERE
[FI].[pId] = [FPF].[PId] AND -- If I add this explicitly, the query is already a lot faster
(
(
[FI].[tId] = @tID --is bigint (FK)
AND
[Fi].[Name] = @Name --is varchar
)
OR
(
[FI].[fiType] = 1
)
OR
(
[FPF].[tId] = @tID
AND
[FPF].[Name] = @Name
))
ORDER BY [Fi].[Data]
我什至还尝试过 link table0 的主键,但这没有什么区别。同样使用外部应用给出相同的结果。我也一直在两个表上玩索引,但没有任何利润。
有人可以分享一些关于我在这里可能做错了什么的想法吗?
尽量减少 LEFT JOIN 返回的可能记录数。
您只对 [Table2] 中具有特定 @name 和 @tID 的记录感兴趣,因此请在连接点限制 [Table2] result-set 的大小。
SELECT [FI].[ID], [FI].[Name], [FI].[Data]
FROM [dbo].[Table1] AS [FI] WITH (NOLOCK)
LEFT JOIN [Table2] AS [FPF] WITH (NOLOCK) ON [FI].[pId] = [FPF].[pId]
AND [FPF].[tId] = @tID
AND [FPF].[Name] = @Name
WHERE
[FI].[pId] = [FPF].[PId] AND -- If I add this explicitly, the query is already a lot faster
(
(
[FI].[tId] = @tID --is bigint (FK)
AND
[Fi].[Name] = @Name --is varchar
)
OR
(
[FI].[fiType] = 1
)
OR
(
[FPF].[tId] = @tID
AND
[FPF].[Name] = @Name
))
ORDER BY [Fi].[Data]
在 [Table2] 上使用此索引:
CREATE NONCLUSTERED INDEX idx ON [Table2](pID) INCLUDE (tId,Name)
您的额外代码可以将您的查询变成 INNER JOIN。哪个会更快。
[FI].[pId] = [FPF].[PId] AND -- If I add this explicitly, the query is already a lot faster
你真的需要ORDER BY
吗?如果没有,那就摆脱它。
通过在建议索引中添加数据解决,在pid之前添加。
不过,内部连接使情况变得更糟
我们有 3 张桌子:
- 表 0,包含 ID(= 主键)
- Table1,除其他外,包含指向 table0 中 ID 的可为 null 的 FK
- Table2,其中包含指向 table0 中 ID 的可空 FK
我们的查询运行速度太慢,即使已正确编制索引也是如此。在查看执行计划(SQL Server 2014)时,他在左外连接上浪费了很多时间。 SQL 服务器改为使用 "Hash Match",使其成为内部连接,成本为 47%(如果我没有在 where 子句中明确设置 [FI].[pId] = [FPF].[PId]
,则成本为 50%)。
execution plan
解释说他对 [FI].[pId] 使用 "hash key probe"。
SELECT [FI].[ID], [FI].[Name], [FI].[Data]
FROM [dbo].[Table1] AS [FI] WITH (NOLOCK)
LEFT JOIN [Table2] AS [FPF] WITH (NOLOCK) ON [FI].[pId] = [FPF].[pId]
WHERE
[FI].[pId] = [FPF].[PId] AND -- If I add this explicitly, the query is already a lot faster
(
(
[FI].[tId] = @tID --is bigint (FK)
AND
[Fi].[Name] = @Name --is varchar
)
OR
(
[FI].[fiType] = 1
)
OR
(
[FPF].[tId] = @tID
AND
[FPF].[Name] = @Name
))
ORDER BY [Fi].[Data]
我什至还尝试过 link table0 的主键,但这没有什么区别。同样使用外部应用给出相同的结果。我也一直在两个表上玩索引,但没有任何利润。
有人可以分享一些关于我在这里可能做错了什么的想法吗?
尽量减少 LEFT JOIN 返回的可能记录数。
您只对 [Table2] 中具有特定 @name 和 @tID 的记录感兴趣,因此请在连接点限制 [Table2] result-set 的大小。
SELECT [FI].[ID], [FI].[Name], [FI].[Data]
FROM [dbo].[Table1] AS [FI] WITH (NOLOCK)
LEFT JOIN [Table2] AS [FPF] WITH (NOLOCK) ON [FI].[pId] = [FPF].[pId]
AND [FPF].[tId] = @tID
AND [FPF].[Name] = @Name
WHERE
[FI].[pId] = [FPF].[PId] AND -- If I add this explicitly, the query is already a lot faster
(
(
[FI].[tId] = @tID --is bigint (FK)
AND
[Fi].[Name] = @Name --is varchar
)
OR
(
[FI].[fiType] = 1
)
OR
(
[FPF].[tId] = @tID
AND
[FPF].[Name] = @Name
))
ORDER BY [Fi].[Data]
在 [Table2] 上使用此索引:
CREATE NONCLUSTERED INDEX idx ON [Table2](pID) INCLUDE (tId,Name)
您的额外代码可以将您的查询变成 INNER JOIN。哪个会更快。
[FI].[pId] = [FPF].[PId] AND -- If I add this explicitly, the query is already a lot faster
你真的需要ORDER BY
吗?如果没有,那就摆脱它。
通过在建议索引中添加数据解决,在pid之前添加。 不过,内部连接使情况变得更糟