应用程序查询空表


10

我公司使用的应用程序存在很大的性能问题。我正在研究数据库本身存在许多问题,但是许多问题纯粹与应用程序有关。

在调查中,我发现有数百万个查询命中SQL Server数据库,查询空表。我们大约有300个空表,其中一些表每分钟最多查询100-200次。这些表与我们的业务领域无关,实际上是原始应用程序的一部分,当我的公司与他们签约为我们提供软件解决方案时,供应商并未删除这些原始应用程序。

除了我们怀疑应用程序错误日志中充斥着与此问题相关的错误以外,供应商还向我们保证,应用程序或数据库服务器不会对性能或稳定性造成影响。错误日志泛滥成灾,以至于我们看不到价值超过2分钟的错误来进行诊断。

这些查询的实际成本显然会在CPU周期等方面很低。但是,谁能说出对SQL Server和应用程序有什么影响呢?我怀疑发送请求,确认请求,处理请求,返回请求以及确认应用程序已收到请求的实际机制本身会对性能产生影响。

我们将SQL Server 2008 R2,Oracle Weblogic 11g用于该应用程序。

@ Frisbee-长话短说,我创建了一个包含querytext的表,该表命中了应用程序数据库中的空表,然后对其查询以获取我知道为空的所有表名,并得到了很长的列表。考虑到该应用通常在上午8点至下午6点使用,因此在30天的正常运行时间中,执行次数最高的是270万次执行,因此这些数字更多地集中在运营时间。多个表,多个查询,可能有些通过联接释放,有些则没有。命中率最高(当时为270万)是从一个带有where子句,无联接的空表中进行的简单选择。我希望连接到空表的较大查询可能包括对链接表的更新,但是我将检查并尽快更新此问题。

更新:有1000个查询,执行计数在1043-4622614之间(超过2.5个月)。我将不得不挖掘更多信息以找出缓存计划的产生时间。这只是为了让您了解查询的范围。大多数都相当复杂,有20多个连接。

@ srutzky-是的,我相信会有一个与计划编制时间相关的日期栏,因此您将对此感兴趣,因此我将对其进行检查。我想知道,当SQL Server位于VMware群集上时,线程限制是否会成为一个因素?值得庆幸的是,即将成为专用的Dell PE 730xD。

@Frisbee-对不起,您的回复很晚。正如您所建议的,我使用SQLQueryStress在空表中对24个线程运行了10,000次select *(实际上是240,000次迭代),并立即达到10,000个批处理请求/秒。然后,我在24个线程中减少了1000次,并达到了4,000个批处理请求/秒以下。我还仅在12个线程上尝试了10,000次迭代(因此总共进行了120000次迭代),这产生了持续的6,505批/秒。实际上,对CPU的影响非常明显,在每次测试运行期间,约占CPU总使用量的5-10%。网络等待时间可以忽略不计(例如,工作站上的客户端需要3毫秒),但是对CPU的影响是肯定的,就我而言,这是非常确定的。这似乎归结为CPU使用率和一些不必要的数据库文件IO。每秒总执行次数约为3000次,这比生产中的要多,但是我只测试了数十个这样的查询之一。数百个查询以每分钟300-4000次之间的速率命中空表的最终结果在CPU时间方面不可忽略。所有测试都是针对具有双闪存阵列和256GB RAM,12个现代内核的空闲PE 730xD进行的。 这是SQLSentry的输出

@ srutzky-好主意。默认情况下,SQLQueryStress似乎使用连接池,但是无论如何,我发现,是的,连接池复选框已选中。更新以跟随

@ srutzky-应用程序上的连接池显然未启用-如果已启用,则无法使用。我进行了探查器跟踪,发现对于审计登录事件,连接具有EventSubClass“ 1-Nonpooled”。

RE:连接池-检查了weblogics,发现启用了连接池。针对活着的发现更多痕迹,发现池化迹象没有正确/根本没有: 在此处输入图片说明

这是当我对填充的表没有连接的情况下运行单个查询时的样子。异常显示为“与SQL Server建立连接时发生与网络有关或特定于实例的错误。找不到服务器或无法访问该服务器。请验证实例名称正确并且已将SQL Server配置为允许远程连接。 (提供程序:命名管道提供程序,错误:40-无法打开与SQL Server的连接)“请注意批处理请求计数器。在生成异常的时间内对服务器执行ping操作会成功执行ping响应。

