Best way to track locks - SQL Server - sql-server

We have a new sp getting released and during testing we found that when it runs its blocking other OLTP transactions. We found that initially it was because the new sp was causing lock escalation on a table and we reduced the number of batch size and was able to avoid that. even after avoiding lock escalation, it is still blocking oltp transactions that are coming in.
I think its locking the same row which the oltp transaction is updating.
I need to find a way to track all the locks held and release by the new sp. I tried trace/xevents(lock acquired/release) and it does not look like its capturing all the lock, may be cause it happens so fast.
Just to understand how lock acquired look like, i tested it out by doing a select * from atable. but it gives me different results. When we do select * doesnt it put a series of page locks, so i should be seeing shared page locks in the trace. but all i see is IS lock acquired and released.
what is the best way to track all the locks for a given transaction?

I ran below query in one session
begin tran
update orderstst
set unitprice=unitprice+1
waitfor delay '00:00:20'
and ran below dmv while the query is running on other session..
select resource_database_id,request_mode,request_type,request_status,txt.text
from sys.dm_tran_locks lck
join
sys.dm_exec_requests ec
on ec.session_id=lck.request_session_id
cross apply
sys.dm_exec_Sql_text(ec.sql_handle) txt
I got below data...
when the transaction is still not committed,but completed,i ran above dmv again.but didnt get any output.since this is not currently executing.
But running below dmv,will still give me lock info of all sessions holding locks..so you will be able to identify which session is holding more locks
select resource_database_id,request_mode,request_type,request_status
from sys.dm_tran_locks lck
join
sys.dm_exec_sessions ec
on ec.session_id=lck.request_session_id
Above query gives me below info..
So in summary,you have to run DMV1 or DMV2 for some period through sql agent job and insert into some table for later analaysis..
Further from SQL 2012,you can use extended events also..
Go to Management ->Extended Events ,Right Click and say ,start new session wizard.
Give it a name and check start at server startup
next screen gives you an option to select default template or not,i choose default template for locks as shown below and click next..
In the next screen,you can choose different events,in channel,select all channels and do the same in categories too and select the events of your interest,i choose below ..
In this screen,you can select actions ,i choose text ,sessionid
In next screen,filter like say for example ..gather events only for a databasename like 'somename' or query like some text..
Next screen is where you can save file to disk for later analysis..
Complete rest of screens and finally select start event session immediately option..
When you are done with gathering data,go to extended events and stop the session you created.Right click and say view target data..which shows you below screenn
EDIT: as of 12/3/2019 the start new session wizard is now located here:

Related

SQL Server 2008 - how to raise error, when trying to update locked row?

