I have trouble to update some rows in SQL Server (2005 and 2008).
Often, when I try to update one row while having a running query (select * from thistable),
I start the update command and it will fail due to a timeout/lock issue.
It only appears on tables with nvarchar(max)/text columns!
Even if I try to SELECT * FROM thistable WITH(ROWLOCK), I do encounter the same problem.
So my basic question here is:
Can I motivate SQL Server NOT to lock more than the actual row ?
Edit: I first run the SELECT afterwards I try to UPDATE...
There is a great explanation on Locking in SQL-Server on simple talk
Try using:
SELECT * FROM thistable (NOLOCK)
for your select statement.
Then run your update as normal.
Related
I am using the mssql-jdbc JDBC driver to do the following in a single transaction.
Executed the following statement:
delete from table1
There were around 10 records in the table which were deleted (execute update returned 10). Then, immediately following the delete, executed the following select statement:
select count(*) from table1
Resultset said that there are still 10 records.
In other DBs like Oracle and Postgres, we get 0, which is what I am expecting.
I do not want autocommit=true behaviour. Also, the two statements need to execute in the same transaction.
Is there anything I can do to get the behaviour I want?
Answering for my question.
There was a bug in the on-delete cascade trigger we had added for the table.
As a result, a commit was not happening when records in that table were deleted. Since no JDBC exceptions were being thrown for failures in the trigger, the problem was not apparent from Java end.
There was no other issue.
I have a database called mbt. I wanted to write some data from temporary table to real table.
--I used this query.
SELECT * INTO new_table FROM #tmp
when i runned the query it returned normal message.
15813 row(s) affected
After that i checked my tables in mbt database, but i couldn't see 'new_table'
how could such a thing be, where the table might have gone.
I may have forgotten to use 'use MBT' statment at the beginning of the query. Does it make problem
I'm using ms sql server 2014(SP2)(KB3171021)-12.0.5000.0(X64)
ANSWER
It gone to Master DB
select 'master' as DatabaseName,
T.name collate database_default as TableName
from master.sys.tables as T
It Will create a new table on your database. but you did not use so it will store in master database on your server.
Run the query below to find databases which have the object new_table:
sp_MSForEachDB 'Use [?] IF EXISTS (SELECT 1 FROM sys.objects WHERE name= ''new_table'')
SELECT DB_NAME()'
I had the same problem. What i did is, I rewrite the statement of use Database and then refresh the database browser after that i got Result. You can try it. may be it will help you.
Always use command "USE db_name" to make sure that you are querying right database.
Below command will show all databases available on the server.
SHOW DATABASES;
If you are using GUI tool to connect DB server, there is a possibility that at the time of connection you got connected to different DB. If you executed the query to create table and inserted record. These records are inserted in new table in different DB than mbt.
I am using the EXEC (sql) AT LinkedServer command to get some data from a remote server. So far the only thing I can do with the results in my script is insert them into a local table.
CREATE TABLE #MyTable (Col1 VARCHAR(10))
INSERT INTO #MyTable
EXEC ('SELECT Col1 FROM MyDB.dbo.Table1 WHERE Col2 = ?', 'Val2') AT REMOTEDDB
This works great and I can use this.
I wanted to join the result set to a local table directly like OPENQUERY does but I can't find syntax for that. It may not be supported. I can't use OPENQUERY because the data is too big and I need to apply run time parameters.
Are there any other options for processing and working with the results of the EXEC AT command that don't require inserting it into a table first?
There is no way, that I know of, to join directly to an Exec. Inserting into a temp table would be your best bet in my opinion. Even if you joined directly in syntax the same thing would still happen, SQL Server needs to pull the remote data local and then perform the join.
Another option might be to pass a table parameter and have that output. You can do that with sp_executesql.
https://msdn.microsoft.com/en-us/library/ms188001.aspx
I would sync that table locally using something like sql agent every 5 minutes or so. Then I do the join to that local table.
In my experience, querying remote table using link server never gives me the best query plan available. I would avoid that if I can.
There is nothing wrong in caching remote results locally before using them. On average, this approach gives the best performance.
Also, you can try a static query:
select *
from dbo.LocalTable lt
inner join RemoteDB.MyDB.dbo.Table1 rt on lt.Id = rt.Id
where rt.Col2 = 'Val2';
If it wouldn't work straight away, at least you can try REMOTE join hint. Of course, normally it should be a last resort (the hint, I mean).
I am migrating several hundred stored procedures from one server to another, so I wanted to write a stored procedure to execute an SP on each server and compare the output for differences.
In order to do this, I would normally use this syntax to get the results into tables:
select * into #tmp1 from OpenQuery(LocalServer,'exec usp_MyStoredProcedure')
select * into #tmp2 from OpenQuery(RemoteServer,'exec usp_MyStoredProcedure')
I then would union them and do a count, to get how many rows differ in the results:
select * into #tmp3
from ((select * from #tmp1) union (select * from #tmp2))
select count(*) from #tmp1
select count(*) from #tmp3
However, in this case, my stored procedure contains an OpenQuery, so when I try to put the exec into an OpenQuery, the query fails with the error:
The operation could not be performed because OLE DB provider "SQLNCLI"
for linked server "RemoteServer" was unable to begin a distributed transaction.
Are there any good workarounds to this? Or does anybody have any clever ideas for things I could do to make this process go more quickly? Because right now, it seems that I would have to run the SP on each server, script the results into tmp tables, then do the compare. That seems like a poor solution!
Thank you for taking the time to read this, and any help would be appreciated greatly!
I think your method would work - you just need to start the MSDTC. This behavior occurs if the Distributed Transaction Coordinator (DTS) service is disabled or if network DTC access is disabled. By default, network DTC access is disabled in Windows. When running and configured properly, the OLE DB provider would be able start the distributed transaction.
Check out this for instructions- it applies to any Windows Server 2003 or 2008.
Similar to your question.
Insert results of a stored procedure into a temporary table
I have a table I'm using as a work queue. Essentially, it consists of a primary key, a piece of data, and a status flag (processed/unprocessed). I have multiple processes trying to grab the next unprocessed row, so I need to make sure that they observe proper lock and update semantics to avoid race condition nastiness. To that end, I've defined a stored procedure they can call:
CREATE PROCEDURE get_from_q
AS
DECLARE #queueid INT;
BEGIN TRANSACTION TRAN1;
SELECT TOP 1
#queueid = id
FROM
MSG_Q WITH (updlock, readpast)
WHERE
MSG_Q.status=0;
SELECT TOP 1 *
FROM
MSG_Q
WHERE
MSG_Q.id=#queueid;
UPDATE MSG_Q
SET status=1
WHERE id=#queueid;
COMMIT TRANSACTION TRAN1;
Note the use of "WITH (updlock, readpast)" to make sure that I lock the target row and ignore rows that are similarly locked already.
Now, the procedure works as listed above, which is great. While I was putting this together, however, I found that if the second SELECT and the UPDATE are reversed in order (i.e. UPDATE first then SELECT), I got no data back at all. And no, it didn't matter whether the second SELECT was before or after the final COMMIT.
My question is thus why the order of the second SELECT and UPDATE makes a difference. I suspect that there is something subtle going on there that I don't understand, and I'm worried that it's going to bite me later on.
Any hints?
by default transactions are READ COMMITTED :
"Specifies that shared locks are held while the data is being read to avoid dirty reads, but the data can be changed before the end of the transaction, resulting in nonrepeatable reads or phantom data. This option is the SQL Server default."
http://msdn.microsoft.com/en-us/library/aa259216.aspx
I think you are getting nothing in the select because the record is still marked as dirty. You'd have to change the transaction isolation level OR, what I do is do the update first and then read the record, but to do this you have to flag the record w/ a unique value (I use a getdate() for batchs but a GUID would be what you probably want to use).
Although not directly answering your question here, rather than reinventing the wheel and making life difficult for yourself, unless you enjoy it of course ;-), may I suggest that you look at using SQL Server Service Broker.
It provides an existing framework for using queues etc.
To find out more visit.
Service Broker Link
Now back to the question, I am not able to replicate your problem, as you will see if you execute the code below, data is returned regardless of the order os the select/update statement.
So your example above then.
create table #MSG_Q
(id int identity(1,1) primary key,status int)
insert into #MSG_Q select 0
DECLARE #queueid INT
BEGIN TRANSACTION TRAN1
SELECT TOP 1 #queueid = id FROM #MSG_Q WITH (updlock, readpast) WHERE #MSG_Q.status=0
UPDATE #MSG_Q SET status=1 WHERE id=#queueid
SELECT TOP 1 * FROM #MSG_Q WHERE #MSG_Q.id=#queueid
COMMIT TRANSACTION TRAN1
select * from #MSG_Q
drop table #MSG_Q
Returns the Results (1,1) and (1,1)
Now swapping the statement order.
create table #MSG_Q
(id int identity(1,1) primary key,status int)
insert into #MSG_Q select 0
DECLARE #queueid INT
BEGIN TRANSACTION TRAN1
SELECT TOP 1 #queueid = id FROM #MSG_Q WITH (updlock, readpast) WHERE #MSG_Q.status=0
SELECT TOP 1 * FROM #MSG_Q WHERE #MSG_Q.id=#queueid
UPDATE #MSG_Q SET status=1 WHERE id=#queueid
COMMIT TRANSACTION TRAN1
select * from #MSG_Q
drop table #MSG_Q
Results in: (1,0), (1,1) as expected.
Perhaps you could qualify your issue further?
More experimentation leads me to conclude that I was chasing a red herring, brought about by the tools I was using to exec my stored procedure. I was initially using DBVisualizer (free edition) and Netbeans, and they both appear to be confused by something about the format of the results. DBVisualizer suggests that I'm getting multiple result sets back, and that the free edition doesn't handle that.
Since then, I grabbed the free MS SQL Server Management Studio Express and things work perfectly. For those interested, the URL to SMSE is here:
MS SQL Server SMSE
Don't forget to install the MSXML6 service pack, too:
MSXML Service Pack 1
So, totally my bad in this case. :-(
Major thanks and kudos to you guys for your answers though. You helped me confirm that what I was doing should work, which lead me to the change I had to make to actually "solve" the issue. Thanks ever so much!
One more point-- including a "SET NOCOUNT ON" in the stored procedure fixed things for all ODBC clients. Apparently the rowcounts for the first select was confusing the ODBC clients, and telling SQL Server to not return that value makes things work perfectly...