在此处输入图片说明

更新-两次连续的测试运行,相同的工作量(select * fromEmptyTable),启用/未启用池。CPU使用率略高,故障很多,并且从未超过500个批处理请求/秒。测试显示10,000个批处理/秒,并且在启用池的情况下没有失败,大约400个批处理/秒,然后由于禁用了池而导致很多失败。我想知道这些故障是否与连接可用性不足有关?

在此处输入图片说明

@srutzky-从sys.dm_exec_connections中选择Count(*);

  • 启用池化:即使在负载测试停止后也始终保持37

  • 禁用池化:11-37,具体取决于是否
    在SQLQueryStress 上发生异常,即:当这些低谷出现在Batchs
    / sec图上时,在SQLQueryStress上发生异常,并且
    连接数下降到11,然后逐渐恢复到37当批次开始达到高峰且未发生异常时。非常非常有趣。

两个测试/活动实例上的最大连接数设置为默认值0。

已经检查了应用程序日志并且找不到连接问题,但是由于错误的数量和大小(即:大量的堆栈跟踪错误),只有几分钟的可用日志记录可用。应用程序支持的一位同事建议,发生大量与连接有关的HTTP错误。似乎基于此,由于某种原因,应用程序无法正确地建立连接池,结果服务器反复耗尽连接。我将进一步研究应用日志。我想知道是否有办法从SQL Server方面证明这种情况正在生产中发生?

@ srutzky-谢谢。我明天将检查weblogic配置并进行更新。我只是在考虑仅37个连接-如果SQLQueryStress在10,000次迭代中执行12个线程= 120,000个非池选择语句,那是否不应该意味着每个选择都将创建一个与sql实例的不同连接?

@ srutzky-将Weblogics配置为缓冲连接,因此它应该可以正常工作。在4个负载平衡的weblogic的每一个上,连接池都是这样配置的:

  • 初始容量:10
  • 最大容量:50
  • 最小容量:5

当我增加执行从空表查询中执行选择的线程数时,连接数将达到47左右。在禁用连接池的情况下,我始终看到较低的最大批处理请求数/秒(从10,000降低到大约400)。每次将发生的情况是,SQLQueryStress上的“异常”在批处理/秒进入低谷后不久发生。它与连通性有关,但我无法确切说明为什么会这样。当没有测试在运行时,#connections下降到大约12。

在禁用连接池的情况下,我很难理解为什么会发生异常,但是也许这是Adam Machanic的其他所有stackExchange问​​题?

@srutzky我想知道为什么即使SQL Server没有用尽连接,异常也会在没有启用池的情况下发生?


1
Peter,考虑到有关连接池的最新更新,您现在似乎需要使用SQLQueryStress重新运行测试,但必须关闭 Connection Pooling 。这将更准确地反映应用程序的工作方式,我相信它将显示CPU使用率甚至RAM使用率的增加。
所罗门·鲁兹基

1
彼得,您是否为服务器设置了最大连接数?我猜想如果没有池,您将遇到连接过多的问题。我不知道您的应用程序是否曾经遇到该错误。另外,如果可以再运行一次最后一次测试(启用和不启用缓冲池),则在针对这两种配置中的每一种进行测试时,请运行a SELECT COUNT(*) FROM sys.dm_exec_connections;以查看启用缓冲池或启用缓冲池之间的值是否有很大差异。不。基于这些错误,我认为禁用池后会有更多连接。
所罗门·鲁兹基

1
彼得,与37个联络人的人数似乎太少了。假设连接限制设置为0(即无限),系统内存是否绑定?此外,默认情况下,连接池应处于打开状态,但由客户端控制。该应用程序是.NET应用程序吗?不必为了使用连接池而已,但是有助于了解原因以找到原因。您可以看到正在使用的连接字符串吗?它指定Pooling=false还是Max Pool Size
所罗门·鲁兹基

1
彼得,每个查询12个线程中的每个线程都按顺序创建自己的连接,每次迭代10k。因此,无需缓冲,只要代码关闭连接,连接就可以销毁。池化将保持连接状态以供重复使用。因此,使用池时连接数保持一致是有意义的。不知道为什么37没有更多信息。没有测试在运行时有多少个连接?回退该数字将更好地表明测试创建了多少个。
所罗门·鲁兹基