In my application, several users have the ability to read or modify the same tables. However, when one row is modified by a user, the others should not be able to use it anymore.
I am using Transactions with ISOLATION LEVEL READ UNCOMMITED. The Problem is, that when a user updates a row in a table and another user tries to update the same row - the second Transaction will wait for the first Transaction to ROLLBACK/COMMIT, before it can update the row.
What i want to do is to raise an error in this Situation, for the second user - so he does not have to wait so long.
How can I do this??
The Problem is that the Transactions are quite large (several procedures included), so there would be a posibility of blocking some users for quite some time because of the lock.
Thank you
You might be able to use a NOWAIT hint when the second user attempts his query from his own transaction:
User one
BEGIN TRAN
SELECT *
FROM someTable
WHERE blah
User two
(first user's transaction still open)
BEGIN TRAN
SELECT *
FROM someTable WITH(NOWAIT)
WHERE blah
I recall reading somewhere that only Oracle and Postgres support fail fast lock acquisitions. If so, then the above hint might be ignored.

TABLOCKX not working

I am playing with my SQL Server 2012 trying to get a hold of the locks. Based on a tutorial I saw, I tried to test obtaining an exclusive lock on a table so that no other query would be able to read information from it, until the transaction is not over, but its just not working. Even though it was working in the video, here is my query in the first window :
use TSQL2012
BEGIN transaction
update tele with (TABLOCKX, holdlock)
set cor = '12'
waitfor delay '00:05'
go
then in a second query window I simply tried:
select * from tele
and it worked fine, although on theory there should have been "exclusive" lock preventing that. Why is that happening? I tried also with
set transaction isolation level serializable on
and also without the delay but the select is always successful. Any ideas?
I've tried this on two different tables and can easily reproduce what you've found. Here is what is happening:
If Sql-Server is returning rows to the SELECT query before the table is updated then its VERY probable that at that moment, there are already locks on your tele table that are incompatible with an exclusive lock. For example, if there is another session somewhere that already has a reader lock on the table then your UPDATE statement will be SUSPENDED with a WAIT_TYPE of LCK_M_X, meaning that your UPDATE is blocked, waiting for locks that are incompatible with an exclusive lock to be released. Since all locks are incompatible with an exclusive table lock then when any other session is accessing the table with any kind of lock, your update statement will be suspended.
In a 3rd instance of SQL Management Studio, right click your server and open activity monitor. Filter for your database and login and re-run the experiment. If the table is something that applications use frequently and the SELECT runs before the UPDATE, then you will notice a LCK_M_X WAIT_TYPE on the UPDATE.
Try creating a new table that only you know about and re-run the experiment. It should work.

Locking database on SELECT INTO

I have a query that return a huge number of rows and I am using SELECT INTO (instead of INSERT INTO) to avoid having problems with transaction log.
The problem is: while this query is running, I can read objects but not showing them in object explorer. When I try to expand the tables item, for example, I receive the message bellow:
Is there a way to avoid this problem?
As M.Ali explained, SELECT INTO has a table lock on your new table, which is also locking the schema objects that SSMS is trying to query in order to build the tree browser.
I would suggest tuning the query so that the statement can run faster. Since this is inserting into a Heap with no indexes and has the tablock, it will be minimally logged as you stated. So it is likely the SELECT part of the statement that is causing things to be slow. See if that query can be optimized or broken into smaller pieces so that the statement does not run so long.
Alternatively, perform the insert in smaller batches using INSERT INTO (and not specifying the tablock hint)
Now here is a Test for you which will give answer to your question...
Open a Query window in SSMS. Write any query which will return any number or rows, could be only one row or maybe 10. and do as follows
Query window 1
BEGIN TRANSACTION;
SELECT *
INTO NEW_Test_TABLE
FROM TABLE_NAME
Query Window 2
Now Open another window and write a SELECT statement against this NEW_Test_TABLE.
SELECT * FROM NEW_Test_TABLE
Your Query will never finish executing,,, no results will be returned (At this time NEW_Test_TABLE only exists in buffer chache). Unless you go back to your 1st Query Window and commit the transaction, And if you goto query window 1 and ROLLBACK TRANSACTION NEW_Test_TABLE would have existed once in buffer chache and no longer exist anywhere.
Similarly when your Select into statement in being executed nothing is committed to disk, therefore SSMS cannot see it neither can show you any information about it via Object explorer.
So the answer is while the query is being executed be patient and let SQL Server Commit the SELECT INTO transaction to disk and you will be able to access it VIA querying it or via Object explorer.

Does inserting data into SQL Server lock the whole table?

I am using Entity Framework, and I am inserting records into our database which include a blob field. The blob field can be up to 5 MB of data.
When inserting a record into this table, does it lock the whole table?
So if you are querying any data from the table, will it block until the insert is done (I realise there are ways around this, but I am talking by default)?
How long will it take before it causes a deadlock? Will that time depend on how much load is on the server, e.g. if there is not much load, will it take longer to cause a deadlock?
Is there a way to monitor and see what is locked at any particular time?
If each thread is doing queries on single tables, is there then a case where blocking can occur? So isn't it the case that a deadlock can only occur if you have a query which has a join and is acting on multiple tables?
This is taking into account that most of my code is just a bunch of select statements, not heaps of long running transactions or anything like that.
Holy cow, you've got a lot of questions in here, heh. Here's a few answers:
When inserting a record into this table, does it lock the whole table?
Not by default, but if you use the TABLOCK hint or if you're doing certain kinds of bulk load operations, then yes.
So if you are querying any data from the table will it block until the insert is done (I realise there are ways around this, but I am talking by default)?
This one gets a little trickier. If someone's trying to select data from a page in the table that you've got locked, then yes, you'll block 'em. You can work around that with things like the NOLOCK hint on a select statement or by using Read Committed Snapshot Isolation. For a starting point on how isolation levels work, check out Kendra Little's isolation levels poster.
How long will it take before it causes a deadlock? Will that time depend on how much load is on the server, e.g. if there is not much load will it take longer to cause a deadlock?
Deadlocks aren't based on time - they're based on dependencies. Say we've got this situation:
Query A is holding a bunch of locks, and to finish his query, he needs stuff that's locked by Query B
Query B is also holding a bunch of locks, and to finish his query, he needs stuff that's locked by Query A
Neither query can move forward (think Mexican standoff) so SQL Server calls it a draw, shoots somebody's query in the back, releases his locks, and lets the other query keep going. SQL Server picks the victim based on which one will be less expensive to roll back. If you want to get fancy, you can use SET DEADLOCK_PRIORITY LOW on particular queries to paint targets on their back, and SQL Server will shoot them first.
Is there a way to monitor and see what is locked at any particular time?
Absolutely - there's Dynamic Management Views (DMVs) you can query like sys.dm_tran_locks, but the easiest way is to use Adam Machanic's free sp_WhoIsActive stored proc. It's a really slick replacement for sp_who that you can call like this:
sp_WhoIsActive #get_locks = 1
For each running query, you'll get a little XML that describes all of the locks it holds. There's also a Blocking column, so you can see who's blocking who. To interpret the locks being held, you'll want to check the Books Online descriptions of lock types.
If each thread is doing queries on single tables, is there then a case where blocking can occur? So isn't it the case that a deadlock can only occur if you have a query which has a join and is acting on multiple tables?
Believe it or not, a single query can actually deadlock itself, and yes, queries can deadlock on just one table. To learn even more about deadlocks, check out The Difficulty with Deadlocks by Jeremiah Peschka.
If you have direct control over the SQL, you can force row level locking using:
INSERT INTO WITH (ROWLOCK) MyTable(Id, BigColumn)
VALUES(...)
These two answers might be helpful:
Is it possible to force row level locking in SQL Server?
Locking a table with a select in Entity Framework
To view current held locks in Management Studio, look under the server, then under Management/Activity Monitor. It has a section for locks by object, so you should be able to see whether the inserts are really causing a problem.
Deadlock errors generally return quite quickly. Deadlock states do not occur as a result of a timeout error occurring while waiting for a lock. Deadlock is detected by SQL Server by looking for cycles in the lock requests.
The best answer I can come up with is: It depends.
The best way to check is to find your connection SPID and use sp_lock SPID to check if the lock mode is X on the TAB type. You can also verify the table name with SELECT OBJECT_NAME(objid). I also like to use the below query to check for locking.
SELECT RESOURCE_TYPE,RESOURCE_SUBTYPE,DB_NAME(RESOURCE_DATABASE_ID) AS 'DATABASE',resource_database_id DBID,
RESOURCE_DESCRIPTION,RESOURCE_ASSOCIATED_ENTITY_ID,REQUEST_MODE,REQUEST_SESSION_ID,
CASE WHEN RESOURCE_TYPE = 'OBJECT' THEN OBJECT_NAME(RESOURCE_ASSOCIATED_ENTITY_ID,RESOURCE_DATABASE_ID) ELSE '' END OBJETO
FROM SYS.DM_TRAN_LOCKS (NOLOCK)
WHERE REQUEST_SESSION_ID = --SPID here
In SQL Server 2008 (and later) you can disable the lock escalation on the table and enforce a WITH (ROWLOCK) in your insert clause effectively forcing a rowlock. This can't be done prior to SQL Server 2008 (you can write WITH ROWLOCK, but SQL Server can choose to ignore it).
I'm speaking generals here, and I don't have much experience with BLOBs as I usually advise developers to avoid them, especially if larger than 1 MB.

Sql server table can be queried but not updated

i have a table which was always updatable before, but then suddenly i can no longer update the any of the columns in the table. i can still query the whole table and the results come back very fast, but the moment i try to update a column in the table, the update query simply stalls and does nothing.
i tried using
select req_transactionUOW
from master..syslockinfo
where req_spid = -2
to see if some orphaned transaction was locking the table, but it returns no results.
i can't seems to find signs of my table being locked, but simply cannot update it. any clues as to how to fix the table or whatever state it is in?
Could you please issue this query:
SELECT COUNT(*)
FROM mytable WITH (UPDLOCK, READPAST)
which will skip the locked records and make sure it returns the same number of records as
SELECT COUNT(*)
FROM mytable
You may need to repeat it with every index on the table forced, to make sure that no index resources is locked as well.
When you say "times out", does it hit the client timeout? For example, the default .net command timeout is 30 seconds. I would suggest increasing this to a very large value or running the update in SQL tools (by default no timeout set).
Other than that, an update will finish at some point or error and rollback: are you leaving enough time?
There is also the blocking, last index rebuild, last statistics update, triggers, accidental cross join, MDF or LDF file growth, poor IO, OS paging... etc. And have you restarted the SQL instance or server to remove environmental issues and kill all other connections?
There simply isn't enough information to make a judgement right now sorry.
I'm guessing this isn't a permissions issue as you're not getting an error.
So the closest I have had to this before is when the indexes on the table have become corrupt. Have you tried dropping the indexes and recreating them? Try one by one at first.
If you suspect locking, one of the first things I would do would be to run sp_lock. It will give you a list of all of the current locks held. You can use the DB_NAME and OBJECT_NAME functions to get the names that correspond to the dbid and ObjId columns.
Have you got any triggers on the table?
If so it could be that the trigger is failing so preventing the update.
Can you update other tables? If not (or anyways, if you like) you could check if the transaction log is full (if you use the full recovery model)/the partition your transaction log resides on is full. I think if SQL Server is unable to write to the transaction log you would/could experience this behaviour.
DBCC would be your friend: DBCC SQLPERF(LOGSPACE) shows you, how much (in percent) of your log is used. If it is (close to) 100% this might be your issue.
Just my two pennies worth.

Resources