【问题标题】:T-SQL : why is running multiple sql statements in one batch slower without GO?T-SQL:为什么在没有 GO 的情况下一批运行多个 sql 语句会变慢?
【发布时间】:2021-03-03 02:01:00
【问题描述】:

我遇到了一个非常有趣的问题(至少对我来说)。

当我运行以下 SQL 时:

SELECT count(*) AS [count]
FROM [dbo].[contract_v] AS [contract_v]
WHERE 1 = 0;

SELECT *
FROM [dbo].[contract] AS [contract]
LEFT JOIN ([dbo].[contract_accepted_garbage_type] AS [garbageTypes->contract_accepted_garbage_type]
INNER JOIN [dbo].[garbage_type] AS [garbageTypes] ON [garbageTypes].[id] = [garbageTypes->contract_accepted_garbage_type].[garbage_type_id]) 
     ON [contract].[id] = [garbageTypes->contract_accepted_garbage_type].[contract_id]
WHERE [contract].[id] IN (125018);

执行需要 21 秒

但是当我添加 GO 语句如下:

SELECT count(*) AS [count]
FROM [dbo].[contract_v] AS [contract_v]
WHERE 1 = 0;

GO

SELECT *
FROM [dbo].[contract] AS [contract]
LEFT JOIN ([dbo].[contract_accepted_garbage_type] AS [garbageTypes->contract_accepted_garbage_type]
INNER JOIN [dbo].[garbage_type] AS [garbageTypes] ON [garbageTypes].[id] = [garbageTypes->contract_accepted_garbage_type].[garbage_type_id])
     ON [contract].[id] = [garbageTypes->contract_accepted_garbage_type].[contract_id]
WHERE [contract].[id] IN (125018);

只需 2 秒。

第一个 SQL 语句中使用的视图基于第二个语句中调用的表。

您能向我解释一下这种行为吗?我知道 GO 语句使数据库为每个批次创建单独的执行计划。我检查了执行计划,实际步骤是相同的​​。

谢谢!

【问题讨论】:

  • GO 不是 SQL 语句 - 它是一个 delimiter 用于例如SQL Server Mgmt Studio(以及 sqlcmd 等工具)用于分隔 批次的 SQL 语句。
  • 您在两次尝试刷新缓存之间做了什么,...?您是否尝试以相反的顺序运行 GO/no GO 示例?对性能进行基准测试时的一个常见问题是,第一个操作将表、索引等加载到内存中,而当第二个查询运行时它仍然存在,从而节省了物理读取。
  • @HABO 我已经尝试过各种组合,每次没有 GO 的情况都会变慢,当我多次运行没有 GO 的语句时,每次需要 20 秒。看来数据库缓存与这个性能问题无关。

标签: performance tsql


【解决方案1】:

GO 关键字分隔执行批次。如果两个查询中的基础表相同,并且它们在同一个批处理中执行,则两个查询必须在相同的事务上下文中执行。这样可以确保两个表中的基础数据在两次执行期间都是相同的。

如果使用单独的批处理(中间的 GO 语句),您不能保证数据会保持一致,因为理论上可以在两次执行之间修改行。

如果您不关心查询之间数据发生变化的可能性,那么请务必使用 GO 来提高性能。如果您真的在意,请认为这是一个危险的举动。

SQL Server 应用程序可以将多个 Transact-SQL 语句发送到 SQL Server 实例以作为批处理执行。然后将批处理中的语句编译为单个执行计划。程序员在 SQL Server 实用程序中执行即席语句,或构建 Transact-SQL 语句的脚本以通过 SQL Server 实用程序运行,使用 GO 表示批处理结束。

https://docs.microsoft.com/en-us/sql/t-sql/language-elements/sql-server-utilities-statements-go?view=sql-server-ver15

【讨论】:

  • 我理解GO是分批执行的,但是为什么会有这么大的性能差异,主要是查询表的执行计划是一样的。
  • 如果 contract_v 正在查看与第二个查询相同的记录,那么它可能会尝试锁定记录以确保同一批次中两个查询的数据一致,因为它正在执行数数。优化器可能不会检查 1=0,直到为时已晚,例如表扫描。为什么你总是有错误的 1=0 呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-08
  • 2014-01-09
  • 1970-01-01
  • 2018-06-12
相关资源
最近更新 更多