In a SQL Server 2008 (sp2) stored procedure, before starting a transaction I create two temporary tables. I insert into them in the transaction. When the transaction loops through a fairly large set of data (~1,200 times), the stored procedure fails to finish. Specifically, a trace shows that
SELECT * FROM #tmpTable2
in the below code starts but doesn't complete. When the loop is about half as big, it works fine.
IF [true] > 0 --error
BEGIN
SELECT * FROM #tmpTable1
SELECT * FROM #tmpTable2
DROP TABLE #tmpTable1
DROP TABLE #tmpTable2
rollback TRANSACTION
return -1
END
Note that in the trace, transactionlog events occur more and more frequently as it gets to the point it fails.
Any ideas? Thanks!
Related
I have an app which keeps inserting rows into table.using stored procedures.
Based on my search so far Oracle needs commit but sql server does it automatically.
I could not find any solid reference to confirm the above.
So question: does Sql server needs commit after every insert and delete(inside stored procedures) or it is automatic?
SQL will commit by default. If you don't want it to commit, you can begin a TRANSACTION, and then you can choose to COMMIT TRANSACTION or ROLLBACK TRANSACTION
More info:
https://msdn.microsoft.com/en-us/library/ms188929.aspx?f=255&MSPPError=-2147217396
The answer can be complicated depending on configuration and your exact code, however in general Sql Server writes with each operation. For all practical purposes if you do something like:
CREATE TABLE dbo.DataTable( Value nvarchar(max) )
GO
CREATE PROC dbo.WriteData
#data NVARCHAR(MAX)
AS BEGIN
INSERT INTO DataTable( Value ) VALUES ( #data )
END
GO
EXEC dbo.WriteData 'Hello World'
SELECT *
FROM DataTable
DROP TABLE dbo.DataTable
DROP PROC dbo.WriteData
Once the proc has completed the data is commited. Again, depending on lots of factors the timing of this can change or be delayed.
However for what it sounds like you are asking if your "INSERT" the data is inserted no need to finalize a transaction unless you started one.
I'm having issues with timeouts of a table on mine.
Example table:
Id BIGINT,
Token uniqueidentifier,
status smallint,
createdate datetime,
updatedate datetime
I'm inserting data into this table from 2 different stored procedures that are wrapped with transaction (with specific escalation) and also 1 job that executes once every 30 secs.
I'm getting timeout from only 1 of them, and the weird thing that its from the simple one
BEGIN TRY
BEGIN TRAN
INSERT INTO [dbo].[TempTable](Id, AppToken, [Status], [CreateDate], [UpdateDate])
VALUES(#Id, NEWID(), #Status, GETUTCDATE(), GETUTCDATE() )
COMMIT TRAN
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN;
END CATCH
When there is some traffic on this table (TempTable) this procedure keeps getting timeout.
I checked the execution plan and it seems I haven't missed any indexes in both stored procedures.
Also, the only index on TempTable is the clustered PK on Id.
Any ideas?
If more information is needed, do tell.
The 2nd stored procedure using this table isn't causing any big IO or something.
The job, however, uses an atomic UPDATE on this table and in the end of it DELETEs from the table, but as I checked on high IO of this table, the job takes no longer than 3 secs.
Thanks.
It is most propably because some other process is blocking your insert operation, It could be another insert, delete , update or some trigger or any other sql statement.
To find out who is blocking your operation you can use some esaily avialable stored procedures like
sp_who2
sp_whoIsActive (My Preferred)
While your insert statement is being executed/hung up execute one of these procedures and see who is blocking you.
In sp_who2 you will see a column by the name Blk_by get the SPID from that column and execute the following query
DBCC INPUTBUFFER(71);
GO
This will reutrn the last query executed by that process id. and it is not very well formatted the sql statement, all the query will be in one single line you will need to format it in your SSMS to acutally be able to read it.
On the other hand sp_WhoIsActive will only return the queries that are blocking other process and will have the query formatted just as the user has execute it. Also it will give you the execution plan for that query.
I have an MSSQL Server 2008 (Express) set up.
In my database I have a set of tables and a stored procedure.
What I want to achieve is get any changes that have been made to an existing table, and return them at the end of the procedure. The stored procedure I have created works fine when I run it locally within MSSQL Management Studio.
However, when I call the procedure through a JDBC connection certain parts of the procedure seem to have not completed.
The summary of what I'm trying to do is as follows:
1) Put a snapshot of the data contained in CurrentTableA into #CurrentShotA (temporary table)
2) Compare #CurrentShotA with PreviousTableA
3) Insert differences into #TempTableB
(this equates to new rows or altered rows in #CurrentShotA)
4) Empty PreviousTableA
5) Insert contents of #CurrentShotA into PreviousTableA
6) Select * from #TempTableB (return all new rows and changes)
Step 6 returns the data correctly the first time it is called via JDBC.
When the procedure is called the second and subsequent times it is clear that step 5 has not completed as expected. PreviousTableA is always empty when it should contain a snapshot of the old data.
Question is why does the procedure work properly when called with in MSSQL Management studio but not when I call it via JDBC?
CREATE PROCEDURE [dbo].[getUpdatedSchedules]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Check of the temporary table exists, delete if it does
IF OBJECT_ID('#TempTableB','U')IS NOT NULL
begin
drop table #TempTableB
end
-- Force the creation of the temporary tables quickly
select * into #TempTableB from dbo.CurrentTableA where 1=0
select * into #CurrentShotA from dbo.CurrentTableA where 1=0
-- Get the differences between schedules and put into #TempTableB
insert #CurrentShotA select * from dbo.CurrentTableA
insert #TempTableB select * from #CurrentShotA
except select * from dbo.PreviousTableA
TRUNCATE TABLE dbo.PreviousTableA
insert dbo.PreviousTableA select * from #CurrentShotA
select * from #TempTableB
END
GO
I'm new enough to stored procedures and MSSQL configuration so I have considered that it might be a permissions issue. I login to MSSQL Studio using SQL authentication that is not linked to a windows account and the procedure runs as normal so I don't think it's permissions.
I hope my explanation and question is clear enough. I'd appreciate any thoughts or suggestions as to what I am doing wrong.
There's no need to check if #TempTableB exists since it will be dropped automatically once the procedure finishes executing, just as the other temp tables are dropped automatically; perhaps you expect these tables to have data on subsequent calls to the proc and that's why you think it doesn't work when you call it from Java?
When you execute these SQL statements from SSMS they may have data in them since it's all the same database session, but that's not the case when called using JDBC.
I have needs to keep some of log data in different tables even my transaction is rolled back.
I already learned that in SQL Server it is impossible do something like this
begin tran t1
insert ...
insert ...
select ...
begin tran t2
insert into log
commit tran t2
rollback tran t1
select * from log -- IS EMPTY ALWAYS
So I try hacking SQL Server that I madded CLR which is going to export data need for LOG to local server disk in XML format. CLR Code is simple as it can be:
File.WriteAllText(fileName, xmlLog.Value.ToString());
Before I release this in production bases Ill love to hear your toughs about this technique.
Here are few questions:
Is there other better way to accomplish autonomous transaction in SQL Server 2005
How can be bad holding my transaction uncommitted while SQL Server is executing CLR (amount of data written by SQL is relative small about 50 - 60 records of 3 integers and 4 floats)
I would suggest using a Table Variable as it is not affected by the Transaction (this is one of the methods listed in the blog noted by Martin below the question). Consider doing this, which will work in SQL Server 2005:
DECLARE #TempLog TABLE (FieldList...)
BEGIN TRY
BEGIN TRAN
INSERT...
INSERT INTO #TempLog (FieldList...) VALUES (#Variables or StaticValues...)
INSERT...
INSERT INTO #TempLog (FieldList...) VALUES (#Variables or StaticValues...)
COMMIT TRAN
END TRY
BEGIN CATCH
IF (##TRANCOUNT > 0)
BEGIN
ROLLBACK TRAN
END
/* Maybe add a Log message to note that we ran into an error */
INSERT INTO #TempLog (FieldList...) VALUES (#Variables or StaticValues...)
END CATCH
INSERT INTO RealLogTable (FieldList...)
SELECT FieldsList
FROM #TempLog
Please note that while we are making use of the fact that Table Variables are not part of the transaction, that does create a potential situation where this code does a COMMIT but errors (or server crashes) before the INSERT INTO RealLogTable and you will have lost the logging for the data that did make it in. At this point there would be a disconnect as there is data but no record of it being inserted as far as RealLogTable is concerned. But this is just the obvious trade-off for being able to bypass the Transaction.
I'm trying to write to a log file inside a transaction so that the log survives even if the transaction is rolled back.
--start code
begin tran
insert [something] into dbo.logtable
[[main code here]]
rollback
commit
-- end code
You could say just do the log before the transaction starts but that is not as easy because the transaction starts before this S-Proc is run (i.e. the code is part of a bigger transaction)
So, in short, is there a way to write a special statement inside a transaction that is not part of the transaction. I hope my question makes sense.
Use a table variable (#temp) to hold the log info. Table variables survive a transaction rollback.
See this article.
I do this one of two ways, depending on my needs at the time. Both involve using a variable, which retain their value following a rollback.
1) Create a DECLARE #Log varchar(max) value and use this: #SET #Log=ISNULL(#Log+'; ','')+'Your new log info here'. Keep appending to this as you go through the transaction. I'll insert this into the log after the commit or the rollback as necessary. I'll usually only insert the #Log value into the real log table when there is an error (in theCATCH` block) or If I'm trying to debug a problem.
2) create a DECLARE #LogTable table (RowID int identity(1,1) primary key, RowValue varchar(5000). I insert into this as you progress through your transaction. I like using the OUTPUT clause to insert the actual IDs (and other columns with messages, like 'DELETE item 1234') of rows used in the transaction into this table with. I will insert this table into the actual log table after the commit or the rollback as necessary.
If the parent transaction rolls back the logging data will roll back as well - SQL server does not support proper nested transactions. One possibility is to use a CLR stored procedure to do the logging. This can open its own connection to the database outside the transaction and enter and commit the log data.
Log output to a table, use a time delay, and use WITH(NOLOCK) to see it.
It looks like #arvid wanted to debug the operation of the stored procedure, and is able to alter the stored proc.
The c# code starts a transaction, then calls a s-proc, and at the end it commits or rolls back the transaction. I only have easy access to the s-proc
I had a similar situation. So I modified the stored procedure to log my desired output to a table. Then I put a time delay at the end of the stored procedure
WAITFOR DELAY '00:00:12'; -- 12 second delay, adjust as desired
and in another SSMS window, quickly read the table with READ UNCOMMITTED isolation level (the "WITH(NOLOCK)" below
SELECT * FROM dbo.NicksLogTable WITH(NOLOCK);
It's not the solution you want if you need a permanent record of the logs (edit: including where transactions get rolled back), but it suits my purpose to be able to debug the code in a temporary fashion, especially when linked servers, xp_cmdshell, and creating file tables are all disabled :-(
Apologies for bumping a 12-year old thread, but Microsoft deserves an equal caning for not implementing nested transactions or autonomous transactions in that time period.
If you want to emulate nested transaction behaviour you can use named transactions:
begin transaction a
create table #a (i int)
select * from #a
save transaction b
create table #b (i int)
select * from #a
select * from #b
rollback transaction b
select * from #a
rollback transaction a
In SQL Server if you want a ‘sub-transaction’ you should use save transaction xxxx which works like an oracle checkpoint.