Am I right in saying that from a performance perspective, sql transactions are far better within a stored procedure than code?
At the moment I use most of my transactions in stored procs but sometimes I use code for more complex routines - which obviously I keep to a minimum as much as possible.
It's just that there was a complex routine that required too many "variables" that writing the sql transaction in c# was far easier than using SQL Server. It's a fine line between code readability and performance.
Any ideas?
The performance varies; a SqlTransaction can have less overhead than a TransactionScope, especially if the TransactionScope decides it needs to get entangled with DTC. But I wouldn't expect a vast difference between SqlTransaction and a BEGIN TRAN, except for the extra round trip. However, TransactionScope is still fast, and is the most convenient option for encapsulating multiple operations in a transaction, as the ambient transaction does not need to be manually associated with the command each time.
Perhaps a better (and more significant) factor is the isolation-level. TransactionScope defaults to the highest (serializable). Lower isolation levels allow morefor less blocking (but at the risk of non-repeatable reads, etc). IIRC a TSQL transaction defaults to one of the lower levels. But the isolation level can be tweaked for all 3 options.
I'm for TransactionScope. As per Marc, use a factory method on your TransactionScope to drop the isolation level to READ COMMITTED for most common usages I can think of.
Note that you can use both SQL transactions AND TransactionScope - the SQL BEGIN TRAN / COMMIT TRAN will have little effect on TransactionScope (other than incrementing / decrementing ##TRANCOUNT) - this way if you do need to call the same SQL Sproc elsewhere, e.g. from an adhoc query that you will still get the benefit of a transaction.
The benefit of TransactionScope IMO is that it will manage DTC for you if you DO need to do 2 phase commit (e.g. Multiple databases, Queues or other XA transactions). And with SQL 2005 and later, it works with the Lightweight Transaction Manager, so DTC won't be required e.g. if all accesses are to the one database, one connection at a time.
Transaction management in the code (read c#) is an option and to be followed for managing transactions over multiple data source or system. For managing transaction for a single database, the management at the server end will be always simpler. But if you think that the code might need to cater to a scenario where multiple data-sources get added in the transaction, keep the transactions in the code level.
I belive that the store procedure will have better performance.
If you mean you write SQL Transactions in C# and use ADO.Net or similar to execute them then they are probably less efficient because SQL will cache the query plan for a stored procedure (which is also now the case for Entity Framework - though still not as quick as proc I don't think) so really you should probably be doing it the other way round - complex procedures in SQL to get the caching benefits (if only it were that simple...)
It depends on what application.
But I will say that in most cases it is best to surprised to have logic in the database. A very advantageous also to have business logic in the databse, is that then it will be the same even if you have riders a WinForms version and a web, or whatever
But if you're talking about the CLR in SQL. The negative with this, it becomes much more difficult for a DBA to find any errors or something about. performance.
Related
Morning all,
I am working on a project where I am saving data to Mongo DB and also to Sql Server (Entity Framework code first). There are a number of scenarios where I carry out a write to each database in a single block of code. I'm wondering, can any of you suggest a way to handle this in something similar to a transaction ? such that if any part of the code block fails, the whole thing should fail and rollback ?
I don't think there's any bullet-proof way of doing this since you not only have two separate connections but also two different architectures.
Assuming your SQL Server has the more complicated data model (the one that's more likely to fail for some reason) I came up with an approach in the past that worked for me:
Execute the operations sequentially not both at the same time
Execute the SQL satement first, if it fails don't execute the MongoDB statement and you'll be consistent
Should it succeed, execute the MongoDB statement next
If the MongoDB statement fails write an error log. Make sure the log is not on a remote machine so that the possibility that the logging could fail is as small as possible.
You can later use the error log to either manually or automatically salvage your data. In any case you should implement a retry policy for all statements, since the most likely reason for a failed operation is (given your code is correct) a timing issue and retrying solves this in general. If you're doing it right there will be maybe like one exotic error a month.
Of course in step 4 you could try to revert the SQL operation, instead of (or in addition to) writing a log entry. But this is mostly cumbersome and leaves you with the question what to do should the revert fail.
Maybe there still is some magic middleware to integrate MongoDB statements into an SQL transaction but for the time being I would just acknowledge that data consistency and using different databases are opposing goals. Try to monitor errors closely and reduce the error potential.
Two Phase Commit will suit your scenario. In a single transaction we can hit any number(normally we use two) of DB's and maintain our Data synchronized across the DB's.
More info on Two Phase Commit
https://lostechies.com/jimmybogard/2013/05/09/ditching-two-phased-commits/
https://www.coursera.org/learn/data-manipulation/lecture/mXS0H/two-phase-commit-and-consensus-protocols
https://sankarsan.wordpress.com/tag/two-phase-commit/
Read this post
How to force only one transaction within multiple DbContext classes?
So in WCF to flow transactions from client to server you must have your
[OperationBehavior(TransactionScopeRequired = true)]
On your instance methods and
[TransactionFlow(TransactionFlowOption.Allowed)]
On your service interfaces. And everything works. However, I find it concerning that
the server allocates a TX even if the client isn't flowing one up. It seems wasteful
I understand .NET transactions can be lightweight. Am I overreacting? Should I just
trust in .NET and let it allocate a needless local transaction? I'm worried it's
unnecessary bulk, and even more worried it may get promoted to MSDTC involvement
EDIT 1:
The operation at hand which makes this clumsy is:
insert on table A
insert on table B
read on table A
insert on table C
Operation 3, read MUST be marked up as above as transactionscoperequired. Otherwise since TX is not flowed, read times out. I find this a little weird, brute forcing a TX to exist for a read-only operation. It implies I'll have to mark most of the WCF calls in the system with a TransactionScopeRequired=true
A transaction is a tiny .NET in-memory data structure. It is nothing. What's expensive are the resource enlistments. That said, you are going to have at least one such enlistment.
Transactions usually help with database throughput, especially with writes.
You probably want your method to execute under a transaction anyway because you want effects to be atomic and reads to be consistent. It doesn't matter whether the client requests a tran or not.
and even more worried it may get promoted to MSDTC involvement
That's a valid concern. That said distributed transactions are best avoided because they are slow and they do not work at all with some HA strategies like mirroring and AG.
I'm maintaining a ASP/C# program that uses an MS SQL Server 2008 R2 for its database requirements.
On normal and perfect days, everything works fine as it is. But we don't live in a perfect world.
An Application (for Leave, Sick Leave, Overtime, Undertime, etc.) Approval process requires up to ten separate connections to the database. The program connects to the database, passes around some relevant parameters, and uses stored procedures to do the job. Ten times.
Now, due to the structure of the entire thing, which I can not change, a dip in the connection, or heck, if I put a debug point in VS2005 and let it hang there long enough, the Application Approval Process goes incomplete. The tables are often just joined together, so a data mismatch - a missing data here, a primary key that failed to update there - would mean an entire row would be useless.
Now, I know that there is nothing I can do to prevent this - this is a connection issue, after all.
But are there ways to minimize connection lag / failure? Or a way to inform the users that something went wrong with the process? A rollback changes feature (either via program, or SQL), so that any incomplete data in the database will be undone?
Thanks.
But are there ways to minimize connection lag / failure? Or a way to
inform the users that something went wrong with the process? A
rollback changes feature (either via program, or SQL), so that any
incomplete data in the database will be undone?
As we discussed in the comments, transactions will address many of your concerns.
A transaction comprises a unit of work performed within a database
management system (or similar system) against a database, and treated
in a coherent and reliable way independent of other transactions.
Transactions in a database environment have two main purposes:
To provide reliable units of work that allow correct recovery from failures and keep a database consistent even in cases of system
failure, when execution stops (completely or partially) and many
operations upon a database remain uncompleted, with unclear status.
To provide isolation between programs accessing a database concurrently. If this isolation is not provided, the program's outcome
are possibly erroneous.
Source
Transactions in .Net
As you might expect, the database is integral to providing transaction support for database-related operations. However, creating transactions from your business tier is quite easy and allows you to use a single transaction across multiple database calls.
Quoting from my answer here:
I see several reasons to control transactions from the business tier:
Communication across data store boundaries. Transactions don't have to be against a RDBMS; they can be against a variety of entities.
The ability to rollback/commit transactions based on business logic that may not be available to the particular stored procedure you are calling.
The ability to invoke an arbitrary set of queries within a single transaction. This also eliminates the need to worry about transaction count.
Personal preference: c# has a more elegant structure for declaring transactions: a using block. By comparison, I've always found transactions inside stored procedures to be cumbersome when jumping to rollback/commit.
Transactions are most easily declared using the TransactionScope (reference) abstraction which does the hard work for you.
using( var ts = new TransactionScope() )
{
// do some work here that may or may not succeed
// if this line is reached, the transaction will commit. If an exception is
// thrown before this line is reached, the transaction will be rolled back.
ts.Complete();
}
Since you are just starting out with transactions, I'd suggest testing out a transaction from your .Net code.
Call a stored procedure that performs an INSERT.
After the INSERT, purposely have the procedure generate an error of any kind.
You can validate your implementation by seeing that the INSERT was rolled back automatically.
Transactions in the Database
Of course, you can also declare transactions inside a stored procedure (or any sort of TSQL statement). See here for more information.
If you use the same SQLConnection, or other connection types that implement IDbConnection, you can do something similar to transactionscopes but without the need to create the security risk that is a transactionscope.
In VB:
Using scope as IDbTransaction = mySqlCommand.Connection.BeginTransaction()
If blnEverythingGoesWell Then
scope.Commit()
Else
scope.Rollback()
End If
End Using
If you don't specify commit, the default is to rollback the transaction.
I have to implement Transactions in my code. I have the following options:-
TransactionScope from C# code:- I will use this case if i have some logical code in transaction along with my Database calls.Transaction rolls back and locks are released if command timeouts are there.
Having Explicit transactions in SP:- In case of command timeout, Transactions remain opens and locks are not released.
Has any one of you faced similar issues. Please suggest. Also tell me setting XACT_ABORT_ON will help in the second case.
If your stored procedure is not an "interface procedure" (called by third-party outside your code) I recommend using TransactionScope or creating SqlTransaction in code for your procedure call. Handling transactions in code is much easier. You may read this article: http://www.code-magazine.com/Article.aspx?quickid=0305111 - as you can see if you start using transactions in stored procedures things may get unnecesarily complicated.
I always use SET XACT_ABORT ON
Server side transactions don't require MSDTC and have less overhead
TRY/CATCH makes the stored procs more reliable
See my answer here for a safe stored proc template which will deal with nested transactions too: Nested stored procedures containing TRY CATCH ROLLBACK pattern?
I am having more then 20 transaction in in one shot. I want to use transaction scope with this. Is it possible? And If possible then what is the advantage of using transacation scope class over simple transaction.
What is the best practice to use transaction scope?
The advantages of TransactionScope are:
you don't have to pass a transaction around (ADO.NET should enlist automatically)
which means that you can even use a TransactionScope to add transactions to existing, closed-source code (i.e. no changes are required)
a TransactionScope can (via DTC) span multiple resources (i.e. multiple databases, or a database and an MSMQ server, etc)
But you pay for this a little bit with speed. A connection-based transaction is slightly quicker (not much), but can only span a single resource and needs to be attached manually to all your DAL code. However, if you only talk to a single SQL2005/SQL2008 instance, then it can use the "LTM" - meaning it doesn't have to involve DTC (which is where most of the performance cost comes from) unless it absolutely needs to. Many TransactionScope operations can therefore complete talking only to the database.
If you want to span 20 operations, then TransactionScope should be ideal - it'll save you having to pass the transactions around, and allow each operation to manage their connection locally - making for highly re-usable code. Indeed, TransactionScope can be nested in the ways you expect, so you can have:
void Deposit(...) { /* uses TranScope to do a deposit */ }
void Debit(...) { /* uses TranScope to do a debit */ }
void Transfer(...) { /* uses a TranScope to span Debit/Deposit */ }
To do this using database transactions you'd need to pass the connection and transaction objects to each method, which quickly gets ungainly - especially if you need to code to work with/without an existing open transaction (lots of "if(tran==null)" etc).
For more information, see Transactions in .net