我公司使用的应用程序存在相当大的性能问题。我正在处理的数据库本身存在许多问题,但其中许多问题纯粹与应用程序相关。
在我的调查中,我发现有数百万个查询命中查询空表的 SQL Server 数据库。我们有大约 300 个空表,其中一些表每分钟查询高达 100-200 次。这些表格与我们的业务领域无关,本质上是原始应用程序的一部分,当供应商与我公司签约为我们生产软件解决方案时,供应商没有删除这些表格。
除了我们怀疑我们的应用程序错误日志中充斥着与此问题相关的错误之外,供应商向我们保证,对应用程序或数据库服务器的性能或稳定性没有影响。错误日志被淹没到我们看不到超过 2 分钟的错误来进行诊断的程度。
这些查询的实际成本在 CPU 周期等方面显然会很低。但是有人可以建议对 SQL Server 和应用程序的影响吗?我怀疑发送请求、确认请求、处理请求、返回请求以及应用程序确认接收的实际机制本身会对性能产生影响。
我们为该应用程序使用 SQL Server 2008 R2、Oracle Weblogic 11g。
@Frisbee-长话短说,我创建了一个包含查询文本的表,该表命中了应用程序数据库中的空表,然后查询它以查找我知道的所有空表名并得到一个很长的列表。最高命中率是在 30 天的正常运行时间内执行了 270 万次,请记住该应用程序通常在上午 8 点至下午 6 点使用,因此这些数字更集中于运行时间。多个表,多个查询,可能有些是通过连接相关的,有些不是。最高命中率(当时为 270 万)是从带有 where 子句的单个空表中进行的简单选择,没有连接。我希望连接到空表的更大查询可能包括对链接表的更新,但我会检查并尽快更新此问题。
更新:有 1000 个查询,执行次数在 1043 - 4622614 之间(超过 2.5 个月)。我将不得不深入挖掘以找出缓存计划的来源。这只是为了让您了解查询的范围。大多数都相当复杂,有超过 20 个连接。
@srutzky- 是的,我相信有一个日期列与计划的编制时间相关,所以我会感兴趣,所以我会检查一下。我想知道当 SQL Server 位于 VMware 集群上时,线程限制是否会成为一个因素?谢天谢地,很快就会成为专用的 Dell PE 730xD。
@Frisbee - 抱歉回复晚了。正如您所建议的,我使用 SQLQueryStress 在 24 个线程上从空表中运行了 select * 10,000 次(实际上是 240,000 次迭代)并立即达到 10,000 个批处理请求/秒。然后我在 24 个线程上减少到 1000 次并且达到每秒 4,000 个批处理请求。我还仅在 12 个线程上尝试了 10,000 次迭代(因此总迭代次数为 120000 次),这产生了持续的 6,505 批次/秒。对 CPU 的影响实际上很明显,在每次测试运行期间大约占总 CPU 使用率的 5-10%。网络等待可以忽略不计(比如我工作站上的客户端等待 3 毫秒),但 CPU 的影响肯定存在,就我而言,这是非常确定的。它似乎归结为 CPU 使用率和一些不必要的数据库文件 IO。每秒执行的总数略低于 3000,这比生产中的要多,但是我只测试了几十个这样的查询中的一个。因此,当涉及到 CPU 时间时,数百个查询以每分钟 300-4000 次的速度命中空表的净影响是不可忽略的。所有测试均针对具有双闪存阵列和 256GB RAM、12 个现代内核的闲置 PE 730xD 进行。
@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 上是否
发生异常即:当 Batches
/sec 图表上出现这些波谷时,SQLQueryStress 上发生异常,
连接数下降到 11,然后逐渐回升到 37当批次开始达到峰值并且没有发生异常时。非常非常有趣。
两个测试/实时实例上的最大连接数设置为默认值 0。
已检查应用程序日志,但找不到连接问题,但是,由于错误的数量和大小很大,因此只有几分钟的日志记录可用,即:大量堆栈跟踪错误。一位应用程序支持同事建议,大量 HTTP 错误的发生与连接有关。似乎基于此,由于某种原因,应用程序未正确汇集连接,结果,服务器反复耗尽连接。我会更多地查看应用程序日志。我想知道是否有一种方法可以证明这种情况发生在 SQL Server 端的生产环境中?
@srutzky- 谢谢。我明天会检查 weblogic 配置并更新。我在考虑仅仅 37 个连接——如果 SQLQueryStress 在 10,000 次迭代中执行 12 个线程 = 120,000 个非池化的选择语句,难道这不意味着每个选择都创建一个到 sql 实例的不同连接吗?
@srutzky- Weblogics 配置为连接池,因此它应该可以正常工作。连接池的配置如下,在 4 个负载平衡的 weblogics 中的每一个上:
- 初始容量:10
- 最大容量:50
- 最小容量:5
当我增加执行 select from empty table 查询的线程数时,连接数峰值约为 47。在禁用连接池的情况下,我始终看到较低的最大批处理请求/秒(从 10,000 下降到大约 400)。每次都会发生的是 SQLQueryStress 上的“异常”发生在 batches/sec 进入低谷后不久。它与连接性有关,但我不明白为什么会这样。当没有测试运行时,#connections 下降到大约 12。
禁用连接池后,我无法理解为什么会发生异常,但也许这是 Adam Machanic 的另一个 stackExchange 问题/问题?
@srutzky 我想知道为什么在没有启用池的情况下发生异常,即使 SQL Server 没有用完连接?
是的,甚至还有一些额外的因素,但如果不分析系统,就不可能说出这些因素中的任何一个实际影响您系统的程度。
话虽这么说,你问的是什么可能是一个问题,有一些事情要提,即使其中一些目前不是你特定情况的一个因素。你说:
可能还有更多,但这应该有助于了解事物。请记住,与大多数性能问题一样,这都是规模问题。如果每分钟被击中一次,上述所有项目都不是问题。这就像在您的工作站或开发数据库中测试更改:它总是只对表中的 10 - 100 行起作用。将该代码移至生产环境,运行需要 10 分钟,有人肯定会说:“好吧,它在我的盒子上运行”;-)。意思是,只是由于拨打的电话数量过多,您才会看到问题,但这就是存在的情况。
因此,即使有 100 万个无用的 0 行查询,也等于:
维护的连接越多,占用的内存就越多。您有多少未使用的物理 RAM?该内存将更好地用于运行查询和/或查询计划缓存。最坏的情况是您的物理内存不足并且 SQL Server 必须开始使用虚拟内存(交换),因为这会减慢速度(检查您的 SQL Server 错误日志以查看您是否收到有关内存被分页的消息)。
以防万一有人提到,“好吧,有连接池”。是的,这绝对有助于减少所需的连接数。但是,由于查询以每分钟多达 200 次的速度传入,因此存在大量并发活动,合法请求仍需要存在连接。执行 a
SELECT * FROM sys.dm_exec_connections;
以查看您维护的活动连接数。如果我在这里所说的没有错,那么在我看来,即使是小规模的,这也是对您系统的一种 DDoS 攻击,因为它正在用虚假请求淹没网络和您的 SQL Server ,防止真正的请求到达 SQL Server 或被 SQL Server 处理。
如果表格每分钟被点击 100-200 次,那么它们(希望)在内存中。服务器上的负载非常非常低。除非数据库服务器上有高 CPU 或内存,否则这可能不是问题。
是的,查询采用共享锁,但希望它们不会阻止任何更新锁,也不会被任何更新锁阻止。您是否对这些表进行了任何更新、插入或删除。如果不是,我会放手 - 如果您遇到性能问题,那么从数据库服务器的角度来看,必须有更大的鱼要炸。
我在一个空表上对 100,000 个 select count(*) 进行了测试,它在 32 秒内运行并且查询是通过网络进行的。所以 1/3 毫秒。除非您的网络超载,否则这甚至不会影响客户端。如果您遇到重大性能问题,这些 1/3 毫秒的空白查询并不是导致应用程序崩溃的原因。
这些可能只是左连接的一部分,用于获取一些不属于当前应用程序的静态类型数据。它可以与其他查询链接在一起,因此它不是额外的往返。如果是的话,它很草率,但它甚至不会造成更多的流量。
所以回头看看实际的陈述。您是否看到这些表有任何更新、添加或删除?
是的,许多空表和对空表的查询都表明编码草率。但是,如果您遇到重大性能问题,这不是原因,除非您还对这些表进行了一些非常草率的写操作。
通常在每个查询上完成以下步骤:
您提到的许多查询可能会给已经很重的系统带来额外的负载——连接、CPU、RAM 和 I/O 的额外负载。