DB2 INSERT INTO … SELECT lock - sql

There is an application Application1 which is issuing insert statement that we are using in Prod
INSERT INTO Table1
(SELECT FROM Table2
WHERE conditions are true)
There is another application Apllication2 which is doing a select query on Table2
SELECT FROM Table2
WHERE conditions are true
with ur
Now whenever the insert query is running, the second query is running very slow, sometimes getting read timed out.
I tried to find if the Table2 was getting locked due to being part of the insert statement, but I couldn't find any concrete evidence.
I did find something for MySQL
How to improve INSERT INTO ... SELECT locking behavior
but nothing for DB2.
Can somebody please help me understand the cause of slowness ?

The insert statement is almost certainly issuing locks against table2. However, if your second statement has with UR then it is likely it can avoid those locks. If you have a test system you can try setting the registry variable DB2_WORKLOAD to WAS (which sets all these: https://www.ibm.com/support/knowledgecenter/en/SSEPGG_11.1.0/com.ibm.db2.luw.admin.perf.doc/doc/c0011218.html).
I suggest using dsmtop or MONREPORT.DBSUMMARY (https://www.ibm.com/support/knowledgecenter/en/SSEPGG_11.1.0/com.ibm.db2.luw.apdv.sqlpl.doc/doc/r0056370.html) to determine where time is actually being spent for the read-only query.

You can use second query as below:
SELECT FROM Table2 WITH(NOLOCK)
WHERE conditions are true
Note: But It will give you dirty read.

Related

How to fix "UPDATE <table> OUTPUT WITH (READPAST)"

We are trying to retrieve and update the TOP X events from a table but without locking anything else than the "processed" rows. We looked into different SQL hints like ROWLOCK and READPAST, but haven't figured out what combination of those should be used in this scenario. Also, we need to make sure that the returned rows are unique across different concurrent executions of that query and that the same row will never be selected twice.
Note: This table has got many INSERTs happening concurrently.
UPDATE TOP(:batchSize) wsns WITH (READPAST)
SET consumer_ip = :consumerIP
OUTPUT inserted.id, inserted.another_id, inserted.created_time, inserted.scheduled_time
FROM table_A a
WHERE a.scheduled_time < GETUTCDATE() AND a.consumer_ip IS NULL
Any help is highly appreciated. Many thanks!
I don't quite follow how/why are you trying to use the READPAST hint here?
But anyway - to achieve what you want I would suggest:
WITH xxx AS
(
SELECT TOP(:batchSize) *
FROM table_A
)
UPDATE xxx
SET consumer_ip = :consumerIP
OUTPUT inserted.id, inserted.another_id, inserted.created_time, inserted.scheduled_time
FROM table_A a
WHERE a.scheduled_time < GETUTCDATE() AND a.consumer_ip IS NULL;
If all that could happen in the background are new inserts then, I can't see why this would be a problem. SQL Server optimiser most likely would decide for PAGE/ROW lock (but this is depending on your DB settings as well as indexes affected and their options). If by any reason you want to stop other transaction until this update is finished - hold an exclusive lock on the entire table, till the end of your transaction, you can just add WITH(TABLOCKX). Therefore, I would strongly recommend to have a good read on the SQL Server concurrency and isolation before you start messing with it in a production environment.

Delete statement after executing a SQL insert twice

From an Oracle database, I have executed an insert SQL statement twice in a production environment.
Sadly, the rollback option did not seem to work.
The insert statement was:
INSERT INTO MAE_INT.T_INT_APPLICATION (INAP_IDENT, INAP_PARAM, INAP_VALEUR, INAP_DATE)
VALUES ((SELECT MAX(INAP_IDENT)+1 FROM MAE_INT.T_INT_APPLICATION), 'monitoring', 'true', '10/06/2016');
COMMIT;
I guess the only option now is to make a delete statement for the double.
Anyone can help with that? Not sure how to write it
You can delete max(INAP_IDENT) like below, thereby leaving you with first insert statement only.
NOTE: TEST IT IN DEV/UAT ENVIRONMENT FIRST
delete from MAE_INT.T_INT_APPLICATION
where INAP_IDENT=
(SELECT MAX(INAP_IDENT) FROM MAE_INT.T_INT_APPLICATION);
Before committing, check if you dont have duplicate entry.

Using HoldLock Incorrectly in SQL Server stored procedure

I believe I am using HOLDLOCK incorrectly.
The reason I think this is because I have a table that acts like a queue. The queue receives its items from the SQL below and gets processed, one by one in a console application. I haven't tested yet but I believe when this console application starts processing this table, during some of the long selects the code below fails. Why do I think that...because I am logging the GameID when grabbing everything from the table queue and processing them one by one in that console application. The funny thing is the games that I believe didn't make it through didn't make it in the log, therefore I dont believe they are being inserted in my queue table and I believe it's because of the HOLDLOCK below.
Thoughts?
MERGE Test WITH (HOLDLOCK) AS GL
USING (SELECT #GameId AS ID) AS NewTest ON GL.ID = NewTest.ID
WHEN NOT MATCHED THEN
INSERT
(
Id,
FailedAttempts,
DateCreated
)
VALUES
(
NewTest.ID,
0,
SYSDATETIME()
);
I suspect your issue is unrelated to your use of MERGE or HOLDLOCK. I see no reason to introduce cumbersome MERGE syntax here, since it provides no benefit, and especially given the potential issues it can cause in other areas. I suggest a very simple INSERT ... WHERE NOT EXISTS:
INSERT dbo.Test(Id, FailedAttempts, DateCreated)
SELECT #GameId, 0, SYSDATETIME()
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.Test WITH (HOLDLOCK)
WHERE Id = #GameId
);
I'd prefer this over just blindly trying to insert and getting a PK violation for the reasons outlined here and here - in almost all cases, forcing SQL Server to try and get an exception instead of checking yourself first will yield worse performance.

what make insert into select sql statement very slowly(no resultset return)

execute very slowly on below sql statement, env: oracle 9. Please advise the cause or hints to debug. Thanks a lot .
INSERT INTO tmp_table (col1,col2,col3,col4,col5,col6,col7,col8,col9)
select * from my_view where col1 = 1;
How far i tested: execute the select sub-statement cost 3 sec to get 1 record returned while endless executing but no resultset returned when execute the entire statement, like hanging.
When a query appears to execute quickly, in the sense that the last row is returned quickly rather than just the first row, but it runs slowly when used in an insert statement, the usual suspects are:
A change in the execution plan, driven by the optimiser believing that an all_rows goal is now appropriate where previously a first_rows goal was used. Check the execution plan for changes.
Some action being executed as a result of the insert. Slow triggers on the target table, or materialised view logging, are possible causes. This would not be the case when running "create table ... as select ..".

What's blocking "Select top 1 * from TableName with (nolock)" from returning a result?

I'm currently running the following statement
select * into adhoc..san_savedi from dps_san..savedi_record
It's taking a painfully long time and I'd like to see how far along it is so I ran this:
select count(*) from adhoc..san_savedi with (nolock)
That didn't return anything in a timely manner so for the heck of it I did this:
select top 1 * from adhoc..san_savedi with (nolock)
Even that seems to run indefinitely. I could understand if there are millions of records that the count(*) could take a long time, but I don't understand why selecting the top 1 record wouldn't come back pretty much immediately considering I specified nolock.
In the name of full disclosure, dps_san is a view that pulls from an odbc connection via linked server. I don't think that'd be affecting why I can't return the top row but just throwing it out there in case I'm wrong.
So I want to know what is keeping that statement from running?
EDIT:
As I mentioned above, yes dps_san..savedi_record is a view. Here's what it does:
select * from DPS_SAN..root.SAVEDI_RECORD
It's nothing more than an alias and does no grouping/sorting/etc so I don't think the problem lies here, but please enlighten me if I'm wrong about that.
SELECT queries with NOLOCK don't actually take no locks, they still need a SCH-S (schema stability) lock on the table (and as it is a heap it will also take a hobt lock).
Additionally before the SELECT can even begin SQL Server must compile a plan for the statement, which also requires it to take a SCH-S lock out on the table.
As your long running transaction creates the table via SELECT ... INTO it holds an incompatible SCH-M lock on it until the statement completes.
You can verify this by looking in sys.dm_os_waiting_tasks whilst while during the period of blocking.
When I tried the following in one connection
BEGIN TRAN
SELECT *
INTO NewT
FROM master..spt_values
/*Remember to rollback/commit this later*/
And then executing (or just simply trying to view the estimated execution plan)
SELECT *
FROM NewT
WITH (NOLOCK)
in a second the reading query was blocked.
SELECT wait_type,
resource_description
FROM sys.dm_os_waiting_tasks
WHERE session_id = <spid_of_waiting_task>
Shows the wait type is indeed SCH_S and the blocking resource SCH-M
wait_type resource_description
---------------- -------------------------------------------------------------------------------------------------------------------------------
LCK_M_SCH_S objectlock lockPartition=0 objid=461960722 subresource=FULL dbid=1 id=lock4a8a540 mode=Sch-M associatedObjectId=461960722
It very well may be that there are no locks... If dps_san..savedi_record is a view, then it may be taking a long time to execute, because it may be accessing tables without using an index, or it may be sorting millions of records, or whatever reason. Then your query, even a simple top or count, will be only as fast as that view can be executed.
A few issues to consider here. Is dps_san..savedi_record a view? If so, it could just be taking a really long time to get your data. The other thing I can think of is that you're trying to create a temp table by using the select into syntax, which is a bad idea. select * into ... syntax will lock the tempdb for duration of the select.
If you are creating the table using that syntax, then there is a workaround. First, create the table by throwing where 1=0 at the end of your initial statement:
select * into ... from ... where 1=0
This will create the table first (which is quick) which allows you to insert into because the table exists now (without penalty of locking tempdb for duration of query).
Find the session_id that is performing the select into:
SELECT r.session_id, r.blocking_session_id, r.wait_type, r.wait_time
FROM sys.dm_exec_requests AS r
CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS t
WHERE t.[text] LIKE '%select%into%adhoc..san_savedi%';
This should let you know if another session is blocking the select into or if it has a wait type that is causing a problem.
You can repeat the process in another window for the session that is trying to do the select. I suspect Martin is right and that my earlier comment about schema lock is relevant.