1
连接池是按客户端而不是服务器维护的。因此,WebLogics和SQLQueryStress都应具有自己的连接池(就min_pool和max_pool大小而言)。关于“禁用连接池,我看到较低的最大批处理请求数/秒”:这是有道理的,因为从应用程序进行的每个连接都需要更多时间来验证和初始化会话等。这正是存在连接池的原因:- )。
所罗门·鲁兹基

Answers:


7

我怀疑发送请求,确认请求,处理请求,返回请求以及确认应用程序已收到请求的实际机制本身会对性能产生影响。

是的,甚至还有一些其他因素,但是如果不分析系统,这些因素实际上会在多大程度上影响您的系统。

话虽这么说,您正在询问可能是个问题,尽管其中某些因素当前并不是您的特定情况的考虑因素,但仍有一些事情要提及。你说:

我们大约有300个空表,其中一些表每分钟最多查询100-200次。

  • 未查询的空表不是问题。但是我想您可能还意味着它们都在被查询,只是其中一些遭受的打击比其他严重得多。
  • 如果提交的查询文本在调用之间保持不变,那么查询解析和执行计划的生成就不会成为问题。SQL Server将对查询的文本进行哈希处理,然后在计划缓存中查找它。如果找到,则它将不再执行解析或编译步骤(直到从缓存中删除计划)。
  • 任何表,无论是空表还是非空表,都将至少需要一个“共享”锁来指示正在使用资源。这样可以防止需要排他锁的操作(添加/更改/删除列等)在资源使用期间进行更改。锁定和解锁(即使由于没有数据而在不到1毫秒的时间内完成)仍然需要系统资源(内存和CPU)来管理那些锁定操作。
  • 即使没有结果集从SQL Server返回到应用程序,无论查询是否产生结果,仍然有相同数量的网络流量流向SQL Server。查询的文本或存储过程的名称需要发送。即使没有结果返回,SQL Server仍然必须发送一些包含结果集结构的网络数据包,这些数据包除了告诉客户端结果集正在启动(即使未找到行)然后告诉结果集是结束,应该关闭。并且可能还有来自打印语句和/或行计数的其他消息。
  • 连接到SQL Server需要一定数量的系统资源。它需要CPU和内存来处理身份验证(以及来回的网络数据包),这也需要时间。这就是存在连接池的原因:减少此费用。
  • 即使使用连接池减少了系统资源的使用,SQL Server仍然需要维护那些连接,并且这需要内存和最少的CPU。
  • 即使没有行,因此执行时间也短,查询仍然被执行。即使有10或10,000行,并且由于它们被频繁使用而从缓冲池(即内存)中拉出,它们仍然需要一个线程来完成。在这个无用的查询上工作的线程不在实际的有用查询上工作。

甚至可能更多,但这应该有助于您了解事物。并且请记住,与大多数性能问题一样,这都是规模问题。如果上述所有项目每分钟被击中一次,则均为非问题。这就像在您的工作站或开发数据库中测试更改一样:表中始终仅处理10至100行。将该代码移至生产环境,需要10分钟才能运行,肯定有人会说:“好吧,它可以在我的盒子上工作” ;-)。意思是,仅由于发出大量呼叫,您才看到问题,但这就是存在的情况。

因此,即使是一百万无用的,0行的查询,也等于:

  • 额外的200万次锁定操作(每个锁定都必须​​解锁,对吗?)。这主要是花费在无用的操作而不是有用的操作上的时间成本。
  • 更多的网络流量可能使您更趋近饱和(不确定这种可能性有多大,但仍然如此)
  • 维护更多的连接会占用更多的内存。您有多少未使用的物理RAM?该内存将更适合用于运行查询和/或查询计划缓存。最糟糕的情况是您的物理内存已用完,并且SQL Server必须开始使用虚拟内存(交换),因为这会减慢速度(检查SQL Server错误日志以查看是否收到有关分页内存的消息)。

    并且以防万一有人提到“好,这里有连接池”。是的,这绝对有助于减少所需的连接数。但是,由于查询每分钟最多进行200次,因此存在大量并发活动,对于合法请求仍然需要存在连接。请执行一次SELECT * FROM sys.dm_exec_connections;以查看您要维护多少个活动连接。

  • 不管其他任何事情,每天仍然至少有100万次不存在本来可以做有用的事情的线程。

