标签: sql-server

为什么我的标量 UDF 在两个不同(但极其相似)的服务器上表现如此不同?

最近,我正在解决一个奇怪的性能问题,该问题影响了应用程序的生产环境,但不影响任何较低的环境。我设法用这个查询以最简单的形式复制了这个问题:

SELECT product_id, dbo.TranslateStatusToActive(status_id) FROM prod_Products
Run Code Online (Sandbox Code Playgroud)

TranslateStatusToActive是一个非常简单的标量 UDF,它基本上只是连接给另一个表的值,并根据case语句返回 1 或 0 。我会发布代码,但它是供应商编写的功能,我今天对被起诉并不特别感兴趣。(是的,逻辑可以内联。是的,它解决了性能问题。是的,我们已经说服供应商实施更改。这不是我的问题。)

在生产中执行时,查询需要 10 到 20 秒才能返回结果。在开发中,相同的查询在不到 3 秒的时间内返回。执行计划几乎相同,除了显示 CPU 时间在生产中约为 15000 毫秒,其他地方为 3000 毫秒。

我怀疑存在一些环境差异,因此我设置了另一台服务器来尽可能地复制生产条件:我确保 CPU 的数量、分配给 SQL Server 的内存量以及特定的补丁级别 (13.0.0.1)。 4451) 相同。

我将生产数据库的副本恢复到这个新的沙箱服务器,令我惊讶的是,查询的执行速度与它在开发中的执行速度一样快。再一次,计划和数据是相同的,除了额外的 CPU 时间。执行计划中列出的等待类型相同,并且在每个环境中彼此相差几毫秒。

不知道接下来要做什么,我optimize for ad hoc workloads在生产服务器上启用了。这解决了性能问题!但是有一件事:其他环境都没有启用此设置。我一直在测试期间定期清除每个环境中的程序和系统缓存,所以我认为这不是更改设置导致重新编译的结果。

问题

  • 尽管有相同的计划和几乎相同的系统,但什么可能导致 UDF 在每个环境中运行如此不同?
  • 为什么需要optimize for ad hoc workloads启用生产环境才能与未启用它的其他环境一样好?
  • 是否有一些我没想到检查的设置可能会导致如此大的差异?

开发是共享的,而生产目前仅由该应用程序使用。第三个盒子的用法和生产的盒子几乎一样。我几乎清除了他们发出DBCC命令的每个缓存。开发环境经常用作培训系统,所以我相当确信这不是计划缓存问题。

与第三个框的唯一区别是没有连接到它的应用程序,但是在我在生产中测试该功能时几乎没有使用应用程序,所以区别在于,基于我在这种环境中工作的经验,微不足道。我唯一不能做的就是重启生产服务器,但微软的文档明确指出启用optimize for ad hoc workloads不会清除或影响任何现有计划,所以我看不出有什么区别。

performance sql-server functions sql-server-2016 query-performance

2
推荐指数
1
解决办法
202
查看次数

Invoke-SqlCmd - 将强制转换为整数以防止注入

我很懒惰,宁愿参数化一次(以获得名称的 object_id)并Invoke-SqlCmd用于其余工作。

给定一系列用于处理任意服务器对象的函数,下面的测试是否足以确认 CmdletBinding 输入参数Int32防止通过用户提供的方式注入$object_id?

function foo {
    [CmdletBinding()]Param(
        [Int32]$object_id 
    )
    $query = "select type_desc from sys.objects where object_id = $object_id;"
    Invoke-Sqlcmd -ServerInstance "localhost" -Database "tempdb" -Query $query
}

foo 3
foo "0 union all select name from sys.syslogins where sid = 0x01"
foo $null
foo ([math]::Pow(2,31)+1)
foo @(1,2)
Run Code Online (Sandbox Code Playgroud)

sql-server sql-injection powershell

2
推荐指数
1
解决办法
316
查看次数

为什么即使没有提交事务,日志文件也会增长?

以下是我所做的:

  1. 以简单恢复模式创建数据库。
  2. 创建的表。
  3. 开始 tran 并插入如此多的行以超过日志文件的大小。
  4. 提交了交易。

在第 4 步之前,我注意到日志文件在增长,这让我很困惑。为什么会这样?

根据 MSDN:

对于每个逻辑写入,事务日志记录都会插入记录修改的日志缓存中。

进而:

提交事务时将日志记录写入磁盘。

那么如何解释插入数据时日志文件不断增长的事实,即使没有提交事务?

据我了解,未提交的日志记录应该存储在日志缓冲区中,而不是存储在磁盘上。

sql-server transaction-log

2
推荐指数
1
解决办法
530
查看次数

用于事务复制的域帐户或 Windows 帐户

所有在线资源都说使用 Windows 帐户作为 Agent 帐户,即 Snapshot、Distributor 和 Log Reader 来设置复制。

请参阅以下链接作为示例:

我的问题是:上面使用域帐户有什么问题,哪个更容易维护和管理?

replication sql-server sql-server-agent transactional-replication

2
推荐指数
1
解决办法
2113
查看次数

在 SQL 2014 中拆分现有分区

我有一个包含超过 200 亿行的 SQL Server 表,最后一个分区中有 130 亿行。

该表目前按“时间”字段分为 6 种方式:

2011
2012
2013
2014
2015
2016/2017/2018
Run Code Online (Sandbox Code Playgroud)

