是否有其他人在调用CHANGETABLESQL Server 2016时遇到过糟糕的计划?
我有一个使用更改跟踪来更新缓存的应用程序。应用服务器每秒获取多个表的更改。在CHANGETABLE如此频繁,通常仅返回几行调用。这在 2008 R2 和 2012 中效果很好。当我测试 2016 时,我发现 CPU 飙升,并发现该计划正在扫描更改跟踪内部表,它曾经在那里进行搜索。
如果您想在此处查看此行为,请执行复制它的步骤:
创建表:
CREATE TABLE [dbo].[ChangeTable_Test](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Test_ChangeTable_Id] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[ChangeTable_Test] ENABLE CHANGE_TRACKING
GO
INSERT INTO ChangeTable_Test (Name) VALUES ('Test')
GO 1000
Run Code Online (Sandbox Code Playgroud)包括实际的执行计划并运行以下命令。
SET STATISTICS IO …Run Code Online (Sandbox Code Playgroud)在BOL 上,我阅读了以下关于MultiSubnetFailover=True 的内容:
即使可用性组仅跨越单个子网,MultiSubnetFailover连接选项也应设置为True。这允许您预先配置新客户端以支持未来跨子网,而无需更改未来客户端连接字符串,并且还优化了单个子网故障转移的故障转移性能。
据我了解MultiSubnetFailover,使用此选项设置客户端驱动程序为与侦听器关联的每个 IP 地址设置一个套接字。它们都被并行检查以加快查找在线 IP 的过程,第一个响应将用于连接。在这里,我看到了性能提升。
但是单个子网的性能提升在哪里?只有与侦听器关联的 IP。
这个问题在专家交流中尝试了两次,但没有真正的答案。
我知道我不应该缩小日志文件 - 这不是问题。
如果你想回答一个人不应该这样做 - 这已经被多次确认,是的,这不是这个问题的目标。
设置为简单备份也不是一个选项。
多年来一直困扰着我 - 事实上我现在知道为什么应该备份它两次。
我最近看到第一个日志文件每次都能够在第一次尝试时缩小 - 令人难以置信。我向那个人询问了这件事,我只能说“在发布之前重新组织”——我不知道他指的是什么。我无法再次与他联系。
我从 EE 上的现有帖子中知道这一点:“收缩删除日志的非活动部分。为了不活动,必须截断日志,这作为日志备份的一部分发生。
但是,事务日志由许多以循环方式使用的虚拟日志文件组成。只能修剪文件末尾的虚拟日志,因此如果 SQL Server 当前正在使用最后一个虚拟日志,则无法删除任何内容。sql 7 中的旧修复是运行一个脚本,该脚本运行足够多的虚拟事务来填充日志并将指针环绕到第一个虚拟日志(如果您愿意,仍然可以使用此方法)。
http://support.microsoft.com/kb/256650/EN-US
DBCC 现在为您执行此操作,但仍需要额外的步骤再次截断日志,以便可以删除非活动空间”
来自另一位用户:“我所要做的就是停止上次管理员在数据库维护计划中留下的自动优化和完整性检查。”
我有一个具有该CURSOR VARYING类型的输出参数的存储过程。我想验证调用存储过程的代码是否可以使用输出游标。这似乎CURSOR_STATUS是正确使用的函数,但将其应用到输出光标时,我得到了意想不到的结果。该函数在创建它的存储过程内返回值 -3,但在存储过程外按预期工作。请参阅下面的代码:
CREATE OR ALTER PROCEDURE dbo.OutputCursorTest
(@Cursor_OUT CURSOR VARYING OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
SET @Cursor_OUT = CURSOR FORWARD_ONLY STATIC FOR
SELECT [high]
from master..spt_values
OPEN @Cursor_OUT;
SELECT CURSOR_STATUS('variable', '@Cursor_OUT'); -- this seems to always return -3
-- possible workaround
/*
DECLARE @Cur_Copy CURSOR;
SET @Cur_Copy = @Cursor_OUT;
SELECT CURSOR_STATUS('variable', '@Cur_Copy');
DEALLOCATE @Cur_Copy;
*/
RETURN;
END;
GO
DECLARE @Cur CURSOR;
EXEC dbo.OutputCursorTest @Cursor_OUT = @Cur OUTPUT;
SELECT CURSOR_STATUS('variable', '@Cur'); -- this returns 1 …Run Code Online (Sandbox Code Playgroud) 我正在 MSDN 的 SQL-Server 中学习“分区功能”和“分区架构”。我发现这种将所有分区映射到同一个文件组的语法。例如:
CREATE PARTITION FUNCTION myRangePF3 (int)
AS RANGE LEFT FOR VALUES (1, 100, 1000);
GO
CREATE PARTITION SCHEME myRangePS3
AS PARTITION myRangePF3
ALL TO ( test1fg );
Run Code Online (Sandbox Code Playgroud)
我的问题是,这样做的关键是什么?这甚至称为分区吗???我们通常什么时候将所有分区映射到同一个文件组?
我使用了很多函数来启动和运行网站,该网站中的几乎每个操作都会导致执行 SQL 函数。想象一下,几乎所有的数据处理和网站逻辑都是由数据库和部分网络服务器处理的,疯了吧?不是我的错。
但是这里有一个问题,前端有多个事件处理程序,它们向数据库发送请求并返回请求大量数据,例如单击请求大的JSON字符串,因此用户有可能错误地调用这些SQL通过在短时间内同时单击这些事件来运行,这可能导致数据库连接断开或服务器关闭。
那么,我只需要知道是否可以防止 SQL 函数在短时间内多次执行?或者至少在返回数据之前执行一次?如何?
我正在尝试运行一个递归更改表,从我的 sys 表中读取几个参数。
DECLARE @AlterCmd NVARCHAR(MAX)
SELECT top 1
@AlterCmd = 'ALTER TABLE [dbo].[table] ALTER COLUMN ' + COLUMN_NAME + ' NVARCHAR(' + CHARACTER_MAXIMUM_LENGTH + ')'
FROM
information_schema.columns
WHERE
table_name = 'table_name' and DATA_TYPE like '%char%'
print @AlterCmd
Run Code Online (Sandbox Code Playgroud)
在此示例代码中,我只想验证命令是否正确,但由于连接中的错误而无法运行它。根据我收到的错误消息:
Msg 245, Level 16, State 1, Line 63
Conversion failed when converting the varchar value ')' to data type int.
Run Code Online (Sandbox Code Playgroud) 我清除了我的统计数据并运行了我的查询。实际执行计划的总估计成本为 0.61。我使用dmv 中的total_worker_time列dm_exec_query_stats来计算平均 20858 微秒的 CPU 时间:
(SUM(query_stats.total_worker_time) / SUM(query_stats.execution_count))
Run Code Online (Sandbox Code Playgroud)
该计划推荐了一个索引,我创建了该索引。我清除了我的统计信息,然后再次运行查询。这一次,该计划在顶层的总估计成本为 0.37。我dm_exec_query_state再次检查了dmv,现在平均 CPU 时间为 51536 微秒。
我原以为工人的时间大约是一半,而不是两倍!我在这里错过了什么吗?为什么查询计划的改进没有反映在 exec 查询统计信息中?两个计划在这里上传:
我有一个供应商数据库,我想对其使用更改数据跟踪,但不能,因为他们的表都没有定义主键。这些表确实有唯一索引,但它们没有定义为 PK 约束。在我看来,鉴于它们已经是唯一索引,使它们成为主键将是一件安全的事情(即不会干扰或更改软件操作)。
谁能告诉我我的理解是正确的还是遗漏了什么?
我需要制作一个程序来计算水费。以下是我创建的表定义:
CusAdd_Table
Id,
Name,
Phone,
FamilyNo,
City,
SubscribeDate
Calu_Table
NowData,
PerviousData,
Diff,
MonthtBill,
money,
id
Run Code Online (Sandbox Code Playgroud)
该Diff列计算为NowData-PerviousData。该id列是对 的引用CusAdd_Table。该Money列的计算有一些差异。该MonthtBill列是用于排序的 dataTimepicker。
我的表结构能够轻松地向数据库添加新订阅者。当我添加一个月的新账单时,我会在 Calu_Table 表中插入一行。例如,我想指定的值NowData,PerviousData,[NowData-PerviousData] as Diff用于插入数据时的列Jan。我需要插入额外的行来为Feb和插入数据Mar。
我想打印上个月的数据,但代码需要在不知道订阅者数量的情况下工作。我尝试了下面的代码,但它不满足我的要求,因为我希望每个Id都有它的最后一个值。
SELECT
CusAdd.CusID AS Expr1,
CusAdd.CusName,
CusAdd.CusPhone,
CusAdd.CusFamily,
CusAdd.CusCity,
CusAdd.CusSubscribe,
Calculte_Table.Months,
Calculte_Table.NowRead,
Calculte_Table.ExRead,
Calculte_Table.Esthlak,
Calculte_Table.WhatHePay,
Calculte_Table.Dis_Money,
Calculte_Table.MonthtBill
FROM Calculte_Table
INNER JOIN CusAdd ON Calculte_Table.CusID = CusAdd.CusID
ORDER BY Calculte_Table.MonthtBill DESC;
Run Code Online (Sandbox Code Playgroud)
结果如下:
sql-server ×10
t-sql ×2
backup ×1
cursors ×1
functions ×1
logs ×1
performance ×1
primary-key ×1
truncate ×1