Tom*_*Dee 3 sql-server delete profiler
我正在运行连接到 SQL Server 2012 数据库的 Web 服务。在短时间内(大约 5 秒)内执行多个删除查询时,实际执行的查询似乎是随机的。当一次运行一个或在每次执行之间放置 0.5 秒的延迟时,它们运行完美。
查看 SQL 分析器,所有查询都显示为RPC:Completed
即使它们实际上并未删除表中的行。我检查了表,数据仍然存在,然后将查询从 Profiler 复制并粘贴到 SSMS 中,这影响了一行并将其删除。
所以我假设 Web 服务运行良好,问题出在它的数据库端。探查器中有没有办法查看查询是否成功?什么可能导致这实际上不影响行?
没有触发器。仅使用不同的参数运行相同的查询。只有数据通常是按顺序变化的。刚才没有其他查询在数据库上运行。
我添加了客户端站点日志记录,如果它删除该行,它实际上会返回 1,如果它不删除该行,它会返回 0。然而,即使它出现为 0,Profiler 也会显示它已经运行了查询,但似乎没有影响它。当我通过 SSMS 运行查询时,它确实会影响该行。
未收到来自 Web 服务的任何错误,并且查询通过 SSMS 运行良好。只有在快速连续多次运行时似乎不会删除。我确实同意它很可能针对不同的行,但是当它在 SSMS 中运行正常时看不到它是如何发生的。
CREATE TABLE dbo.ContractDates2HumanAssets
(
iContractDate2HumanAssetID int IDENTITY(1,1) NOT NULL,
iContractDateID int NOT NULL,
iHumanAssetID int NOT NULL,
cCategory nvarchar(256) NOT NULL,
cHR_x0020_ID nvarchar(256) NOT NULL,
cCD_x0020_ID nvarchar(256) NOT NULL,
CONSTRAINT PK_ContractDates2HumanAssets PRIMARY KEY CLUSTERED
(
iContractDate2HumanAssetID 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
CREATE TABLE dbo.ContractDates
(
iContractDateID int IDENTITY(1,1) NOT NULL,
iContractID int NOT NULL,
dDate datetime NOT NULL,
cResource nvarchar(256) NOT NULL,
cCD_x0020_ID nvarchar(256) NOT NULL,
CONSTRAINT PK_ContractDates PRIMARY KEY CLUSTERED
(
iContractDateID ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY];
exec sp_executesql N'DELETE FROM ContractDates2HumanAssets
WHERE iContractDateID IN ((SELECT ContractDates.iContractDateID
FROM ContractDates2HumanAssets
INNER JOIN ContractDates ON ContractDates.iContractDateID = ContractDates2HumanAssets.iContractDateID
WHERE iHumanAssetID = @humanid AND iContractID = (SELECT iContractID FROM Contracts WHERE cContractNo = @id) AND dDate = @newDate))',N'@id nvarchar(6),@newDate nvarchar(10),@humanid int',@id=N'999111',@newDate=N'2018-03-16',@humanid=82
Run Code Online (Sandbox Code Playgroud)
这是出现在分析器中的查询。检查表后,该行仍然存在。但是将其复制并粘贴到 SSMS 中并执行它,它会返回 1 行受影响并被删除。
SELECT *
FROM ContractDates2HumanAssets
WHERE iContractDateID IN
(
(
SELECT ContractDates.iContractDateID
FROM ContractDates2HumanAssets
INNER JOIN ContractDates
ON ContractDates.iContractDateID = ContractDates2HumanAssets.iContractDateID
WHERE
iHumanAssetID = 82
AND iContractID =
(
SELECT iContractID
FROM Contracts
WHERE cContractNo = N'999111'
)
)
);
Run Code Online (Sandbox Code Playgroud)
结果:
?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ?????? ? iContractDate2HumanAssetID ? iContractDateID ? iHumanAssetID ? c 类别 ? cHR_x0020_ID ? cCD_x0020_ID ? ?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ?????? ? 102538?113369?82 ? ? ? ? ? 102539?113370?82 ? ? ? ? ? 102540?113371?82 ? ? ? ? ? 102541?113372?82 ? ? ? ? ? 102542?113373?82 ? ? ? ? ? 102543?113374?82 ? ? ? ? ? 102544?113375?82 ? ? ? ? ? 102545?113376?82 ? ? ? ? ? 102546?113377?82 ? ? ? ? ? 102547?113378?82 ? ? ? ? ? 102548?113379?82 ? ? ? ? ? 102549?113380?82 ? ? ? ? ? 102550?113381?82 ? ? ? ? ? 102551?113382?82 ? ? ? ? ? 102552?113383?82 ? ? ? ? ? 102553?113384?82 ? ? ? ? ?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ??????
我运行该查询以获取所有相关数据,如果更有帮助,我可以获取每个表的单个数据。
Han*_*non 12
SQL Server从不随机选择删除或不删除行。当您向DELETE
SQL Server发送有效语句时,它会执行它。保证。时期。如果语句中有错误,SQL Server 将返回错误。你看到错误了吗?
更有可能的问题是查询本身没有针对您认为的行,或者这些行不存在。显示您的表结构以及实际的删除语句。
罗伯特·罗德里格斯 (Robert Rodriguez)在下面的回答中谈到了隐式交易的影响,这很可能是导致您出现问题的原因,我在回答发布时对此进行了投票。SQL Server中的大多数肯定不会删除行,甚至当SET IMPLICIT_TRANSACTIONS
是ON
。为了证明这一点,请运行以下语句,在 SSMS 的查询窗口中创建和填充表:
USE tempdb;
DROP TABLE IF EXISTS dbo.t;
CREATE TABLE dbo.t
(
i int NOT NULL
CONSTRAINT t_pk
PRIMARY KEY
CLUSTERED
);
GO
INSERT INTO dbo.t (i)
VALUES (1);
SELECT *
FROM dbo.t;
GO
Run Code Online (Sandbox Code Playgroud)
运行上面的代码,你会看到这样的输出:
????? ? 一世 ? ????? ? 1 ? ?????
现在,在第二个 SSMS 查询窗口中,运行以下代码:
USE tempdb;
/*********************************
* TURN ON IMPLICIT TRANSACTIONS *
*********************************/
SET IMPLICIT_TRANSACTIONS ON;
SELECT [State] = 'PRE DELETE'
, [@@TRANCOUNT] = @@TRANCOUNT
, [IMPLICIT_TRANSACTIONS] = CASE WHEN @@OPTIONS & 2 = 2 THEN 'ON' ELSE 'OFF' END
, [Count of Rows in dbo.t] = (SELECT COUNT(1) FROM dbo.t)
DELETE
FROM dbo.t
WHERE dbo.t.i = 1;
SELECT [State] = 'POST DELETE'
, [@@TRANCOUNT] = @@TRANCOUNT
, [IMPLICIT_TRANSACTIONS] = CASE WHEN @@OPTIONS & 2 = 2 THEN 'ON' ELSE 'OFF' END
, [Count of Rows in dbo.t] = (SELECT COUNT(1) FROM dbo.t)
GO
--DISCONNECT the session after you run the above code
Run Code Online (Sandbox Code Playgroud)
运行上面的代码,你会看到两组结果:
?????????????????????????????????????????????????????? ?????????????????????????????? ? 状态 ?@@TRANCOUNT ?IMPLICIT_TRANSACTIONS ? dbo.t 中的行数? ?????????????????????????????????????????????????????? ?????????????????????????????? ? 预删除?1 ? 在 ?1 ? ?????????????????????????????????????????????????????? ?????????????????????????????? ?????????????????????????????????????????????????????? ????????????????????????????????? ? 状态 ?@@TRANCOUNT ?IMPLICIT_TRANSACTIONS ? dbo.t 中的行数? ?????????????????????????????????????????????????????? ????????????????????????????????? ? 发布删除?1 ? 在 ?0 ? ?????????????????????????????????????????????????????? ?????????????????????????????????
在上面的输出中,您可以看到第一个结果集表明该行确实存在于dbo.t
. 在第二个结果集之前,DELETE FROM dbo.t
语句执行。在第二个结果集中,您可以看到 SQL Server 实际上删除了该行。确保您现在断开上面的会话,ROLLBACK TRANSACTION
由于缺少显式COMMIT TRANSACTION
语句,它将与SET IMPLICIT_TRANSACTIONS ON;
.
现在在 SSMS 中打开第三个查询窗口,并运行以下代码:
SELECT [State] = 'POST ROLLBACK'
, [@@TRANCOUNT] = @@TRANCOUNT
, [IMPLICIT_TRANSACTIONS] = CASE WHEN @@OPTIONS & 2 = 2 THEN 'ON' ELSE 'OFF' END
, [Count of Rows in dbo.t] = (SELECT COUNT(1) FROM dbo.t);
Run Code Online (Sandbox Code Playgroud)
您将看到以下输出,表明该行仍然存在于dbo.t
.
?????????????????????????????????????????????????????? ????????????????????????????????? ? 状态 ?@@TRANCOUNT ?IMPLICIT_TRANSACTIONS ? dbo.t 中的行数? ?????????????????????????????????????????????????????? ????????????????????????????????? ? 后回滚?0 ? 离开 ?1 ? ?????????????????????????????????????????????????????? ?????????????????????????????????
当然,由于隐式事务被回滚,该行存在于表中,就像您ROLLBACK TRANSACTION
直接在DELETE FROM
.
假设您仍然不相信该行实际上已被DELETE FROM dbo.t
语句删除,让我们将有DBCC PAGE
问题的表的输出添加到第二组代码中,然后重新运行它。下面的代码取自我关于使用 DBCC PAGE 查看行详细信息的博客文章
USE tempdb;
SET IMPLICIT_TRANSACTIONS ON;
SELECT [State] = 'PRE DELETE'
, [@@TRANCOUNT] = @@TRANCOUNT
, [IMPLICIT_TRANSACTIONS] = CASE WHEN @@OPTIONS & 2 = 2 THEN 'ON' ELSE 'OFF' END
, [Count of Rows in dbo.t] = (SELECT COUNT(1) FROM dbo.t)
DBCC TRACEON(3604) WITH NO_INFOMSGS;
DECLARE @dbid int = DB_ID();
DECLARE @fileid int;
DECLARE @pageid int;
DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY
FOR
SELECT dpa.allocated_page_file_id
, dpa.allocated_page_page_id
FROM sys.schemas s
INNER JOIN sys.objects o ON o.schema_id = s.schema_id
CROSS APPLY sys.dm_db_database_page_allocations(DB_ID(), o.object_id, NULL, NULL, 'DETAILED') dpa
WHERE o.name = N't'
AND s.name = N'dbo'
AND dpa.page_type_desc = N'DATA_PAGE';
OPEN cur;
FETCH NEXT FROM cur INTO @fileid, @pageid;
WHILE @@FETCH_STATUS = 0
BEGIN
DBCC PAGE (@dbid, @fileid, @pageid, 3);
FETCH NEXT FROM cur INTO @fileid, @pageid;
END
CLOSE cur;
DEALLOCATE cur;
DBCC TRACEOFF(3604);
DELETE
FROM dbo.t
WHERE dbo.t.i = 1;
DBCC TRACEON(3604) WITH NO_INFOMSGS;
DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY
FOR
SELECT dpa.allocated_page_file_id
, dpa.allocated_page_page_id
FROM sys.schemas s
INNER JOIN sys.objects o ON o.schema_id = s.schema_id
CROSS APPLY sys.dm_db_database_page_allocations(DB_ID(), o.object_id, NULL, NULL, 'DETAILED') dpa
WHERE o.name = N't'
AND s.name = N'dbo'
AND dpa.page_type_desc = N'DATA_PAGE';
OPEN cur;
FETCH NEXT FROM cur INTO @fileid, @pageid;
WHILE @@FETCH_STATUS = 0
BEGIN
DBCC PAGE (@dbid, @fileid, @pageid, 3);
FETCH NEXT FROM cur INTO @fileid, @pageid;
END
CLOSE cur;
DEALLOCATE cur;
DBCC TRACEOFF(3604);
SELECT [State] = 'POST DELETE'
, [@@TRANCOUNT] = @@TRANCOUNT
, [IMPLICIT_TRANSACTIONS] = CASE WHEN @@OPTIONS & 2 = 2 THEN 'ON' ELSE 'OFF' END
, [Count of Rows in dbo.t] = (SELECT COUNT(1) FROM dbo.t)
GO
Run Code Online (Sandbox Code Playgroud)
结果集看起来与上面的第二组完全相同,但是如果我们查看“消息”选项卡,我们将看到删除前后运行 DBCC PAGE 的输出。删除前第一个 DBCC PAGE 的输出,并删除了标题部分,如下所示:
. . . 插槽 0 偏移 0x6b 长度 11 记录类型 = PRIMARY_RECORD 记录属性 = NULL_BITMAP 记录大小 = 11 内存转储@0x000000B76B27A06B 0000000000000000: 10000800 01000000 010000 ..... 插槽 0 列 1 偏移量 0x4 长度 4 长度(物理)4 我 = 1 插槽 0 偏移量 0x0 长度 0 长度(物理)0 KeyHashValue = (8194443284a0)
您可以在上面的输出中看到Record Type
is PRIMARY_RECORD
,并且 Slot0
包含值:1
。这表明该行存在于表中并且具有我们期望的值。
DBCC PAGE 的输出,删除后,删除了相同的标题部分,如下所示:
插槽 0 偏移 0x6b 长度 11 记录类型 = GHOST_DATA_RECORD 记录属性 = NULL_BITMAP 记录大小 = 11 内存转储@0x000000B76B27A06B 0000000000000000: 1c000800 01000000 010000 ..................... 插槽 0 列 1 偏移量 0x4 长度 4 长度(物理)4 我 = 1 插槽 0 偏移量 0x0 长度 0 长度(物理)0 KeyHashValue = (8194443284a0)
输出清楚地显示Record Type
for slot 0
is GHOST_RECORD
,这表明 slot (row) 已被删除。
我们还可以sys.fn_dblog
使用m_lsn
DBCC PAGE 输出中的值,通过未记录的系统函数检查事务日志:
SELECT *
FROM sys.fn_dblog('102:281659:60', '102:281659:60');
Run Code Online (Sandbox Code Playgroud)
输出显示删除已记录在事务日志中:
?????????????????????????????????????????????????????? ???????????????????????????????????? ? 当前 LSN ? 手术 ?语境 ?交易 ID ? ?????????????????????????????????????????????????????? ???????????????????????????????????? ? 00000066:00044c3b:003c?LOP_DELETE_ROWS ? LCX_MARK_AS_GHOST ?0000:00160373 ? ?????????????????????????????????????????????????????? ????????????????????????????????????
为简洁起见,这里只显示了输出的前几列,但您可以清楚地看到该LOP_DELETE_ROWS
操作,其上下文为LCX_MARK_AS_GHOST
,这表明 SQL Server 已DELETE
在事务日志中记录了该操作。
Web 服务代码有可能开启隐式事务。
作为其工作原理的示例,我在 tempdb 中创建了一个简单的表,插入了一行,打开了隐式事务,然后删除了该行:
USE tempdb;
CREATE TABLE dbo.t
(
someval int
);
INSERT INTO dbo.t (someval)
VALUES (1);
SET IMPLICIT_TRANSACTIONS ON;
DELETE FROM dbo.t;
Run Code Online (Sandbox Code Playgroud)
如果我现在断开连接并重新连接会话,则运行以下代码:
USE tempdb;
SELECT *
FROM dbo.t
Run Code Online (Sandbox Code Playgroud)
我看到该行仍在表格中。这非常符合您所看到的描述。您需要为此检查网络服务代码,或查看跟踪以查看此选项是否有效。
如果您有兴趣,可以对此Not Connect项目进行投票,以要求 Microsoft 提供一种更简单的方法来确定是否启用了隐式事务。
归档时间: |
|
查看次数: |
16730 次 |
最近记录: |