缓冲池到底有多重要?

SEa*_*986 0 performance sql-server memory buffer-pool sql-server-2017

我一直在对新的(虚拟)服务器进行一些测试,以替换现有的生产服务器。我们怀疑当前的生产服务器规格过高,因此正在从低水平调整新服务器的虚拟组件(RAM、CPU 等),直到性能适合处理当前的工作负载。

虽然认识到新服务器处理现有服务器工作负载的能力的真正测试是针对新服务器测试该工作负载,但出于兴趣,我对现有服务器和新服务器进行了一些简单的、任意的测试:

  • 恢复数据库-读取速度
  • 备份数据库-写入速度
  • 大型数据库上的 DBCC CHECKDB - 花费的时间

(两台服务器上使用相同的数据库备份,以使上述所有测试保持一致)

以上所有内容都支持新服务器(更快的读写速度、更快的 CHECKDB)

我做的最后一个基本测试是测试执行一个简单的操作所需的时间SELECT *在冷缓存和热缓存上最大的表之一上执行简单操作所需的时间,以进一步了解读取速度。

测试代码如下,我在两台服务器上运行

USE StackOverflow

SET STATISTICS IO, TIME ON

CHECKPOINT

DBCC DROPCLEANBUFFERS

SELECT * FROM Users  /* cold cache run */
SELECT * FROM Users  /* warm cache run */
Run Code Online (Sandbox Code Playgroud)

统计IO如下:

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 12 ms.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

 SQL Server Execution Times:
   CPU time = 62 ms,  elapsed time = 266 ms.

(14080580 rows affected)
Table 'Users'. Scan count 1, logical reads 250190, physical reads 1, page server reads 0, read-ahead reads 250200, page server read-ahead reads 0, lob logical reads 1387, lob physical reads 58, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 24047 ms,  elapsed time = 508456 ms.

(14080580 rows affected)
Table 'Users'. Scan count 1, logical reads 250190, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 1385, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 23297 ms,  elapsed time = 478627 ms.
Run Code Online (Sandbox Code Playgroud)

我的两台服务器上的结果相似,但令我震惊的是,从磁盘读取而不是从 RAM 读取时,经过的时间仅慢了 30 秒。

我对 SQL Server 将所有内容读入缓冲池的理解是 RAM 比磁盘快 - 在本次测试中,RAM 仅快 6%。

基于上述,如果我的“现实生活”查询从缓存中读取需要 2000 毫秒,那么从 RAM 中读取数据需要 3200 毫秒。可以说,这并不是一个明显的差异。

那么,为什么我们要竭尽全力确保数据,并确保服务器有尽可能多的 RAM 来缓存数据,而数据速度似乎只提高了 6%?

我的问题是故意开玩笑的,因为我觉得我在这里忽略了一些东西,并且我很欣赏我的测试本质上非常简单。

对我所忽视的事情的思考:

  • 如果数据位于 RAM 中,繁忙服务器上的磁盘争用就会减少
  • 我很欣赏 RAM 在 SQL Server 中用于其他用途而不仅仅是缓冲池
  • SQL Server 可能从早期就拥有这种架构,当时磁盘比现代 SSD 慢得多

Joe*_*ish 10

您运行的用于测量冷缓存和热缓存差异的测试查询将花费大部分执行时间等待ASYNC_NETWORK_IO。在您的情况下,将 1400 万行发送到 SSMS 可能需要大约 450 秒。如果减去等待超时,您可能会发现冷缓存查询花费的时间大约是热缓存查询的两倍。

\n

SQL Server 还有各种减少 I/O 等待时间的技巧。其中一个技巧是预读。您运行的查询类型可能会从预读中受益匪浅。几乎所有的 I/O 都是通过预读机制完成的:

\n
\n

预读读数 250200

\n
\n

并非所有查询都能从预读中获得如此大的优势。我碰巧写了一篇最近的博客文章,其中有一个由于 I/O 等待而导致查询性能非常差的示例。复制相关部分:

\n
\n

在我的机器上执行存储过程[使用 FAST_FORWARD 选项]大约需要 2 毫秒。

\n

...

\n

遗憾的是,如果我删除 FAST_FORWARD 选项,则代码需要 50 秒才能在我的计算机上执行。是什么导致了运行时的巨大\n差异?

\n

...

\n

对于游标执行,\xe2\x80\x99 不会预读查询所需 I/O 的 95%。当您必须使用 DOP 1 查询执行 240000 次 I/O 时,即使是亚毫秒 I/O 延迟也可能会很痛苦。总之,\nFAST_FORWARD 游标能够使用索引有效地查找\n20 个匹配行。使用默认选项的游标执行大约 15 GB 的\nI/O,\xe2\x80\x99s 不适合预读。

\n
\n

回到您的系统,您可以考虑COUNT_BIG(*)针对表发出 a 。这将把客户端的等待时间减少到几乎为零,并且更直接地向您展示热缓存和冷缓存之间的区别。如果您想在新服务器上测试 I/O 而没有预读的好处,您可以尝试运行本博客文章中提到的演示代码中提到的演示代码:

\n
use tempdb;\n \nCREATE TABLE #outer (\n    ID BIGINT IDENTITY(1, 1) NOT NULL,\n    DUMMY BIGINT NOT NULL,\n    PRIMARY KEY (ID)\n);\nINSERT INTO #outer (DUMMY)\nSELECT TOP (130000) 0\nFROM master..spt_values t1\nCROSS JOIN master..spt_values t2;\nCREATE TABLE #inner (\n    ID BIGINT IDENTITY(1, 1) NOT NULL,\n    BIG_DUMMY CHAR(5000) NOT NULL,\n    PRIMARY KEY (ID)\n);\nINSERT INTO #inner (BIG_DUMMY)\nSELECT TOP (130000) \'0\'\nFROM master..spt_values t1\nCROSS JOIN master..spt_values t2;\n\nCHECKPOINT;\nDBCC DROPCLEANBUFFERS;\n \nSELECT COUNT_BIG(*)\nFROM #outer o\nWHERE o.DUMMY = 1\nOR EXISTS (\n    SELECT 1\n    FROM #inner i\n    WHERE i.ID = o.ID\n)\nOPTION (MAXDOP 1, QueryRuleOff BuildSpool);\n
Run Code Online (Sandbox Code Playgroud)\n