Is it true that "Every statement (select/insert/delete/update) has an isolation level regardless of transactions"?
I have a scenario in which I have set update of statements inside a transaction (ReadCommitted).
And another set not in a transaction (select statements).
In this case when first set is executing another waits.
If I set READ_COMMITTED_SNAPSHOT for DB Deadlock occurs.
ALTER DATABASE Amelio SET ALLOW_SNAPSHOT_ISOLATION ON
ALTER DATABASE Amelio SET READ_COMMITTED_SNAPSHOT ON
To solve this problem, do I need to put "Select" statements in TransactionScope?
On SQL Server every transaction has an implicit or explicit transaction level. Explicit if called with BEGIN/COMMIT/ROLLBACK TRANSACTION, implicit if nothing like this is issued.
Start your snapshot before the update query starts. Otherwise you give SQL Server no chance to prepare the changed rows into tempdb and the Update query still has the lock open.
Another way without creating a snapshot isolation is to use SELECT <columns> FROM <table> WITH (NOLOCK) which is the way to tell SQL Server to get the rows no matter what (aka READ_UNCOMMITED). As it is a query hint it changes the isolation level even with your settings. Can work if you are not bothered which state of the row is queried - however caution needs to be used when evaluating the data received.
Related
I have a table were values can be altered by different users and records of 100k rows.
I made a stored procedure where in, it has a begin tran and at the last part
to either commit or rollback the changes depending on the situation.
So for now the problem we're encountering is a lock of that table. For example 1st user is executing the stored procedure thru the system, then the other users won't be able to select or also execute the stored procedure because the table is currently locked.
So is there anyway where I can avoid lock other than using dirty read. Or a way where I can rollback the changes made without using begin tran, because it is the main reason why the table is locked up.
Yes, you can at least (quick & dirty) enable SNAPSHOT isolation level for transactions. That will prevent locks inside the transactions.
ALTER DATABASE MyDatabase
SET ALLOW_SNAPSHOT_ISOLATION ON
ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON
See for details.
Two SP's are getting executed one after another and the second one is getting blocked by first one. They both are trying to update same table. Two SP's are as following
CREATE PROCEDURE [dbo].[SP1]
Begin
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRANSACTION ImpSchd
update Table t1 .......... ................................//updating
a set of [n1,n2....n100] records
COMMIT TRANSACTION ImpSchd
SET TRANSACTION ISOLATION LEVEL
READ COMMITTED;
END
2.
CREATE PROCEDURE [dbo].[SP2]
Begin
update Table t1 .......... ................................//updating
a set of [n101,n102.....n200] records
END
My question is when sp1 is running is snapshot level isolation why is it blocking sp2 (n both are updating different set of records)?
If i run first sp for two different set of records simultaneously it
works perfectly.
How can I overcome this situation ?
If using the snapshot level isolation is to be set for each sp updating the same table then it would be a larger change.
if two sp has to update same records in a table, how should i handle that(both sp will update different columns)?
Isolation levels only are for not blocking selects,so any DML wont be affected by Isolation levels.In this case update takes IX lock on table,page followed by taking xlock on row to update.Since you are updating in bulk ,table itself might have been locked due to lock escalation.Hope this helps
I need a sanity check ;[, a customer of mine says he is seeing data at a time when I think he should not.
example, update 2 tables
BEGIN TRANSACTION;
update table1...
update table2...
COMMIT TRANSACTION;
question - it is possible for a separate connection in the database to be triggered to read the updates to table1 before the updates in table2 are done?
Yes you can if you set the isolation level of the other reading transaction to read uncommited. https://msdn.microsoft.com/en-us/library/ms173763(v=sql.110).aspx.
It's easy to test if you start up two Sql Management Studios and run the transaction without commiting in one window, then try to select in the other window with different Isolation Levels.
Yes, it is possible, if your isolation level is set to read uncommitted.
Look at the isolation level provided by:
dbcc useroptions
https://msdn.microsoft.com/en-us/library/ms173763.aspx
http://blog.sqlauthority.com/2010/05/24/sql-server-check-the-isolation-level-with-dbcc-useroptions/
SQL Server 2008 R2 (Data Center edition - I think)
I have a very specific requirement for the database.
I need to insert a row marked with timestamp [ChangeTimeStamp]. Timestamp value is passed as a parameter. Timestamp has to be unique.
Two processes can insert values at the same time, and I happen to run into duplicate key insertion once in a while. To avoid this, I am trying:
declare #maxChangeStamp bigint
set transaction isolation level read committed
begin transaction
select #maxChangeStamp = MAX(MaxChangeTimeStamp) from TSMChangeTimeStamp
if (#maxChangeStamp > #changeTimeStamp)
set #maxChangeStamp = #maxChangeStamp + 1
else
set #maxChangeStamp = #changeTimeStamp
update TSMChangeTimeStamp
set MaxChangeTimeStamp = #maxChangeStamp
commit
set #changeTimeStamp = #maxChangeStamp
insert statment
REPEATABLE READ - causes deadlock
READ COMMITTED - causes duplicate key inserts
#changeTimeStamp is my parameter.
TSMChangeTimeStamp holds only one value.
If anyone has a good idea how to solve this I will appreciate any help.
You don't read-increment-update, this will fail no matter what you try. Alway update and use the OUTPUT clause to the new value:
update TSMChangeTimeStamp
set MaxChangeTimeStamp += 1
output inserted.MaxChangeTimeStamp;
You can capture the output value if you need it in T-SQL. But although this will do what you're asking, you most definitely do not want to do this, specially on a system that is high end enough to run DC edition. Generating the next timestamp will place an X lock on the timestamp resource, and thus will prevent every other transaction from generating a new timestamp until the current transaction commits. You achieve complete serialization of work with only one transaction being active at a moment. The performance will tank to the bottom of the abyss.
You must revisit your requirement and come up with a more appropriate one. As it is now your requirement can also be expressed as 'My system is too fast, how can I make is really really really slow?'.
Inside the transaction, the SELECT statement will acquire a shared lock if the mode is not READ COMMITTED or snapshot isolation. If two processes both start the SELECT at the same time, they will both acquire a shared lock.
Later, the UPDATE statement attempts to acquire an exclusive lock (or update lock). Unfortunately, neither one can acquire an exclusive lock, because the other process has a shared lock.
Try using the WITH (UPDLOCK) table hint on the SELECT statement. From MSDN:
UPDLOCK
Specifies that update locks are to be taken and held until the
transaction completes. UPDLOCK takes update locks for read operations
only at the row-level or page-level. If UPDLOCK is combined with
TABLOCK, or a table-level lock is taken for some other reason, an
exclusive (X) lock will be taken instead.
When UPDLOCK is specified, the READCOMMITTED and READCOMMITTEDLOCK
isolation level hints are ignored. For example, if the isolation level
of the session is set to SERIALIZABLE and a query specifies (UPDLOCK,
READCOMMITTED), the READCOMMITTED hint is ignored and the transaction
is run using the SERIALIZABLE isolation level.
For example:
begin transaction
select #maxChangeStamp = MAX(MaxChangeTimeStamp) from TSMChangeTimeStamp with (updlock)
Note that update locks may be promoted to a table lock if there is no index for your table (Microsoft KB article 179362).
Explicitly requesting an XLOCK may also work.
Also note your UPDATE statement does not have a WHERE clause. This causes the UPDATE to lock and update every record in the table (if applicable in your case).
Is there a way to lock a SELECT in a Transaction? If a SELECT occurs, no more SELECTs are executed while the first one is not finished.
Thanks!
Not sure I understand your question correctly, but if you want to impose more rigorous locking than SQL Server's default, then you can either bump up the isolation level or use a locking hint. This can be useful if you first need to SELECT something and then later, based on the value SELECTed, do an UPDATE. To avoid a phantom UPDATE from another transaction (wherein the value you previously SELECTed was changed in b/w the SELECT and UPDATE), you can impose an update lock on your SELECT statement.
Eg:
select * from mytable with (holdlock, xlock)
Notice that the SELECT statement above uses the more rigorous update lock & holds that lock for the duration of the transaction. You would also want to wrap your statements in an explicit transaction, as in:
begin transaction
select * from mytable with (holdlock, xlock) -- exclusive lock held for the entire transaction
-- more code here...
update mytable set col='whatever' where ...
commit transaction
Be wary, of course, for long-running transactions.
Might want to look at Isolation Level instead of a hint
You'll need an isolation level of SERIALIZABLE:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
The other SELECT queries will block until the transaction completes in this case. The default level is usually READ COMMITTED.
it seems you're looking for a pessimistic locking strategy but without acctually locking your data. look into Application locks in sql server.
Changing your isolation levels is generally your best choice.
But, if for whatever reason that's not an option for you - you could also do an exclusive table lock...
select * from MyTable with (tablockx)
That would prevent any other selects on the table until your transaction is finished.