SQL Server 2008 - adding a column to a replicated table fails - sql

We have scenario:
SQL Server 2008
we have replication on the db
we have simple sproc that performs ALTER of one of the table (add new column)
isolation level is default (READ COMMITTED)
Stored procedure fails with error:
You can only specify the READPAST lock in the READ COMMITTED or REPEATABLE READ isolation levels
Questions:
What causes the problem?
How to fix that?
UPDATE:
I believe this is very common problem so I'm wonder why there is no good explanations why replication causes this issue

You cant only specify READPAST when reading from committed data.
Reason is because readpast ignores locked rows, so when you use it, you are pretty much saying to sql server, give me everything that has not been touched by any other transaction. Example from BOL:
For example, assume table T1 contains a single integer column with the
values of 1, 2, 3, 4, 5. If transaction A changes the value of 3 to 8
but has not yet committed, a SELECT * FROM T1 (READPAST) yields values
1, 2, 4, 5.
It doesnt make much sense saying that on a read uncommitted isolation level, which by default, brings back uncommitted values. Its kinda requesting two opposite things.

SET TRANSACTION ISOLATION LEVEL READ COMMITTED
//REST OF QUERY ADD WITH (READPAST) after the table names Ex. SELECT FOO.* FROM dbo.foobar FOO WITH (READPAST)
And/or this should help you.
http://support.microsoft.com/kb/981995

Are you sure isolation level is set to READ COMMITTED?
I've seen this error when isolation is set to serializable and you use ALTER TABLE on a table published for replication. This is because some replication stored procedures use the READPAST hint to avoid blocking which can only be used in READ COMMITTED or REPEATABLE READ isolation levels.
If you are sure that the isolation level is set to READ COMMITTED, then I would recommend contacting Microsoft PSS on this one as it should not be happening. They will be able to assist you better.

Related

Sql Table Locked By Readpast

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.

Sql Server Isolation level Read Uncommitted is locking

I'm defining the isolation level as READ UNCOMMITTED because this is a long running process on a few tables and there's no risk for dirty read because I'm just inserting new data.
Based on my understanding, because I'm using this isolation level, I should be able to execute SELECT statements from the table where I'm inserting rows but I can't, it gets blocked.
Why is this isolation level blocking the SELECT statement?
It is supposed to allow to query those tables and, in the worst case scenario, retrieve dirty data.
Just in case this helps, I'm working with a CURSOR (I know, I hate them too but I did not write this code) over really big data and multiple tables.
When you do an insert (regardless of what the isolation level is) locks occur. There is no way to insert rows without doing some locking. The isolation levels affect reading.
If you do a select * from tablea with (nolock) you will read uncommitted rows but for a brief period (because of the insert) a lock will occur.

How to set all tables and all views isolation level to read uncommited?

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)

Deadlocks - Will this really help?

So I've got a query that keeps deadlocking on me. People who know the system well can't figure out why the sproc is deadlocking, but they tell me that I should just add this to it:
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Is this really a valid solution? What does that do?
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
This will cause the system to return inconsitent data, including duplicate records and missing records. Read more at Previously committed rows might be missed if NOLOCK hint is used, or here at Timebomb - The Consistency problem with NOLOCK / READ UNCOMMITTED.
Deadlocks can be investigated and fixed, is not a big deal if you follow the proper procedure. Of course, throwing a dirty read may seem easier, but down the road you'll be sitting long hours staring at your general ledger and wondering why the heck it does not balance debits and credits. So read again until you really grok this: DIRTY READs ARE INCONSISTENT READS.
If you want a get-out-of-jail card, turn on snapshot isolation:
ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON
But keep in mind that snapshot isolation does not fix the deadlocks, it only hides them. Proper investigation of the deadlock cause and fix is always the appropriate action.
NOCOUNT will keep your query from returning rowcounts back to the calling application (i.e. 1000000 rows affected).
TRANSACTION ISOLATION LEVEL READ UNCOMMITTED will allow for dirty reads as indicated here.
The isolation level may help, but do you want to allow dirty reads?
Randomly adding SET options to the query is unlikely to help I'm afraid
SET NOCOUNT ON
Will have no effect on the issue.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
will prevent your query taking out shared locks. As well as reading "dirty" data it also can lead to your query reading the same rows twice, or not at all, dependant upon what other concurrent activity is happening.
Whether this will resolve your deadlock issue depends upon the type of deadlock. It will have no effect at all if the issue is 2 writers deadlocking due to non linear ordering of lock requests. (transaction 1 updating row a, transaction 2 updating row b then tran 1 requesting a lock on b and tran 2 requesting a lock on a)
Can you post the offending query and deadlock graph? (if you are on SQL 2005 or later)
The best guide is:
http://technet.microsoft.com/es-es/library/ms173763.aspx
Snippet:
Specifies that statements can read rows that have been modified by other
transactions but not yet committed.
Transactions running at the READ
UNCOMMITTED level do not issue shared
locks to prevent other transactions
from modifying data read by the
current transaction. READ UNCOMMITTED
transactions are also not blocked by
exclusive locks that would prevent the
current transaction from reading rows
that have been modified but not
committed by other transactions. When
this option is set, it is possible to
read uncommitted modifications, which
are called dirty reads. Values in the
data can be changed and rows can
appear or disappear in the data set
before the end of the transaction.
This option has the same effect as
setting NOLOCK on all tables in all
SELECT statements in a transaction.
This is the least restrictive of the
isolation levels.
In SQL Server, you can also minimize
locking contention while protecting
transactions from dirty reads of
uncommitted data modifications using
either:
The READ COMMITTED isolation level
with the READ_COMMITTED_SNAPSHOT
database option set to ON. The
SNAPSHOT isolation level
.
On a different tack, there are two other aspects to consider, that may help.
1) Indexes and the indexes used by the SQL. The indexing strategy used on the tables will affect how many rows are affected. If you make the data modifications using a unique index, you may reduce the chance of deadlocks.
One algorithm - of course it will not work it all cases. The use of NOLOCK is targeted rather than being global.
The "old" way:
UPDATE dbo.change_table
SET somecol = newval
WHERE non_unique_value = 'something'
The "new" way:
INSERT INTO #temp_table
SELECT uid FROM dbo.change_table WITH (NOLOCK)
WHERE non_unique_value = 'something'
UPDATE dbo.change_table
SET somecol = newval
FROM dbo.change_table c
INNER JOIN
#temp_table t
ON (c.uid = t.uid)
2) Transaction duration
The longer a transaction is open the more likely there may be contention. If there is a way to reduce the amount of time that records remain locked, you can reduce the chances of a deadlock occurring.
For example, perform as many SELECT statements (e.g. lookups) at the start of the code instead of performing an INSERT or UPDATE, then a lookup, then an INSERT, and then another lookup.
This is where one can use the NOLOCK hint for SELECTs on "static" tables that are not changing reducing the lock "footprint" of the code.

Would this prevent the row from being read during the transaction?

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.