1

My company is currently running SQL Server 2000, and about to make the jump to SQL Server 2012, but before we move the upgrade, we want to try and clear up a performance issue that has recently cropped up and is plaguing our ability to do business.

A few months ago we decided that we wanted to add a text field to one of our sql server tables to try and capture a specific event. I thought I’d try and add the column during the day, which in retrospect was probably the first mistake, but I figured if people were using the table, SQL Server wouldn’t allow me to add the column. On this attempt, the extra column was accepted and added to the table. I then coded our Access front end to write to this new column.

Soon after, users started experiencing the Access GUI “locking up”, and eventually throwing a query time out error.

Here's how the error occurs. After clicking a save button in an Access front end, which would then build a T-SQL statement in VBA to update or save a new record, users would not see an Access message box saying that the save completed successfully or that an error had occurred. Instead they would get a Access system dialogue box that said there was a query time out. At this time I deleted the column that I added, hoping that would fix the issue.

I started analysis by having everyone close their Access program, then have the person who was experiencing problems re-open and try to save again. This worked for that user, and I would allow everyone else back into the system at this time. Of course I wasn’t sure why this worked at the time, so I tried looking more into the issue. Further analysis led me to sp_who2. Running this would give me all the users and the SPID of who was blocking. This gave me a quicker way of getting things working again because I could kill the offending SPID and allow everyone else to continue working. Of course the kill results in a rollback, so not all data is being saved and I have to tell the owner of the killed process that they must re-enter all their data a second time. To date, I continuously monitor this database in this way, and if I find something blocked, this is how I fix it.

I know the problem is with a single table in this database, first because trouble only started after I tried to enter a new column, but also because every time a save or update is performed, it locks when writing to this particular table. At the time, I diagnosed this because I asked my users what action they were trying to perform, and in all cases, they were trying to do something to this particular table. In fact, changes to other tables in this same Db execute with no issues. So I felt the problem may be related to corruption to this table.

First thing I did was run a CHECKDB and CHECKTABLE, but neither of these returned an issue with the table. So we decided to rebuild the table. I rebuilt the table by hand, then copied the data over from the original table to the new table. I believe I used a sql tool for this, but I may have run an insert into. (It’s been a while and I didn’t document.) Either way, it didn’t work. The organization continued to experience blocking. So then I re-indexed the table, and that seemed to work, for about a day, and then the error “came back.” Since then I found INPUTBUFFER, which I was running on the SPID of the blocking user every time for a while. Almost every time, the INPUTBUFFER would return a SELECT statement, though I don’t think that’s what was throwing the block. I don’t think the SELECT was throwing the block because in the Access GUI what happens is you hit the save button, it runs a save or update, then it runs a select to refresh the Access screen. I would think that if the SELECT was throwing the block that the save would have happened, but when recalling the record after the process starts blocking, and the process is killed, the user changes are never saved to the record. I’m not entirely sure how INPUTBUFFER works. I know it supposedly returns the last statement sent to SQL Server, but if the save didn’t commit, could Access still be sending SQL to SQL Server?

I will also add that I never seem to throw a block when I’m working in SQL Server Management Studio itself. I have obviously felt the repercussions of an existing block which will hang my sql statement, but I’ve never thrown a block to my knowledge. To that end I’ve also updated the ODBC connectors from every user to 10.0. This doesn’t seem to have a negative or positive impact on the issue.

So I'm not sure what to do next. Any suggestions would be appreciated.

  • When dealing with an Access application which includes ODBC links to server tables, recreate the link in Access after making any change to the *design* (like add column) of the server table. – HansUp Dec 09 '13 at 15:30
  • Good idea. I think I've tried this before, but maybe not since I rebuilt the table. I'll do that and post back if this worked or not. Thanks. – user3083114 Dec 09 '13 at 16:16

1 Answers1

1

When working with linked tables, make sure your SQL Server table has a unique identifier.

Check out my article on how to link tables.

http://craftydba.com/?p=1893

The second question is what type of lock are you getting?

Below is some code from a presentation I do from time to time. Change the adventureWorks2012 to your database name.

This should show you what locks are occuring. Pick the correct hobt_id or object_id to find out details.

--
-- Locked object details
-- 

-- Old school technique
EXEC sp_lock
GO

-- Lock details
SELECT
    resource_type, resource_associated_entity_id,
    request_status, request_mode,request_session_id,
    resource_description 
FROM sys.dm_tran_locks
WHERE resource_database_id = DB_ID('AdventureWorks2012')
GO

-- Page/Key details
SELECT object_name(object_id) as object_nm, *
FROM sys.partitions
WHERE hobt_id = 72057594047037440
GO

-- Object details
SELECT object_name(1266103551)
GO

Blocking is part of how SQL server allows cooperative execution between sessions. The problem is when it turns into a deadlock or SQL server does not detect a deadlock.

Some solutions are to change the isolation level. But this has its own issues - phantom reads, dirty reads, unrepeatable reads, and low concurrency. The first place to look is the lock sequence. Please post an image.

Since you are using SQL Server 2000, look at sp_indexoption.

Overview:

http://technet.microsoft.com/en-us/library/aa213036(v=sql.80).aspx

"For example, when a table is known to be a point of contention, it can be beneficial to disallow page-level locks, thereby allowing only row-level locks. Or, if table scans are always used to access an index or table, disallowing page-level and row-level locks can help by allowing only table-level locks."

Details:

http://technet.microsoft.com/en-us/library/aa238800(v=sql.80).aspx

Try stopping the MS Access program from using page locks.

Sample call from BOL:

USE Northwind
GO

