我有快速继续添加数据的表格。
我需要从此表中获取记录并立即将其删除,以便我无法再次处理相同的记录。由于数据的添加速度更快,我需要使用TOP clause
,因此当时只有少量记录转到业务逻辑进行处理。
我使用以下查询
BEGIN TRAN readrowdata
SELECT
top 5 [RawDataId],
[RawData]
FROM
[TABLE] with(HOLDLOCK)
WITH q AS
(
SELECT
top 5 [RawDataId],
[RawData]
FROM
[TABLE] with(HOLDLOCK)
)
DELETE from q
COMMIT TRANSACTION readrowdata
我在这里使用HOLDLOCK,因此当我执行SELECT和DELETE操作时,新数据无法插入到表中。我使用它是因为假设现在表中只有3条记录,那么SELECT语句将获得3条记录,同时插入新记录,DELETE语句将删除4条记录。所以我会在这里丢失1个数据。
性能期限的查询是否正常?如果我可以改进它,那么请提供你的建议。
谢谢
答案 0 :(得分:3)
就个人而言,我会采用不同的方法。锁定较少的一个,但也有额外的信息表明当前正在处理某些记录......
DECLARE @rowsBeingProcessed TABLE (
id INT
);
WITH rows AS (
SELECT top 5 [RawDataId] FROM yourTable WHERE processing_start IS NULL
)
UPDATE rows SET processing_start = getDate() WHERE processing_start IS NULL
OUTPUT INSERTED.RowDataID INTO @rowsBeingProcessed;
-- Business Logic Here
DELETE yourTable WHERE RowDataID IN (SELECT id FROM @rowsBeingProcessed);
然后,您还可以添加“如果记录已被'处理'超过10分钟,假设业务逻辑失败”等检查,等等。
答案 1 :(得分:1)
通过以这种方式锁定表,您强制其他进程等待您的事务完成。这可能会对可伸缩性和性能产生非常快速的影响 - 而且往往难以预测,因为通常有一系列组件都依赖于您的数据库。
如果每个运行此查询的客户端多个,并且多个客户端向表中添加新行,则整个系统性能可能会在某些时候恶化,因为每个“读取”客户端都在等待锁定,等待插入数据的“写”客户端增长,反过来它们可能会占用其他组件(无论是生成要插入的数据)。
迭戈的答案就是钱 - 将数据放入变量,并删除匹配的行。如果可以避免,请不要在SQL Server中使用锁!
答案 2 :(得分:0)
如果我理解正确,你担心在你的选择和你的删除之间会插入更多的记录而第一个TOP 5会与第二个TOP 5不同吗?
如果是这样,你为什么不把你的第一个选择加载到临时表或变量(或者至少是PK)中,你做了什么与你的数据有关,然后根据这个表进行删除?
答案 3 :(得分:0)
您可以使用TRIGGERS轻松完成。下面提到的是一种情况,它可以帮助您不要让其他试图同时插入数据的用户。如下......
数据定义语言
CREATE TABLE SampleTable
(
id int
)
示例记录
insert into SampleTable(id)Values(1)
示例触发
CREATE TRIGGER SampleTableTrigger
on SampleTable AFTER INSERT
AS
IF Exists(SELECT id FROM INSERTED)
BEGIN
Set NOCOUNT ON
SET XACT_ABORT ON
Begin Try
Begin Tran
Select ID From Inserted
DELETE From yourTable WHERE ID IN (SELECT id FROM Inserted);
Commit Tran
End Try
Begin Catch
Rollback Tran
End Catch
End
希望这是非常简单和有用的
答案 4 :(得分:0)
我知道这是一个古老的问题,但我在这里找到了一些解决方案https://www.simple-talk.com/sql/learn-sql-server/the-delete-statement-in-sql-server/:
DECLARE @Output table
(
StaffID INT,
FirstName NVARCHAR(50),
LastName NVARCHAR(50),
CountryRegion NVARCHAR(50)
);
DELETE SalesStaff
OUTPUT DELETED.* INTO @Output
FROM Sales.vSalesPerson sp
INNER JOIN dbo.SalesStaff ss
ON sp.BusinessEntityID = ss.StaffID
WHERE sp.SalesLastYear = 0;
SELECT * FROM @output;
也许这对你有所帮助。