I want to update a status in a DB table row and I want this to be immediately visible for other processes/transactions reading the same row. Do I have to put this statement in a separate transaction which will be committed right after the update?
I suppose this depends on the DB engine and isolation level, but as this can change I want my code to handle whatever the DB engine and isolation level is.
You have two solutions:
Use the appropriate transaction isolation level SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED (details)
Other queries can use NOLOCK (details)
Check the links from more details.
Related
I have a SQL View. I use READPAST on this SQL View. Because i don't want to see dirty data. But SQL READPAST locked this SQL View 's Table. I don't want to Table locking, i just want to locking Row.
Which method is correct?
When you select from a table you put a shared lock on it anyway...but if your table is locked and you don't want to see dirty data beside using readpast you should make sure that your table has an index and then set page lock to off and row lock to on..of course your query should have a where clause on on yhe indexed column..
https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-2017
It seems the problem is isolation level.You must use read committed snapshot if you use sql server.This provides that you fetch only committed data.Also this does not cause table lock.But you must enable it in database level.You can look https://www.google.com/amp/s/www.red-gate.com/simple-talk/sql/performance/read-committed-snapshot-isolation-high-version_ghost_record_count/amp/ for configuration.
Also readpast is not a solution.It skips locked rows.So you get missing results.When a row is updated,Your select query ignore this row.But in read committed isolation level you get committed version of this row even if locked by another transaction and
this isolation level does not lock your table.I assume that you use default isolation level for the transaction.if you do not set a isolation level to the transaction it uses default isolation level and this is read committed.Read committed snapshot only works under read committed isolation level without locking.Except this for example in serializable isolation level it continues to lock.So you can use default isolation level for the transaction calling your view.
I have to get data from a table which is excessively updated. Dirty read is not a problem for me. I decided to use read uncommitted in my stored procedure.
Then I added this line before select:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
I learned that this code scope is connection, unlike nolock. I heard you should change it to default after your work is done is that right?
Do I have to just add
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
end of the line? I could not find any example on the web where isolation level is changed back after work is done. Is there any example?
Only one of the isolation level options can be set at a time, and it remains set for that connection until it is explicitly changed. All read operations performed within the transaction operate under the rules for the specified isolation level unless a table hint in the FROM clause of a statement specifies different locking or versioning behavior for a table.
...
If you issue SET TRANSACTION ISOLATION LEVEL in a stored procedure or trigger, when the object returns control the isolation level is reset to the level in effect when the object was invoked. For example, if you set REPEATABLE READ in a batch, and the batch then calls a stored procedure that sets the isolation level to SERIALIZABLE, the isolation level setting reverts to REPEATABLE READ when the stored procedure returns control to the batch.
https://msdn.microsoft.com/en-us/library/ms173763.aspx
Currently, we have a lot of background services running. These services are inserting/updating bulk amount of data to the server. This is why our SELECT queries are blocking. So, for temporary I need to make all all tables and all views isolation level to read uncommitted. Is it possible?
First of all, I would like to tell you, reading uncommited data is nothing but Dirty Read.
for eg, of you are working with AdventureWorks Database, then you just fire this query
use AdventureWorks
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITED.
This will help you to view all the records created / updated by some transaction but not yet commited.
By default, in SQL Server, Transaction Isolation Level is set to READ COMMITED.
so untill there is exclusive lock locked by some query, other transaction is not able to view the data of other transaction which is in uncommited state.
Feel free to reply about the result.
Kind Regards,
Ashay (India)
in your select query use hint NoLock
select * from userTbl with(NOLOCK)
Experiment details:
I am running this in Microsoft SQL Server management studio.
On one query window I run:
BEGIN TRANSACTION a;
ALTER table <table name>
ALTER column <column> varchar(1025)
On the other I run:
SELECT 1
FROM sys.objects
WHERE name = ' <other_table name>'
Or this:
SELECT 1
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[<other_table name>]')
For some reason the select with name= does not return until I do commit to the tranaction.
I am doing transaction to simulate a long operation of alter column that we have in our DB sometimes. Which I don't want to harm other operations.
This is because you are working under Default Transaction Isolation Level i.e ReadCommited .
Read Commited
Under Read Commited Trasanction Isolation Level when you explicitly Begin a Transaction Sql Server obtains Exclusive locks on the resources in order to maintain data integrity and prevent users from dirty reads. Once you have begin a transaction and working with some rows other users will not be able to see them rows untill you Commit your transaction or Rollback. However this is sql server's default behaviour this can be changed under different Transaction Isolation Level for instance under Read Uncommited You will be able to read rows which are being Modified/Used by other users , but there is a chance of you have Dirty Reads "Data That you think is still in database but Other user has changed it."
My Suggestion
If Dirty Reads is something you can live with go on than
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITED;
Preferably Otherwise stick to default behaviour of Sql Server and let the user wait for a bit rather than giving them dirty/wrong data. I hope it helps.
Edit
it does not matter if the both queries are executed under same or different isolation level what matters is under what isolation level the queries are being executed, and you have to have Read Uncommited transaction isolation level when you are making use of explicit transactions. If you want other user to have access to the data in during a transaction. Not recomended and a bad practice, I would personally use Snapshot Isolation which will extensively make use of tempdb and will only show the last commited data.
I remember an example where reads in a transaction then writing back the data is not safe because another transaction may read/write to it in the time between. So i would like to check the date and prevent the row from being modified or read until my transaction is finish. Would this do the trick? and are there any sql variants that this will not work on?
update tbl set id=id where date>expire_date and id=#id
Note: date>expire_date happens to be my condition. It could be anything. Would this prevent other transaction from reading the row until i commit or rollback?
In a lot of cases, your UPDATE statement will not prevent other transactions from reading the row.
ziang mentioned transaction isolation levels.
Depending on the isolation level, databases use different types of locking. At the highest level, locking can be divided into two categories:
- pessimistic,
- optimistic
MS SQL 2008, for example, has 6 isolation levels, 4 of them are pessimistic, 2 are optimistic. By default , it uses READ COMMITTED isolation level, which falls into the pessimistic category.
Oracle, on another note, uses optimistic locking by default.
The statement that will lock your record for writing is
SELECT * FROM TBL WITH UPDLOCK WHERE id=#id
From that point on, no other transaction will be able to update your record with id=#id
And only transactions running in isolation level READ UNCOMMITTED will be able to read it.
With the default transaction level, READ COMMITTED, no other thansaction will be able to read or write into this record until you either commit or roll back your entire transaction.
It depends on the transaction isolation level you set on your transaction control. There are 4 types of read
READ UNCOMMITTED: this allows the dirty read
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
for more info, you can check msdn.
You should be able to do this in a normal select using a combination of
HOLDLOCK/ROWLOCK
It very well may work. Different platforms offer different services. For instance, in T-SQL, you can simply set the isolation level of the transaction and, as a result, force a lock to be obtained. I don't know what platform you are using so I cannot answer your question definitively.