是否可以在 Microsoft SQL Server 上为 SQL 查询设置超时?
Posted
技术标签:
【中文标题】是否可以在 Microsoft SQL Server 上为 SQL 查询设置超时?【英文标题】:Is it possible to set a timeout for a SQL query on Microsoft SQL Server? 【发布时间】:2011-03-06 17:28:21 【问题描述】:我有一个场景,有时用户选择正确的参数并进行需要几分钟或更长时间才能执行的查询。我不能阻止他选择这样的参数组合(这很合法),所以我想在查询上设置一个超时。
请注意,我真的想停止查询执行本身并回滚任何事务,否则它会占用大部分服务器资源。添加一个不耐烦的用户重新启动应用程序并再次尝试组合,您就有了灾难的秘诀(阅读:SQL Server DoS)。
这可以做到吗?如何做到?
【问题讨论】:
有什么理由不能在代码中的连接对象上设置它吗? @Oded - 因为我想要它在服务器级别,而不是客户端。我可以在客户端连接上设置它,但这只会终止我的连接。查询将继续在服务器上执行,直到完成。 据我所知,没有办法在逐个查询的基础上执行此操作。sp_configure
允许设置超时,但我相信它们是服务器范围的。
@Oded - 很不幸。 :( 是否愿意将其作为答案以便我接受?
【参考方案1】:
您可以在连接数据库时在 SQL 连接字符串中指定连接超时时间,如下所示:
"Data Source=localhost;Initial Catalog=database;Connect Timeout=15"
在服务器层面,使用MSSQLMS查看服务器属性,在Connections页面可以指定默认查询超时时间。
我不太确定在客户端连接关闭后查询是否继续运行。查询也不应该花那么长时间,MSSQL 可以处理大型数据库,我以前处理过 GB 的数据。对查询运行性能配置文件,也许一些放置良好的索引可以加快速度,或者重写查询也可以。
更新: According to this list,等待服务器注意确认时发生 SQL 超时:
假设您执行了一个命令,然后该命令超时。发生这种情况时,SqlClient 驱动程序会向服务器发送一个特殊的 8 字节数据包,称为注意数据包。这告诉服务器停止执行当前命令。当我们发送注意数据包时,我们必须等待来自服务器的注意确认,这在理论上可能需要很长时间并且超时。您还可以通过在异步 SqlCommand 对象上调用 SqlCommand.Cancel 来发送此数据包。这是一种特殊情况,我们使用 5 秒超时。在大多数情况下,您永远不会遇到这个问题,服务器通常对注意力数据包非常敏感,因为这些数据包在网络层的处理非常低。
所以看起来客户端连接超时后,也会向服务器发送信号以取消正在运行的查询。
【讨论】:
那是连接超时,这与我想要的完全不同。如果它无法连接到服务器(或无法从池中获取连接),这将超时。当我执行一些长时间运行的查询时,我想要一个超时。 啊我明白了,抱歉我误会了。【参考方案2】:如果您只有一个查询,我不知道如何在 T-SQL 级别设置超时。
但是,如果您在存储过程中有一些查询(即将数据收集到临时表中),您可以使用GETDATE()
、DATEDIFF()
和一些INT
变量来控制执行时间存储每个部分的执行时间。
【讨论】:
我希望它是一种通用机制,我将其合并到框架中,因此这实际上不起作用。 :(【参考方案3】:据我所知,除了在客户端设置命令或连接超时,没有办法在服务器中逐个查询更改超时。
您确实可以使用 sp_configure
更改默认的 600 秒,但这些是服务器范围的。
【讨论】:
您应该澄清服务器范围的含义。 SQL Serve 有一个远程查询超时值,它指的是它在链接服务器上发出的查询,而不是客户端向它发出的查询。我相信查询超时是客户端属性,而不是服务器属性。服务器无限期地运行查询。有一个查询调控器可以解决这个问题,默认情况下是禁用的。【参考方案4】:哼! 你试过LOCK_TIMEOUT吗 在运行查询之前记下它最初是什么 为您的查询设置它 运行查询后将其恢复为原始值
SET LOCK_TIMEOUT 1800;
SELECT @@LOCK_TIMEOUT AS [Lock Timeout];
【讨论】:
如果您使用 c# 从 sql server 获取数据,那么您可以在 SqlCommand 对象中设置 Timeout。 这是正确的答案,至少对于我的要求,我可以看到管理工作室的值为 -1(无限),如果我将其设置为 1000,它将在 1 秒时超时。就我而言,我有一些行似乎被锁定,但其他行没有,所以我编写了一个 foreach 行的脚本,并设置了一个小的超时来跳转被锁定的行。【参考方案5】:我可能会建议两件事。
1) 如果您的查询需要很多时间,因为它使用了可能涉及锁定的多个表,那么一个非常快速的解决方案是使用“NoLock”提示运行您的查询。
只需在所有表引用中添加 Select * from YourTable WITH (NOLOCK)
即可防止查询阻塞并发事务。
2) 如果您想确保您的所有查询都在(比方说)不到 5 秒的时间内运行,那么您可以添加 @talha 建议的内容,这对我很有效
只需在执行的顶部添加
SET LOCK_TIMEOUT 5000; --5 seconds.
这将导致您的查询少于 5 次或失败。然后你应该捕获异常并在需要时回滚。
希望对你有帮助。
【讨论】:
嗯,这已经是 7 多年前的事了,所以我不记得查询是什么了。 :) 但我认为这与大量数据(几个大表相乘)而不是锁有关。 对'with (nolock)' 的建议投了反对票,没有附加大的警告。 NOLOCK 允许发生许多查询错误,包括:跳过匹配的行、返回与您的查询不匹配的行以及返回同一行两次。 我从来没有见过 noLock 做你提到的事情,NoLock 只允许脏读,如果你的结果中有不匹配/匹配或重复数据的东西,是你查询中的问题,唯一的“建议”是您可能正在读取可能在您运行查询的同一毫秒内实际发生变化的数据,但不是您所说的。【参考方案6】:在管理工作室中,您可以以秒为单位设置超时。 menu Tools => Options 设置字段然后Ok
【讨论】:
我的问题是关于从代码中执行此操作。您知道如何 Management Studio 实现超时吗? 另外,超时实际上是终止查询,还是在查询继续运行时断开连接?【参考方案7】:这听起来更像是一个架构问题,您可以做的任何超时/断开连接或多或少都是一个创可贴。这必须在 SQL 服务器端通过只读副本、事务日志传送(为您提供一个只读服务器来连接)、复制等方式来解决。基本上,你给 DMZ sql server 重读可以去而不杀死东西。这是很常见的。一个设计良好的 SQL 系统不会被 DDoS 摧毁——这就像一辆踩油门就会死的汽车。
也就是说,如果您可以随意更改代码,您可以猜测查询是否过于繁重,您可以拒绝或仅返回存储过程中的 X 行。如果您使用了某些报告工具等并且无法控制它生成的 SELECT,您可以将其指向一个视图,然后在视图中执行安全阀。
此外,如果最新的新鲜度并不重要,并且您可以在这一点上做出妥协,例如每月销售数据,那么按作业编译复杂联接的物理表以避免复杂联接可能会起到作用 - 即方式每次查询都将是亚秒级。
这完全取决于您在做什么,但总会有解决方案。有时需要额外的编码来优化它,有时需要额外的钱来获得二级只读数据库,有时需要时间和精力来调整索引。
所以这完全取决于,但我会从“我可以妥协什么?我可以改变什么?”开始。然后从那里出发。
【讨论】:
【参考方案8】:您可以以秒为单位设置执行超时。
【讨论】:
以上是关于是否可以在 Microsoft SQL Server 上为 SQL 查询设置超时?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在 Microsoft SQL Server 上为 SQL 查询设置超时?
是否可以在 Microsoft SQL 2000+ 中的表中添加描述/注释