EXEC sp_indexoption 'Customers.City', 
   'disallowpagelocks', 
   TRUE
GO

Use sp_who2 to get the two SPIDS that are blocking.

enter image description here

Use DBCC INPUTBUFFER to get the actual SQL statement for both SPIDS.

enter image description here

CRAFTY DBA
  • 14,351
  • 4
  • 26
  • 30
  • The SQL Server table has a Clustered Index which is also the primary key. I can run the EXEC sp_lock, but the Lock details part of your script won't run for me. Remember I'm still working with a SQL Server 2000 installation. I'm finding that many of the tools I've found on the web are not compatible with 2000, which only makes this issue more fun to try and fix. Any other suggestions? – user3083114 Dec 09 '13 at 16:46
  • Msg 208, Level 16, State 1, Line 1 Invalid object name 'sys.dm_tran_locks'. – user3083114 Dec 09 '13 at 16:47
  • Use sp_lock on SQL Server 2000. The DMV's were introduced in 2005, Use DBCC INPUTBUFFER to track down the query. I think sys.partitions and object_name might not even be supported. I can not check since MSDN no longer has 2000 info, it was discontinued this year. – CRAFTY DBA Dec 09 '13 at 16:51
  • So sp_lock does work for me. You want me to run that and post the results? I'm not a DBA so I'm not even sure what this stuff means. Do I have to run this when a block is occurring? I've used INPUTBUFFER, but like I said in my OP, I'm not sure that the statement it's returning is actually the offending query. In fact, I'd bet against it. – user3083114 Dec 09 '13 at 16:56
  • Look at sp_indexoption. Try disallowing page locks. sp_who2 should have some information on the executing statement; Again, I have not used 2000 in ages. – CRAFTY DBA Dec 09 '13 at 16:58
  • Please post the lock trace; it will be good for reference. Try to turn off page locking - Heading 2 lunch, will check in 1 hr to see how you make out will changing the locking type. – CRAFTY DBA Dec 09 '13 at 17:01
  • Just got back to my desk. Starting to work on this. Ran sp_indexoption and received the error message: Msg 201, Level 16, State 4, Procedure sp_indexoption, Line 0 Procedure 'sp_indexoption' expects parameter '@IndexNamePattern', which was not supplied. – user3083114 Dec 09 '13 at 18:12
  • Not sure how to disallow page locks. How would I do this? I failed to mention prior that this query has worked for years with no issue prior to the attempted change to the table. Not sure if that helps or not. – user3083114 Dec 09 '13 at 18:14
  • What is "the trace"? The results of sp_lock?3 – user3083114 Dec 09 '13 at 18:15
  • Lets start at the beginning, when you run sp_who2. Do you seen a SPID that has been blocked? I will post an example soon using Adventure Works. – CRAFTY DBA Dec 09 '13 at 18:23
  • Yes. It's a different user every time. – user3083114 Dec 09 '13 at 18:25
  • In my OP, I state, "Further analysis led me to sp_who2. Running this would give me all the users and the SPID of who was blocking. This gave me a quicker way of getting things working again because I could kill the offending SPID and allow everyone else to continue working. Of course the kill results in a rollback, so not all data is being saved and I have to tell the owner of the killed process that they must re-enter all their data a second time. To date, I continuously monitor this database in this way, and if I find something blocked, this is how I fix it." – user3083114 Dec 09 '13 at 18:26
  • Yeah, we have a old application next door written in the late 1990's on SQL 2000 with a SQL 7 compatibility mode. We unfortunately do the same thing, since it is so old and the application is going to be retired shortly. – CRAFTY DBA Dec 09 '13 at 18:30
  • Can you send me screens shots of the SQL? I would take the SQL and look at the query plan. How is it finding the data? SCAN or SEEK? – CRAFTY DBA Dec 09 '13 at 18:31
  • Screen shots of what? Where do I get a screenshot of the query plan? How is it finding the data? Don't know how to find that answer. I do know that I'm fragmented to 71% right now. So maybe that's an issue. Sorry, I'm not a DBA so if you could be more specific about what you are looking for I'd appreciate it. – user3083114 Dec 09 '13 at 18:35
  • Okay, I am back. Very busy at work. Any who, you should get familiar with Books On Line (BOL). Here is an article on how to get the query plan. Yes, rebuilding or reorganizing the index with updated statitics helps. http://technet.microsoft.com/en-us/library/aa178303(v=sql.80).aspx – CRAFTY DBA Dec 10 '13 at 18:57
  • It's not the query. The query has performed fine for years prior to tinkering with the table. These indexes were never defraged either...for years. So I know that this would help with performance going forward, but it's not the cause of my current issue. Any other ideas? – user3083114 Dec 11 '13 at 13:54
  • http://technet.microsoft.com/en-us/library/aa258286(v=sql.80).aspx DBCC INDEXDEFRAG. Do not forget to update statistics afterwards. http://technet.microsoft.com/en-us/library/aa260645(v=sql.80).aspx UPDATE STATISTICS – CRAFTY DBA Dec 11 '13 at 14:11
  • Thank you for this. I'll definitely do this. Do you have any ideas on what my issue may be? – user3083114 Dec 11 '13 at 14:39
  • It is very difficult to debug this via just text descriptions. Please do the index defrag and update statistics. I would suggest using http://ola.hallengren.com/ scripts for backups/maintenance. However, SQL 2000 was dropped from extended support in April, 2013. Have to go back to old school techniques. If the indexes are really fragmented, it might be easier to script it out. Drop the index, and recreate it. Be careful of PK and clustered indexes. As usual, a good backup is always prudent. Good luck. – CRAFTY DBA Dec 11 '13 at 15:41