native compiled stored procedure sp_getapplock alternative - sql-server

tldr; what is alternative of sp_getapplock in the native compiled stored procedure.
I have a memory-optimized table and few indexes on it. it is mission critical app. I am using a memory-optimized table since is does minimal logging. I am developing order matching/trade matching engine. one order is inserted at a time and matched with open orders. it is not a bulk operation. I have tried with regular table, but I was not able to achieve throughput I require. the memory-optimized table has solved throughput issue.
I want to restrict SQL server to not run more than one instance of the stored procedure. in the regular stored procedure, this can be achieved with sp_getapplock. how can I achieve this with the natively compiled stored procedure?
I googled and did not found an answer.

One method is to execute sp_getapplock in a outer stored procedure that wraps the call to the native proc:
CREATE PROC dbo.usp_NativeProcWrapper
AS
BEGIN TRY
BEGIN TRAN;
EXEC sp_getapplock 'dbo.usp_NativeProc', 'Exclusive', 'Transaction';
EXEC dbo.usp_NativeProc;
EXEC sp_releaseapplock 'dbo.usp_NativeProc', 'Transaction';
COMMIT;
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0 ROLLBACK;
THROW;
END CATCH;
GO

Related

All in transaction inside stored procedure

I have a pretty big stored procedure with a lot of select/insert/delete statements. I would like all of this to be either commited or rolled back when something wrong happens during execution.
My question: is this "on" by default for a stored procedure, or do I need do add something? I've read somewhere that stored procedure commands which were already executed will not be rollback when any command after would fail. Is it true?
If this is the case putting this inside stored procedure: BEGIN TRAN and at the end COMMIT do the job?
CREATE PROCEDURE [dbo].[SP1]
#param1 INT
AS
set xact_abort on;
BEGIN TRAN;
SET NOCOUNT ON;
DECLARE X INT;
--stored procedure all business code
COMMIT TRAN;
Normal stored procedures in SQL Server are not atomic, so you need to handle be code with BEGIN TRAN/COMMIT to ensure all-or-nothing behaviour.
It is also good to wrap it with TRY/CATCH block to handle errors.
It is worth to note that natively compiled stored procedures are atomic.
Atomic Blocks in Native Procedures
Atomic blocks are executed (atomically) within the transaction. Either all statements in the block succeed or the entire block will be rolled back to the savepoint that was created at the start of the block. In addition, the session settings are fixed for the atomic block

Force rollback to entire script (stored procedure included)

I have a complex script that contains many stored procedures and I need to do a rollback in all cases.
BEGIN TRANSACTION;
INSERT INTO Table1 VALUES(1);
INSERT INTO Table2 VALUES(2);
EXEC storedprocedure1
EXEC storedprocedure2
....
ROLLBACK;
I have not checked all stored procedures inside (if there is or not other transaction).
I ask if there is a way to rollback the entire script (stored procedures included) independently by presence of other transaction inside the stored procedures.
Thanks!
(Assuming SQL Server)
There is no need to check inside those stored procedures.
The ROLLBACK will rollback all the way to the outer-most transaction, including rolling-back all transactions within storedprocedure1 and storedprocedure2, even if those nested transactions are committed within those procedures.
Selecting ##TRANCOUNT will show you that any ROLLBACK sets the transaction count of the session back to 0.
So if you rollback the outer transaction, anyone who may be expecting those nested transactions to commit is going to be disappointed.

Parallel merge strategy without deadlock

