我正在研究在SQL Server上部署一些不占资源但已知的长期存储过程的想法。经过长时间的运行,我在10分钟范围内思考。
它们长时间运行但不占用资源的原因是它们通过C#SQLCLR代码访问外部系统,而这些外部系统的性能导致了性能问题,SQL Server花费了大部分时间它只是在等待外部系统的结果。
我100%意识到做这类事情可能是"不推荐"在SQL Server上,像PowerShell这样的东西会更合适,但是我希望将这个问题限制在实际上对整体SQL Server性能/资源实际上是否有害,如果是这样的话,有多害。
在我的场景中,整体服务器负载不会很高,最多可能有20个其他查询正在运行,其中大多数是针对SQL表的正常查询 - 最多可能有3个用户运行其中一个这样的慢查询。
所以我的问题是:在SQL Server上提供此类查询是否存在任何真正的风险,是否存在与阻塞,连接等相关的问题?
修改:
为了便于讨论,我们假设这是在一个4 CPU,8GB RAM盒上运行。
这样做的动机(从业务角度来看)是它有助于使用SQL作为访问多个异构外部系统的通用抽象层,从而消除了对众多终端用户安装各种本地专有客户端软件的依赖,或者了解所涉及的各种系统的模糊调用语法。
我真的希望人们不要投票来关闭这个问题,因为关于一个人是否应该"的哲学观点。这样做与否。能够使用SQL Server实现这一点在经济上是有价值的。但是,如果它实际上在技术上是危险的,那么是否应该描述一些危险的具体细节呢?
编辑2 应主持人的要求,我将提供一些额外的细节,以缩小我所要求的范围。
情景:
我的公司环境中有20个不同的系统。这些系统中的每一个都有一个专门的API,需要安装软件来访问系统,以及正确语法的专业知识,以便查询系统内的数据。每个系统还有一个可以通过C#访问的API。
由于公司内部的每个人都非常熟悉SQL服务器,因此为所有这些系统提供行业标准API在经济上是有利的,这样可以消除在每个客户端桌面上安装特殊软件的要求,以及最终 - 用户需要学习复杂的语法来查询每个不同的系统。在这种情况下,通用API是SQL Server存储过程(实现为C#SQL CLR存储过程,但这对调用者完全透明)。这些过程的接口(参数)简单且文档齐全,并且完全将用户与基础系统调用实现和语法的复杂性隔离开来。
对任何给定底层系统的实际调用的执行时间范围从小于1秒到长达10分钟,具体取决于所调用的特定过程和系统。在这个SQL过程中没有进行额外的昂贵处理,长时间运行只是等待远程系统完成查询并返回结果的过程。
典型的结果集大小为1到50,000行,平均值可能大约为1000行。 非常大型结果集的大小为5 MB。
在任何给定时间,此服务器上最多可能有25个同时执行的查询处于活动状态,其中至少有20个查询正在执行"常规" TSQL存储过程读取驻留在本地数据库中的普通SQL Server表,而其中最多5个可能是这些"特殊的" C#SQL CLR查询访问外部系统。
所有查询都是读取,没有写入,并且没有正在执行的事务性多命令查询。
25个最大并发查询x 5 MB最大结果集大小=最多125 MB"纯数据"在任何给定时间的内存中,加上任何附带的SQL Server"开销"。
这个运行的典型服务器将是一个运行SQL Server 2012的4 CPU,8GB RAM盒。如果我选择的话,我有很大的余地来大规模增加这个盒子的功能 - 在这种情况下没有预算限制。
因此,考虑到此方案,是否有人知道任何具体技术原因,为什么此实施无效,或合理推测某些技术限制可能出现了?
暂时......我不知道是否有人曾经听过Jeff和Joel在首次开发时回复过的StackoverFlow播客,但这个问题有点让人联想起Joel告诉的轶事他问的是在SQL Server中做了一些不寻常的事情(出于一个非常具体但有效的原因),并且所有答案基本上都是"你不应该这样做!" :)
可能感兴趣的人的参考资料:
https://blog.stackexchange.com/2009/01/podcast-38/
https://stackoverflow.fogbugz.com/default.asp?pg=pgWiki&command=view&ixWikiPage=29025
SQL Server "AFTER INSERT" trigger doesn't see the just-inserted row
同样,我当然意识到这个问题非常不寻常,但如果从纯粹的技术角度考虑,我认为不应该引起争议。
Mods :如果这个额外的细节足以最大限度地减少误解,请告诉我。我真的希望这个问题可以保持开放,因为它是善意的,合法的,并且涉及我认为是一个非常有趣的SQL Server平台功能的边缘案例。
答案 0 :(得分:3)
鉴于在所有情况下:
然后,从概念上讲,SQL Server的稳定性应该没有特定的内在危险。但是,有几件事需要考虑和/或注意:
C#API是指您作为项目参考添加的DLL,对吗?此第三方DLL将需要与您的DLL一起加载到SQL Server中。这是事情变得棘手的地方。可以安全地假设DLL将通过网络与其他服务器通信,因此至少需要将其标记为WITH PERMISSION_SET = EXTERNAL_ACCESS
。
.pfx
文件对第三方DLL进行签名。如果第三方DLL已经签名,我想你可以重新签名。UNSAFE
。这里的风险取决于特定的HPA。例如,通过TimeZoneInfo
进行TimeZone转换可能会导致内存泄漏,因此标记为MayLeakOnAbort
。CREATE ASSEMBLY
而不将程序集设置为UNSAFE
时通知DLL是否执行此操作。将程序集设置为UNSAFE
将允许它工作,您现在有可能运行访问静态变量的代码的多个会话将经历" odd"行为可能会得到不正确的结果。问题是,所有会话都共享一个App Domain,因此为了使用静态变量需要UNSAFE
。唯一可以解决此问题的方法是在任何使用静态变量的API调用周围放置lock
。但是,这不是绝对修复,因为静态变量可能用于不同的API调用。存储的值可能对一个特定会话保持使用有意义,但在会话之间不正确。但是,如果您正在处理Web服务API,那么问题就会大大减少。
EXTERNAL_ACCESS
Dispose()
所有可以浸渍的物体。DefaultConnectionLimit
的默认值为2,这可能不够,因为将在多个会话中访问相同的URI(对于给定的API调用)。关于SQL Server运行状况的一个问题是SQLCLR代码可能会锁定调度程序,以便在此一个进程完成之前它无法执行任何其他操作。这是因为SQL Server使用抢先式多任务处理,这需要线程让自己处于暂停状态。如果您的SQL Server代码执行查询,那么这不是问题,但如果它只是等待来自外部资源的响应,则存在这种可能性。我没有亲自看到调度程序被SQLCLR进程锁定,但它仍然是可能的,因此最好尝试“好玩”#34;与SQL Server。如果可以对API代码进行async
调用,那么您可以使用Timer每10或100毫秒(或类似的东西)调用Thread.Sleep(0);
,直到外部过程返回。调用Thread.Sleep(0);
是SQLCLR代码如何让SQLOS知道它(即SQLCLR进程)可以被置于保持状态。
在SQLCLR中执行任何类型的异步工作都需要将程序集标记为UNSAFE
。由于已经提到的各种其他原因,您的程序集很可能已被标记为UNSAFE
。但即使不是,那么如果这是将它们标记为UNSAFE
的唯一原因,那么它仍然值得,特别是这是一个内部项目。
有助于缓解与UNSAFE
SQLCLR代码(至少对于主SQL Server进程)相关的稳定性问题的一个选项是在单独的SQL Server实例中隔离它。例如,您可以运行单独的SQL Server Express实例,除了处理这些API调用之外什么都不做。只要指定允许SQL Server Express实例使用的Max Server Memory,内存泄漏就不会影响主SQL Server实例,只会影响Express实例。如果调度程序被长时间运行的外部进程锁定,那么它只会影响Express实例。
然后,您只需设置一个从主实例到Express实例的链接服务器,以便用户可以处理主实例并加入到那里的任何表等,
最后,从可用性的角度来看,考虑使用这些SQLCLR对象表值函数而不是存储过程。整合他们的结果会容易得多。您不仅可以加入,而且如果有人不想要整个结果集,则很容易添加WHERE
子句而不是将所有内容转储到临时表(通过{ {1}})仅删除不需要的行。
答案 1 :(得分:1)
这本身不是问题。根据您描述的内容执行将是可靠的。 “可靠”在某种意义上说,尽管这不是最佳实践,但它可以起作用而不会随机引起问题。
有些问题浮现在脑海:
这些问题都不仅仅因为它们的存在而破坏了实例的稳定性。这些都是完全正常的事情,只是放大了10分钟。
我不知道为什么有些评论如此激动。 10min查询在数据仓库中很常见,而这些查询使服务器处于100%负载下,这比等待的10分钟差。这里没问题。
如果您不同意,请发表评论说明原因。当您从SQL Server发出Web服务调用时,请说明完全导致问题。
答案 2 :(得分:-3)
使用正确的工具来完成正确的工作。在您的测试环境中,一切都会顺利运行,但只要您离开该环境并转向生产,您就会被炒掉。
作为主要数据存储的数据库应具有高可用性,而非资源密集型任务的数据库将始终快速增加,具体取决于所进行的并发连接数。在设计系统时请记住最终用户。