某些 SQL 查询在 ESXI 托管环境中性能很差

Blu*_*kMN 5 virtualization performance sql-server vmware-esxi

我们最近设置了一台带有 8 个双核 CPU、20 GB RAM 和 3 个 1 TB 驱动器的新机器,这些驱动器设置在某种 RAID 中,导致我们实际使用了 2 个 1 TB 驱动器(我不是硬件人在这里)。它被设置为 ESXi 主机,我们在其中设置了许多测试环境。当前的测试在带有 SQL Server 2005 Standard 64 位 SP3 的 Windows 2003 64 位上运行。从所有报告来看,该系统应该承载的环境比我们之前的设置表现更好,但某些任务的表现却差得多。我发现了一个特定的 SQL 脚本,它在某些条件下可靠地运行得很慢,我无法理解。SQL 脚本是由 1700 多个 UPDATE 语句组成的简单系列,其开头如下所示:

UPDATE SrfItem SET fkSrfItem = 5 WHERE id = 4
UPDATE SrfItem SET fkSrfItem = 8 WHERE id = 7
UPDATE SrfItem SET fkSrfItem = 10 WHERE id = 9
Run Code Online (Sandbox Code Playgroud)

我发现如果我在这些虚拟环境之一中遵循以下过程,运行脚本需要 9-12 秒:

测试用例#1

  1. 从虚拟 SQL Server 环境中的备份还原测试数据库
  2. 本地连接数据库
  3. 运行脚本 - 这一步需要 9 秒

在我的桌面上,相同的过程在不到 1 秒的时间内运行了第 3 步。

测试用例#2

  1. 从物理 SQL Server 环境中的备份还原测试数据库
  2. 本地连接数据库
  3. 运行脚本——这一步不到 1 秒

但是在事务中运行脚本很快

测试用例 #3

  1. 从虚拟 SQL Server 环境中的备份还原测试数据库
  2. 本地连接数据库
  3. 在脚本开头添加“BEGIN TRAN”
  4. 在脚本末尾添加“COMMIT TRAN”
  5. 运行脚本 - 这一步不到 1 秒

我觉得有趣的是,即使我在事务中执行一次并回滚它,它仍然运行缓慢

测试用例 #4

  1. 从虚拟 SQL Server 环境中的备份还原测试数据库
  2. 本地连接数据库
  3. 在脚本开头添加“BEGIN TRAN”
  4. 在脚本末尾添加“ROLLBACK TRAN”
  5. 运行脚本 - 这一步不到 1 秒
  6. 只执行脚本中不包含交易的部分——这一步需要 9 秒。

我已经在具有 Windows 2003 32 位和 SQL 2005 32 位及以上的虚拟系统以及具有 Windows 2008 64 位和 SQL 2008 64 位的虚拟系统上运行了测试。我已经在运行 Windows 2003 和 SQL 2005 的物理系统以及运行 Windows 7 64 位和 SQL 2008 R2 64 位的物理系统上运行了测试。我尝试过的所有虚拟系统都表现出这种缓慢,并且都托管在新的 ESXi 环境中。所有物理系统都没有表现出这种缓慢。

谁能帮我理解这里发生了什么?我担心类似的性能问题会影响其他领域,我们应该在主机或来宾环境中重新配置一些东西。到目前为止,我们唯一能想到的就是关闭主机 BIOS 中的超线程,以匹配另一个虚拟环境及其主机的配置,在那里我们无法看到缓慢的行为(我没有观察速度不慢的另一个虚拟环境和主机)。这会造成如此大的性能差异吗?

编辑:在对我的问题和第一个答案进行了一些审查后,我同意我设法证明的可能是物理和虚拟环境之间 I/O 延迟性能的差异。我也意识到我应该提供一些其他细节:这些图像使用精简配置,并且在它们下面有两个或三个快照。这会如此显着地影响该统计数据吗?现在的问题是,这个统计数据在虚拟环境和物理环境之间存在如此巨大的差异是否正常?我是否应该能够在环境或 SQL 配置中对其进行优化,还是取决于软件本身为具有极端 I/O 延迟的虚拟系统编写更优化的代码?

vSphere 客户端报告虚拟磁盘上的写入延迟为 11 到 40 毫秒,平均为 21 毫秒。这是一个有用的统计数据吗?那是极端吗?

编辑: 似乎我们的硬件 (DL380 G6) 存在性能问题,如http://laez.nl/vmware-bad-performance-on-hp-proliant-dl380-g6-with-esxi-3-5-u4 所述/并且我们只需要进行一些重新配置即可提高性能。我会接受使我们朝着正确方向看到磁盘 I/O 延迟是问题的答案。

kub*_*zyk 5

总结:

  • 在您的真实服务器上,您可以在不到一秒的时间内进行 1700 次表更新 + 1700 次提交,
  • 在您的虚拟服务器上,您可以在 9 秒内进行 1700 次表更新 + 1700 次提交,
  • 在您的虚拟服务器上,您可以在不到一秒的时间内进行 1700 次表更新 + 1 次提交。

因此,在我看来,您的问题可以重新定义为“在真实服务器上,我可以在不到一秒的时间内进行 1700 次提交,但在我的虚拟服务器上性能下降了十倍”。

1700 次表更新和 1700 次提交有什么区别?表更新完全缓存,完全不依赖于磁盘 I/O。对于提交,这是完全不同的。根据事务数据库的本质,在开始提交下一个事务之前,数据库引擎必须确保提交实际上保存到磁盘(保存到日志文件)。因此,对于这 1700 次提交中的每一次,它都必须等待整个 I/O 往返。综上所述,在您的场景中,I/O 的延迟起着非常重要的作用,应该对其进行分析(不要将延迟与 I/O 速率或以字节为单位的吞吐量混淆;这三个是完全不同的动物;它们是总是单独调谐)。

使用 IOMeter 测试您的存储是一个很好的计划。它在启动时挂起,因为它试图用它的测试文件填满整个磁盘。只需等到文件增长到相当大的数量并重新启动IOMeter,它就会与“不完整”的测试文件一起正常工作。