Using SQL Server 2016, I wish to merge data from a SourceTable to a DestinationTable with a simple procedure containing a simple insert/update/delete on the same table.
The SourceTable is filled by several different applications, and they call the MergeOrders stored procedure to merge their uploaded rows from SourceTable into DestinationTable.
There can be several instances of MergeOrders stored procedure running in parallel.
I get a lot of lock, but that's normal, the issue is that sometimes I get "RowGroup deadlocks", which I cannot afford.
What is the best way to execute such merge operation in this parallel environment.
I am thinking about TABLOCK or SERIALIZABLE hints, or maybe application locks to serialize the access, but interested if there is better way.
An app lock will serialize sessions attempting to run this procedure. It should look like this:
create or alter procedure ProcWithAppLock
with execute as owner
as
begin
set xact_abort on;
set nocount on;
begin transaction;
declare #lockName nvarchar(255) = object_name(##procid) + '-applock';
exec sp_getapplock #lockName,'Exclusive','Transaction',null,'dbo';
--do stuff
waitfor delay '00:00:10';
select getdate() dt, object_name(##procid);
exec sp_releaseapplock #lockName, 'Transaction', 'dbo';
commit transaction;
end
There are a couple of subtle things in this template. First off it doesn't have a catch block, and relies on xact_abort to release the applock in case of an error. And you want to explicitly release the app lock in case this procedure is called in the context of a longer-running transaction. And finally the principal for the lock is set to dbo so that no non-dbo user can acquire a conflicting lock. This also requires that the procedure be run with execute as owner, as the application user would not normally be dbo.

Using transaction in SQL Server calling stored procedure in another server

I want to execute an stored procedure in Server1.DB1, this stored procedure will execute inside another stored procedure using dynamic SQL, it will be in Server1.DB2.
I need to use begin/end transaction to make sure everything is executed or everything fail.
The question is: will the transaction work in this case using dynamic SQL pointed to a the different database?
Like
BEGIN TRANSACT
--Set Status to "In Progress"
SET #Qry = N'EXEC '+ #DB2 + '.[dbo].[StatusUpdate] #Id, #Status'
SET #QryParams = N'#Id INT, #Status INT'
EXEC SP_EXECUTESQL #Qry,
#QryParams,
#Id = #Id,
#Status = #InProgress
INSERT DATA LOCALLY IN A TABLE
UPDATE DATA LOCALLY IN A TABLE
END TRANSACT
I'm using SQL Server 2014.
It depends on REMOTE_PROC_TRANSACTIONS definition:
Specifies that when a local transaction is active, executing a remote
stored procedure starts a Transact-SQL distributed transaction managed
by Microsoft Distributed Transaction Coordinator (MS DTC).
If it's ON:
The instance of SQL Server making the remote stored procedure call is
the transaction originator and controls the completion of the
transaction. When a subsequent COMMIT TRANSACTION or ROLLBACK
TRANSACTION statement is issued for the connection, the controlling
instance requests that MS DTC manage the completion of the distributed
transaction across the computers involved.
Otherwise remote stored procedure calls are not made part of a local transaction.
Several important notes:
Using distributed transaction is risky thus should be carefully used.
This feature is deprecated.

Roll back in SQL Server 2005

My question: Is it possible to rollback a stored procedure from another stored procedure in SQL Server 2005?
I have SP1 to insert the values into one table and SP2 to insert the values into another table.
So, if any error comes while executing the SP2 I want to rollback the SP1 also.
Please anyone help me to solve my problem.
Thanks,
Bharath
You need to wrap both calls in a single transaction.
if you call them in SQL then this is way, or using a more comprehensive version like the other answer by answered 7 mins ago gbn.
create proc doall as
BEGIN TRY
BEGIN TRAN
EXECUTE SP1
EXECUTE SP1
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
END CATCH;
if you're calling the SPs from another source, such as from a non SQL program, you need to setup the outer transaction using a Microsoft Distributed Transaction Coordinator (MSDTC) service.
Depending on the API you're using you set up the transaction in Code, and then commit and rollback in code, dependant on conditions.
for example in .net you can use the System.Transactions namespace to create distributed transactions.
In the main program
var tran = new System.Transactions.Transaction();
.
.
.
in one piece of code doe a db call (and pass the tran object to the sql connection) so it enlists in the transaction... if it fails - abort the transaction (trans.Rollback())
.
.
.
.
in another piece of code do another db call (and pass the tran object to the sql connection) so it enlists in the transaction... if it fails - abort the transaction (trans.Rollback())
.
.
.
later...
if both pieces of code succeed commit the transaction
This is a good introduction to the this namespace if you're using .net
You need a wrapper stored procedure to manage the transaction.
##TRANCOUNT on entry and exit to a stored procedure must be the same, otherwise you get error 266. So you can't exit SP1 having started a TXN for example.
I assume that SP1 and SP2 ca nbe called standalone so you need a nested transaction.
Then you hit the same error because
BEGIN TRAN adds one to ##TRANCOUNT
COMMIT TRAN subtracts one from ##TRANCOUNT
ROLLBACK makes ##TRANCOUNT zero
So you can still get error 266.
My answer here explains more about it, including nesting, error 266 suppression etc: Nested stored procedures containing TRY CATCH ROLLBACK pattern?
So in your case, you need soemthing like this
CREATE PROCEDURE Wrapper
AS
SET XACT_ABORT, NOCOUNT ON
DECLARE #starttrancount int
BEGIN TRY
SELECT #starttrancount = ##TRANCOUNT
IF #starttrancount = 0
BEGIN TRANSACTION
EXEC SP1
EXEC SP2
IF #starttrancount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 AND #starttrancount = 0
ROLLBACK TRANSACTION
RAISERROR [rethrow caught error using #ErrorNumber, #ErrorMessage, etc]
END CATCH
GO

Resources