SQL Server DB 一夜之间变得无法使用

Bob*_*way 9 sql-server sql-server-2008-r2

昨天,我的 SQL Server 数据库很好。今天它几乎无法使用 - 它的速度减慢了五到二十倍,具体取决于我何时击中它。

一些数据是在夜间加载过程中添加到服务器的,但没有什么能比得上对数据库产生如此大影响的卷。大约 50,000 条纯文本记录(没有 XML 或其他花哨的东西)。

在我们重新启动服务器之前,今天早上打了补丁。但是,我们其他也打过补丁的数据库服务器的行为都没有不同。

资源监视器似乎表明它的磁盘 IO 有问题。它始终以接近 100% 的容量运行 .mdf 文件,即使数据库中实际发生的事情不多。对 Templog.ldf 的访问也非常频繁。

这里没有专家 DBA(我们都是具有不同 SQL 技能的开发人员),我们都对发生的事情感到困惑。我们尝试运行 sp_updatestats 并将一些大索引移动到不同的磁盘,但无济于事。

我认为这一定与补丁有关 - 这似乎太巧合了。一位同事确信是数据负载导致 mdf 的大小增加到导致执行计划效率低下的程度。

这到底是什么造成的?我们如何才能找到,我们可以做些什么来解决它?

编辑:

使用sp_WhoIsActive没有发现任何异常。它记录了我自己对 sproc 的使用以及来自当前正在尝试移动另一个索引的同事的一些命令。这可能现在阻止了数据库,但它之前的运行情况一样糟糕。

它是 SQL Server 2008 R2 的标准版本。SELECT @@VERSION给出:

Microsoft SQL Server 2008 R2 (SP2) - 10.50.4033.0 (X64)
2014 年 7 月 9 日 16:04:25
版权所有 (c) Microsoft Corporation 标准版(64 位),Windows NT 6.1(内部版本 7601:Service Pack 1)(管理程序) )

该服务器具有 72GB 的 RAM 和三个四核 2GHz 处理器。

修补程序仅适用于 Windows。除了补丁之外没有其他变化。

选择的设置:

_id     name                        value   minimum     maximum     value_in_use    description                                 is_dynamic  is_advanced
1540    min memory per query (KB)   1024    512         2147483647  1024            minimum memory per query (kBytes)           1           1
1541    query wait (s)              -1      -1          2147483647  -1              maximum time to wait for query memory (s)   1           1
1543    min server memory (MB)      0       0           2147483647  16              Minimum size of server memory (MB)          1           1
1544    max server memory (MB)      65536   16          2147483647  65536           Maximum size of server memory (MB)          1           1
Run Code Online (Sandbox Code Playgroud)

更新:将索引和表转移到不同的磁盘分区似乎正在改进。我仍然对我们如何以如此剧烈的结果如此突然地达到临界点感到困惑。

Ion*_*nic 3

少量数据可能会达到 SQL Server 中的某个限制,从而强制实施另一个计划或类似的情况。这并非不可能。但事实上,你的光盘似乎负荷过重,这让我得出了另一个结论。

\n

导致速度变慢的可能有两个基本原因。

\n
    \n
  1. 您升级了系统并重新启动了它
  2. \n
  3. 你在里面加载一堆数据
  4. \n
\n

我们来看看第 1 部分

\n

您的 SQL Server 配置可能已损坏。这可能会导致服务器速度和光盘使用方面的严重问题。

\n

请首先检查您的基本服务器设置。这些基本设置是max server memoryaffinity I/O maskaffinity maskmax degree of parallelism。您可能需要使用启用高级选项show advanced options

\n

这是一个完整的脚本:

\n
-- enable advanced options\nEXEC sp_configure 'show advanced options',1\n-- apply configuration\nRECONFIGURE\n-- how much memory can the sql server allocate?\nEXEC sp_configure 'max server memory'\n-- which cpu is used to run I/O operations\nEXEC sp_configure 'affinity I/O mask'\n-- which cpus can run processes?\nEXEC sp_configure 'affinity mask'\n-- how many threads can work on one query part?\nEXEC sp_configure 'max degree of parallelism'\n
Run Code Online (Sandbox Code Playgroud)\n

将结果与安装步骤中记录的值进行比较。他们还是一样吗?

\n

您的服务器表现如此奇怪的原因可能有很多。我通常会打赌,你的max server memory是错的。这将导致您的 SQL Server 永久交换数据页。他无法将一切都记在记忆里。这意味着他需要从光盘读取页面,更新它,然后立即写回。如果另一个更新出现并使用同一页面进行更新,则无法从内存中读取它。相反,服务器需要从光盘中再次读取它。只是交换...

\n

另一个问题可能是磁盘或进程的亲和力太高。如果您使用带有 SQL Server 专用光盘的共享服务器(SQL Server + 其他服务)(这种情况可能很少见,但也有可能),这可能是您的问题。例如,您的服务器通常有 3 个用于进程的 cpu,1 个用于 I/O。另外 12 个 cpu 用于其他服务。在这种情况下,您的关联掩码是错误的,并且使用例如自动配置。这意味着您的服务器动态使用所有 16 个内核进行进程和 I/O。如果您正在运行巨大的进程,它们可能会给光盘带来巨大的负载,而光盘可能无法处理。但事实上,我不相信这是你的情况。如果适用的话,速度会更快(即使只是一点点),但你的情况会变慢。

