我们有一个插入和更新批量数据的存储过程;我们在选择上使用nolock
提示。现在,当负载非常高时,我们面临601错误。我们可以使用行版本控制吗?
如果是,可以使用哪一个,因为我们同时运行多个事务。还有一件事我们必须承担的是由于始终打开而导致的延迟,我们同步多个数据库服务器以处理数据库故障转移。
我们正在使用它,因为它可以防止读取被其他操作陷入僵局。我们的应用程序具有较高的事务处理率,而且我们关注的另一件事是我们总是使用5个服务器的可用性组,因此我们在提交时会延迟,因为它只在提交所有服务器后提交。那么我们应该使用行版本控制吗?如果是这样如何选择哪一个?或者我们可以进行快照隔离吗?除了tempdb内存使用之外还要付出多少代价呢?
(UPDLOCK,ROWLOCK)用于小批量工作,但当批次高达2000时,它就陷入僵局。
这是执行SP的代码段;相同的代码托管在10台服务器上,因此预计会同时运行。 GetRSExecutionLogLatestID是内部调用SP的地方。
ExecutionLogData execLog = this.fileShareDeliveryWrapper.GetRSExecutionLogLatestID(rptPath, notification.Owner, sharePointSubscriptiondata.RASSubscriptionID, this.configRSConnectionString);
if (execLog != null)
{
sharePointSubscriptiondata.RSExecutionLogId = execLog.RSExecutionLogId;
sharePointSubscriptiondata.RSSubscriptionId = execLog.RSSubscriptionId;
}
这是SP:
ALTER Procedure [dbo].[RAS_USP_GetLatestExecutionLogId]
@ReportURLPath NVARCHAR(MAX),
@UserID NVARCHAR(200),
@RASSubscriptionID NVARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
print @userId
DECLARE @SubscriptionId UNIQUEIDENTIFIER,@OwnerUserId UNIQUEIDENTIFIER, @LogEntryId BIGINT
DECLARE @Subscriptions AS TABLE(SubscriptionID uniqueIdentifier NOT NULL,
NotificationID uniqueidentifier NULL,
ReportID uniqueIdentifier NULL,
ExtensionSettings XML NOT NULL
)
INSERT INTO @Subscriptions
SELECT n.SubscriptionID,n.NotificationID,n.ReportID,n.ExtensionSettings
FROM dbo.Notifications AS n WITH (UPDLOCK, ROWLOCK) INNER JOIN
Subscriptions AS s WITH (UPDLOCK, ROWLOCK) ON n.SubscriptionID = s.SubscriptionID INNER JOIN
Catalog AS c WITH (UPDLOCK, ROWLOCK) ON c.ItemID = n.ReportID INNER JOIN
Users AS um WITH (UPDLOCK, ROWLOCK) ON um.UserID = s.OwnerID
WHERE c.[Path] = @ReportURLPath --AND um.UserName=@UserID
SELECT @SubscriptionID = SubScriptionID FROM
(SELECT SubscriptionID,
NotificationID,
ReportID,
pValues.pValue.value('Name[1]', 'VARCHAR(50)') AS ParamName,
pValues.pValue.value('Value[1]', 'VARCHAR(150)') AS ParamValue
FROM
@Subscriptions CROSS APPLY
ExtensionSettings.nodes('/ParameterValues/ParameterValue') pValues(pValue)
) AS Result
where ParamName like '%RASSubscriptionID%' AND ParamValue = CAST(@RASSubscriptionID AS VARCHAR(100))
SELECT @OwnerUserId = UserID FROM Users WHERE UserName = @UserID
SELECT @LogEntryId = LogEntryId FROM (
SELECT top 1 LogEntryId
FROM ExecutionLogStorage a WITH (UPDLOCK, ROWLOCK)
INNER JOIN [CATALOG] b WITH (UPDLOCK, ROWLOCK) ON a.reportid = b.itemid
INNER JOIN [Notifications] n WITH (UPDLOCK, ROWLOCK) ON n.ReportID = a.ReportID AND n.SubscriptionID = @SubscriptionId
INNER JOIN dbo.Subscriptions s WITH (UPDLOCK, ROWLOCK) ON s.SubscriptionID = n.SubscriptionID
WHERE [Path] = @ReportURLPath AND n.SubscriptionOwnerID=@OwnerUserId
ORDER BY TimeEnd desc) ss
SELECT @LogEntryId AS LogEntryId, @SubscriptionId AS SubscriptionID
END
答案 0 :(得分:0)
SNAPSHOT ISOLATION
几乎是在更新时防止阻塞的方法,当您控制查询并且需要语句之间的一致性时。 READ_COMMITTED_SNAPSHOT
是另一种可能性,但影响所有查询,而且它不保证"一致性"在给定的交易中(就像READ COMMITTED
vs SERIALIZABLE
可以给出不同的结果)。 99%的情况下, NOLOCK
几乎无从可取。
您可以将SNAPSHOT ISOLATION
视为可行的"只读" serializable
*。当然有几个成本 - 请注意,即使没有活动的快照交易,您也会支付很多费用,因为当然如果一个变为活动,则需要跟踪数据。
其他考虑因素:
本文对情况有一个很好的概述: https://technet.microsoft.com/en-us/library/ms188277(v=sql.105).aspx
但最终,如果你需要避免阻止,你唯一真正的选择是行版本控制和NOLOCK,这不是一个选择。否则,您可能需要以不同的方式设计。其他可能性是使用诸如UPDLOCK之类的东西来避免死锁,一次插入/更新小批量数据以便阻塞周期"很短/不明显等等。
(*)我这样说是因为:
SNAPSHOT
交易并且只读取它,您将获得与使用SNAPSHOT ISOLATION
时相同的读取结果,除非您不会阻止作者并且你不会导致死锁SERIALIZABLE
会导致过多的阻塞和太多的死锁。 我说"只读"因为虽然可以在快照事务中写入,但这是一项更复杂的工作。如果您只是在快照交易中读取,那么您不太可能遇到数据正确性问题 - 实际上,因为它类似于SERIALIZABLE,您甚至可能提高结果的一致性。您可能遇到的唯一问题与性能有关。总的来说,就这一问题而言,它是一个重大变化,将其引入此类查询。如果你开始写作,但是:
由于更新冲突导致快照隔离事务中止。您 无法使用快照隔离来访问表格' XYZ'直 或间接在数据库' ABC'更新,删除或插入 已被另一个事务修改或删除的行。 重试事务或更改隔离级别 更新/删除声明。
这是一个你必须处理的新情况,这比阻止更困难(尽管我认为处理死锁的难度相似)。
想象一下,我们有一个包含白色和黑色大理石混合物的袋子。假设我们想要运行两个事务。一 交易将每个白色大理石变成黑色大理石。该 第二次交易将每个黑色大理石变成白色大理石。 如果我们在可序列化隔离下运行这些事务,我们必须运行 他们一次一个。第一笔交易将留下一个袋子 只有一种颜色的大理石。在那之后,第二次交易将会 将所有这些大理石改为另一种颜色。只有两个 可能的结果:只有白色大理石的袋子或只有袋子的袋子 黑色大理石。
如果我们在快照隔离下运行这些事务,则有一个 在序列化隔离下不可能实现的第三个结果。每 交易可以同时拍摄大理石袋的快照 因为它在我们做出任何改变之前存在。现在一个交易发现 白色大理石,将它们变成黑色大理石。在同一个 时间,其他交易发现黑色大理石 - 但只有那些 当我们拍摄快照时,那些黑色的大理石 - 而不是那些大理石 第一个交易变为黑色 - 并将其变为黑色 白色大理石。最后,我们还有一个混合的弹珠袋 一些白色和一些黑色。事实上,我们已经精确地切换了每个 大理石。
换句话说,如果你坚持只阅读SNAPSHOT交易,它就不那么复杂了,所以在这个意义上,我说你可以认为它是一个可行的"只读&#34 ; SERIALIZABLE
- 如果你只是停在那里,它是一个非常有用的工具,几乎任何人都可以使用它来获得一致的非阻塞结果而不使用NOLOCK ,只要他们能负担得起性能打击。当然,它不止于此,但为了更进一步,你需要处理更多的复杂性。