2016/2017/2018分区需要拆分成自己的分区所以有2016、2017、2018分区。

如何做到这一点并在此过程中避免大量日志文件增长?数据库处于简单恢复中,当前每个分区都位于其自己的一组磁盘上的单独文件组中。

CREATE TABLE [dbo].[Log](

      [RefNo] [nchar](7) NOT NULL,

      [DevID] [nvarchar](7) NOT NULL,

      [Time] [datetime] NOT NULL,

      [summary] [float] NULL,

      [staging] [float] NULL,

      [position] [float] NULL,

CONSTRAINT [PK_Log] PRIMARY KEY CLUSTERED

(

      [RefNo] ASC,

      [DevID] ASC,

      [Time] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 96)

)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

sql-server partitioning sql-server-2014

2
推荐指数
1
解决办法
911
查看次数

在可用性组的辅助节点上补丁失败后无法恢复同步

我在可用性组的辅助节点上应用了 Service Pack 4。它失败了,所以我将辅助节点的整个 VM 恢复到早期版本,现在数据不同步。

我有主动和被动两个节点。我尝试手动恢复数据移动。但它失败了。你能在这里提出什么建议吗?

sql-server availability-groups patching

2
推荐指数
1
解决办法
236
查看次数

查找谁执行了存储过程

SQL Server 中是否有一种方法/任何函数/DMV 可以提供谁执行了特定数据库的存储过程?

sql-server stored-procedures

2
推荐指数
2
解决办法
2956
查看次数

在不同的文件组上创建表分区,这是内存优化文件组的第一个边界

我们所有交易的 99% 都是针对最近一周的数据,一个 WEEK_SELECTOR 列描述了哪一周被描述。按周对我们的 10 亿+ 行表进行分区将是有益的,如果最近一周的 50 万左右行位于内存分区中,则更是如此。

在尝试将前一周拆分到我们的内存优化文件组时

CREATE PARTITION FUNCTION [TPF](int) AS RANGE RIGHT FOR VALUES (N'1700114')
CREATE PARTITION SCHEME [TPS] AS PARTITION [TPF] TO ([PRIMARY], [memtest])
Run Code Online (Sandbox Code Playgroud)

我们收到以下错误:

Msg 7737, Level 16, State 1, Line 2
Filegroup memtest is of a different filegroup type than the first filegroup in partition scheme TPS
Run Code Online (Sandbox Code Playgroud)

我们现在假设分区的文件组必须是相同类型的,我们的计划是不可能的,但找不到文档说这是不可能的。

有人可以解释如何做到这一点,或者如果没有,请提供一个链接来说明?谢谢。

sql-server partitioning memory-optimized-tables sql-server-2016

2
推荐指数
1
解决办法
434
查看次数

LTRIM/RTRIM/ISNULL 的操作顺序

LTRIM与RTRIM结合使用时,您放置的操作顺序是否重要ISNULL?例如,以下面的示例为例,用户可能会在字段中输入一堆空格,但我们将其输入修剪为实际NULL值以避免存储空字符串。

我正在执行以下TRIM操作ISNULL:

DECLARE @Test1 varchar(16) = '    '

IF LTRIM(RTRIM(ISNULL(@Test1,''))) = ''
BEGIN
    SET @Test1 = NULL
END

SELECT @Test1
Run Code Online (Sandbox Code Playgroud)

这适当地返回一个真NULL值。现在让我们ISNULL放在外面:

DECLARE @Test2 varchar(16) = '    '

IF ISNULL(LTRIM(RTRIM(@Test2)),'') = ''
BEGIN
    SET @Test2 = NULL
END

SELECT @Test2
Run Code Online (Sandbox Code Playgroud)

这也返回一个NULL值。两者都适用于预期用途,但我很好奇 SQL 查询优化器处理此问题的方式是否有任何不同?

performance sql-server optimization t-sql query-performance

2
推荐指数
1
解决办法
4464
查看次数

使用动态查询循环遍历 Db 以获取截断语句

请在下面对我的 SQL 查询提供任何帮助,我们将不胜感激。我不熟悉如何循环数据库来截断表。我尝试过的内容如下:

DECLARE @DynamicSQL AS VARCHAR(MAX) = '';
DECLARE @dbName     nvarchar(1000) ='SP_%%';


SELECT @DynamicSQL = @DynamicSQL + 'Use' + QUOTENAME(NAME) + ';  '
FROM sys.databases
WHERE NAME LIKE  'SP_%%';

SELECT @DynamicSQL = @DynamicSQL + 'TRUNCATE TABLE ' + QUOTENAME(NAME) + '; '
FROM sys.tables
WHERE name LIKE 'log%'


PRINT @DynamicSQL
--EXEC (@DynamicSQL)
Run Code Online (Sandbox Code Playgroud)

我得到的结果如下:

Use[SP__20180314];  Use[SPAUT__06092018];
Run Code Online (Sandbox Code Playgroud)

但我想要这样的东西:

Use[SP_20180314] Truncate Table log;  Use[SPAUT_06092018] Truncate Table log;
Run Code Online (Sandbox Code Playgroud)

我正在尝试从 SQL Server 2016 上的数据库中截断日志表。谢谢

sql-server truncate

2
推荐指数
1
解决办法
2144
查看次数