EEddieEmm has asked for the
wisdom of the Perl Monks concerning the following question:

Dear Perl Monks

I am running a Perl script on a Linux server and accessing a MsSQL database on another server. Most everything is fine except for one query. When I run a SELECT, parse through the returned data and then attempt a table update on the same table, the database locks. When I go to the database itself and try to look at the table, I get the "Waiting to execute query" message. When I kill the script back on the Linux server, everything immediately starts to work again with no issues.

The script and query throw no errors. There is no indication that something is wrong. Has anyone else seen anything like this? If you have, what was your solution?

I have a code snippet below that shows what I am trying to do. The problem happens when I try to run the second query.

I can update the database directly. As a matter of of fact, that's how I "get around" the issue at the moment. I read the log and when an update is needed, I'll go into the database with Microsoft SQL Server Management Studio, and make the update with the data from the last log entry. Sucks, but it works.

Being new to DBI, I didn't know how to do this. You are right, might be worth a look although I know where the problem is. Just don't know why.

I was thinking along these lines myself. My plan was to alter the code to place the returned data into an array. Then read through that and make updates as needed. The while loop might be keeping the SELECT active somehow - don't know.

I'm very surprised your code did not error with something like connection is busy with another statement. Until quite recently to get multiple active statements in MS SQL Server you had to do some rather nasty hacks (see Multiple Active Statements (MAS) and DBD::ODBC).

I'd be interested in what DBD you were using and what library under that.

Firstly, how are you connected? FreeTDS or ODBC? If you're connected through FreeTDS, it's pretty difficult to have two queries running concurrently on the same database handle. You need to finish your select before you run any updates. A workaround is to open two database handles on the same database.

Secondly, by default MSSQL locks whole pages and often whole tables while one query is running, meaning a situation like yours is likely to cause deadlocks. You could experiment with adding some table hints to your select query; possibly ROWLOCK, perhaps even NOLOCK as a last resort.

use SQL server's profiler to check for blocking locks.My guess is that the first cursor still has a shared lock on the rows read and while not yet completed you open another cursor (update) which conflicts with the previous one.

What is your isolation level? try setting the isolation level for the session to READ UNCOMITTED just to check that it's a locking issue;remember this isolation level is not otherwise recommended

you are using cursor-based procedural logic;try to mix your select with the update in one query and since I see that you check the values of 2 returned columns,use a CASE clause to place your filter and do your update

or read all rows in an array,commit the select and then iterate through it in the client's memory,opening a cursor and doing your updates. However this has the drawback that your update might fail if another transaction has already changed your row in the mean time,since you take no shared/read locks

This is a discussion forum, not a bug tracker. We don't close threads when you've got the solution you were looking for. People may still want to post answers and observations in the future, and other people with the same problem who find this thread later on may prefer those solutions.