\n

另一个问题可能是并行度太高。这意味着在查询的一部分上有太多空闲线程。如果并行性没有按预期工作,这也可能会导致速度大幅减慢。但这并不能全面描述您的高 I/O。

\n

现在我们也来看看第 2 部分

\n

您将一堆行加载到系统中。即使这是一项常规作业,它也可能会提高查询计划升级的限制。甚至您的插入与 SQL Server 结合使用也可能会产生这种行为。

\n

Y\xce\xbfu 提到您已经尝试将索引迁移到另一张光盘,这似乎有帮助。这可能是由于您将负载分配到两个不同的磁盘上而发生的。

\n

可能是你的指数被破坏了,你的计划被破坏了,或者你的统计数据已经过时了。

\n

1. 让我们检查统计信息的最后更新\n您可以通过界面为每个统计元素手动执行此操作。这会很痛苦。或者您可以尝试以下代码:

\n
SELECT name AS indexname,\nSTATS_DATE(OBJECT_ID, index_id) AS StatsUpdated\nFROM sys.indexes\n
Run Code Online (Sandbox Code Playgroud)\n

这将为您提供每个索引(和堆)及其背后的统计信息的完整信息。即使运行sp_updatestats也不意味着统计数据已更新。更新的部分非常棘手,即使运行sp_updatestats或者auto update statistics启用,统计信息也不会及时更新。当需要/生成更新时,以下是一些边缘点:

\n
    \n
  • 空表获取一行或多行
  • \n
  • 超过 500 行的表更新了 20% + 500 额外行,然后发生了插入
  • \n
  • 当在包含少于 500 行的表中更改 500 行时
  • \n
\n

这意味着,即使您运行更新,您的统计数据也可能已过时。

\n

您可以看一下上面的查询。如果您在某些表中发现一些相当旧的统计信息,您可能需要为此表运行手动统计更新:

\n
UPDATE STATISTICS dbo.YourBadTable WITH FULLSCAN\n
Run Code Online (Sandbox Code Playgroud)\n

之后,你可能想狠狠地踢你的服务器,扔掉所有旧的计划。

\n
DBCC FREEPROCCACHE \n
Run Code Online (Sandbox Code Playgroud)\n

如果您只想清理所有缓存,您可能需要运行以下命令:

\n
DBCC FREESYSTEMCACHE ('ALL')\n
Run Code Online (Sandbox Code Playgroud)\n

这将清理所有缓存,而不仅仅是计划缓存。我通常会警告,在生产阶段的生产服务器上使用它。但由于你的服务器目前无法工作,你不能对他们造成太大伤害。它可能会减慢几秒钟,也许是 1-2 分钟,因为他需要重建所有缓存,但之后他应该以正确的计划运行。

\n

另一个原因可能是索引完全分散。可以使用以下语句在整个服务器上检查这一点:

\n
SELECT * \nFROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, NULL)\n
Run Code Online (Sandbox Code Playgroud)\n

如果碎片非常高,您可能需要重新组织(碎片< 20%)或完全重建(> 20%)。这可能会给椎间盘带来更大的压力并造成麻烦。另一方面,如果指数那么糟糕,最终可能利大于弊。

\n

除了这两个原因之外,还可能存在第三个问题

\n

可能你的服务器已经配置好了,这次你没有改变任何代码,只是添加了几行。所有统计数据均已更新,所有缓存均已重建。您的所有索引都按照您需要的方式重新组织,但仍然不起作用。可能只是您达到了进程中可用内存的限制。也许你需要更多。您可以简单地检查是否有任何进程试图获取比您拥有的内存更多的内存。

\n

您可以使用以下命令检查这一点:

\n
SELECT * FROM sys.dm_exec_query_memory_grants\n
Run Code Online (Sandbox Code Playgroud)\n

它将为您提供消耗内存的所有会话的列表。可能有一些查询仍在等待获取内存。这些查询可以轻松过滤。所有会议都在哪里granted_memory_kb IS NULL。这些是请求内存但未得到内存的会话。另一件事可能是授予的记忆力可能太低。您可以将列requested_memory_kb与进行比较granted_memory_kb。请求显示进程需要多少内存才能最佳运行,而授予显示进程启用的内存。如果一个进程需要 2GB 才能运行,但只获得 2MB...您可能会自己获得。;-)

\n

另一种方法是检查RESSOURCE_SEMAPHORE

\n
SELECT * FROM sys.dm_exec_query_resource_semaphore\n
Run Code Online (Sandbox Code Playgroud)\n

你可以看看waiter_countgrantee_count。如果 waiter 高于 0,则说明您的内存有压力,这可能会导致交换,并可能导致您在 perfmon 中看到的磁盘压力。

\n