如果我对此处所说的内容不正确,那么在我看来,即使规模很小,这也是对系统的一种DDoS攻击,因为它用虚假的请求淹没了网络和SQL Server。 ,防止实际请求到达SQL Server或被SQL Server处理。


1

如果表每分钟被命中100-200次,则它们(希望)在内存中。服务器上的负载非常低。除非数据库服务器上的CPU或内存高,否则这可能不是问题。

是的,查询使用共享锁,但希望它们不会阻止任何更新锁,也不会被任何更新锁阻止。您在这些表上有任何更新,插入或删除吗?如果不是这样,我就放任不管了-如果您遇到性能问题,那么从数据库服务器的角度来看,就不得不炸大鱼。

我在一个空表上对100,000个select count(*)进行了测试,它在32秒内运行,查询通过网络进行。所以1/3毫秒。除非您的网络过载,否则这甚至都不会影响客户端。如果您遇到主要的性能问题,那么这些1/3毫秒的空白查询并不是导致该应用终止的原因。

这些可能只是获取某些静态类型数据的左联接的一部分,而并非当前应用程序的一部分。它可以与其他查询链接在一起,因此这不是额外的往返。如果是这样,那是草率的,但是甚至不会引起更多的流量。

所以回头看看实际的陈述。您在这些表上看到任何更新,添加或删除吗?

是的,许多空表和对空表的查询都表示草率的编码。但是,如果遇到主要的性能问题,这不是问题的根源,除非您对这些表进行了一些非常草率的写操作。


当您进行100k查询测试时,SQL Server上还有多少其他用户正在运行查询?我并不是说我是对的,而你是错的,但是,如果您是系统上的唯一一员,或者是少数几个,那么自然不会有太大影响。锁定的问题不是阻塞的问题,这仅仅是SQL Server锁定和解锁这些数据页所需的资源的问题,即使它们始终位于缓冲池中也是如此。仍在完成工作。调度程序不是无限的。
所罗门·鲁兹基

我并不是说你错了。不管是否是其他用户,它仍然是花费了多长时间和资源的有效度量标准规定的负载为每分钟100-200。在30秒内来自一个客户端的100,000个负载将超出该负载200到400倍。如果没有更新锁,则来自一个客户端或100个更新锁没有影响。您的答案假设存在网络过载或SQL服务器,并且基于您不知道的问题。如果这是DDoS攻击,则可能会超过100 /秒(不是分钟),并且不会针对空表。
狗仔队2015年

是的,根据我们对这个问题的了解不够,无法缩小范围,这就是为什么我要说这些情况可能会因情况而异。而DDoS只是一个类比,主要是基于原始问题的措辞,这暗示着有几个人以这种速度受到打击,还有许多其他人也以较少的频率受到打击。
所罗门·鲁兹基

从第一段很好地总结这一点来看,我认为这是一个有价值的答案:“除非您在数据库服务器上拥有很高的CPU或内存,否则这很可能不是问题。” 在我们的情况下,我们确实在一天中的某些时间使用了较高的cpu,因此根据我的测试,额外的cpu压力似乎确实是一个因素。
彼得

值得注意的是,我仅引用执行100-200次/分钟的查询,而实际上对这些空表有大约50个查询,执行计数在200-4000 /分钟之间。累积地,以这种频率查询空表的效果确实会极大地影响CPU,即使在非参数查询重复执行的最佳情况下,计划,数据等也都存储在内存中。
彼得

0

通常,对每个查询执行以下步骤:

  1. 来自申请的请求。
  2. 数据库解析查询。
  3. 数据库引擎检查此查询是否已存储在RAM中。使用执行计划(如果内存中存在)。
  4. 如果RAM中不存在该数据库,则数据库引擎将检查查询中有关对象的现有统计信息,并确定执行计划。
  5. 运行执行计划,使用I / O从磁盘获取数据。
  6. 对申请的回应。

您提到的许多查询可能会给已经很重的系统带来额外的负载-连接,CPU,RAM和I / O的额外负载。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.