MySQL InnoDB locking - locking

I have 2 connections.
1st connection makes query:
UPDATE table1 SET column1 = 5;
2nd connection:
SELECT t1.column1, t2.column2
FROM table2 t2
JOIN table1 t1
ON t1.column1 = t2.column1
table1 - InnoDB, table2 - MyISAM
MySQL server gets 2nd query immidiatly after getting 1st query. Would the query in 2nd connection wait until update is done?

Assuming isolation level other than SERIALIZABLE (default is REPEATABLE READ), the second query won't wait for the first, but will read the data from the rollback log instead.
You can verify this by starting a transaction, performing an update and then sleeping for several seconds in one thread, and performing the second query while the first is sleeping in another

Related

How does SQL Server add the with (nolock) one time and effect all query?

If I use N tables now, need to add N times with (nolock), for example
select * from T1 with (nolock)
join T2 with (nolock) ..
join T3 with (nolock) ..
join T4 with (nolock) ..
....
If I want to declare it once, what can I make the next all query work with (nolock)
like :
use all with (nolock)
select * from T1
join T2 ..
join T3 ..
join T4 ..
....
You can use set Transaction isolation level read uncommitted, e.g:
set Transaction isolation level read uncommitted
select * from T1
join T2 ..
join T3 ..
join T4 ..
Notice:
Transactions running at the READ UNCOMMITTED level do not issue shared locks to prevent other transactions from modifying data read by the current transaction. READ UNCOMMITTED transactions are also not blocked by exclusive locks that would prevent the current transaction from reading rows that have been modified but not committed by other transactions. When this option is set, it is possible to read uncommitted modifications, which are called dirty reads. Values in the data can be changed and rows can appear or disappear in the data set before the end of the transaction.
from SET TRANSACTION ISOLATION LEVEL (Transact-SQL) - SQL Server | Microsoft Docs

What is (are) difference between NOLOCK and UNCOMMITTED

I use SQL Server 2012.
I write two queries but what is a different between NOLOCK and UnCommitted ?
SELECT lastname, firstname
FROM HR.Employees with (READUNCOMMITTED)
SELECT lastname, firstname
FROM HR.Employees with (NoLock)
NOLOCK : Is equivalent to READ UNCOMMITTED (source : MSDN)
NOLOCK or READ UNCOMMITTED Specifies that dirty reads are allowed. No shared locks are issued to prevent other transactions from modifying data read by the current transaction, and exclusive locks set by other transactions do not block the current transaction from reading the locked data. Allowing dirty reads can cause higher concurrency, but at the cost of reading data modifications that then are rolled back by other transactions
READ UNCOMMITTED and NOLOCK hints apply only to data locks. All queries, including those with READ UNCOMMITTED and NOLOCK hints, acquire Sch-S (schema stability) locks during compilation and execution. Because of this, queries are blocked when a concurrent transaction holds a Sch-M (schema modification) lock on the table
No difference in terms of their functions, like other have mentioned.
The single difference is that you can apply WITH(NOLOCK) selectively, on some tables but not others. READ UNCOMMITTED applies NOLOCK to all tables in a session.
If you do this:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT *
FROM Table1 T1
INNER JOIN Table2 T2 ON T1.ID = T2.id
It is functionally equivalent to:
SELECT *
FROM Table1 T1 WITH(NOLOCK)
INNER JOIN Table2 T2 WITH(NOLOCK) ON T1.ID = T2.ID
But you can also apply WITH(NOLOCK) selectively:
SELECT *
FROM Table1 T1 WITH(TABLOCK)
INNER JOIN Table2 WITH(NOLOCK) ON T1.ID = T2.ID
Under the hood they are the performing the same action.
The READ UNCOMMITTED isolation level is the least restrictive isolation level within SQL Server, which is also what makes it popular for developers when looking to reduce blocking.
The NOLOCK table hint behind the scenes performs the exact same action as running under the read-uncommitted isolation level.
The only difference between the two is that the READ UNCOMMITTED isolation level determines the locking mechanism for the entire connection and the NOLOCK table hint determines the locking mechanism for the table that you give the hint to.
There is no difference at the statement level.
You can set READUNCOMMITED at the session level and here you have to write
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
For NOLOCK , we need to put this hint on table level, so it is require to put for every tables level which are used in update transaction. So it is very lengthy and time consuming to put it everywhere tables refers in query. For READ UNCOMMITTED, We do not need to put it every tables level, just put at session level or query level and can be written at top of the query or stored procedure.
Let us look on small demo to elaborate it. First checking here database default isolation level
CREATE TABLE SAMPLETABLE
(
Col1 INT ,
Col2 VARCHAR(100)
)
INSERT INTO SAMPLETABLE(Col1,Col2)
SELECT 1,'Col1'
Union all
SELECT 2,'Col1'
BEGIN TRANSACTION
Update SAMPLETABLE Set Col2 = 'Value changed' Where col1 =1
Select * from SAMPLETABLE with (nolock)
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Select * from SAMPLETABLE
Output is 1, Col1 for both query

SAS multiple large tables join - ERROR: Sort execution failure

When running a large query of the form (using the undocuemnted _method to output the query method):
PROC SQL _method; CREATE TABLE output AS
SELECT
t1.foo
,t2.bar
,t3.bat
,t4.fat
,t5.baa
FROM table1 t1
LEFT JOIN table t2
ON t1.key2 = t2.key2
LEFT JOIN table3 t3
ON t1.key3 = t3.key3
LEFT JOIN table t4
ON t1.key4 = t4.key4
...
LEFT JOIN tablen tn
ON t1.keyn = tn.keyn
;
Where t1 is ca. 6 Gb, t2 is a view on a table that is ca. 500 Gb, and t3, t4 ... tn are each data tables ca. 1-10 Mb (there are typically six or seven of these), I run into the following error:
NOTE: SAS threaded sort was used. ERROR: Sort execution failure.
NOTE: View WORK.table2.VIEW used (Total process time):
real time 17:02.55
user cpu time 2:40.12
The SAS System
system cpu time 2:19.41
memory 303785.64k
OS Memory 322280.00k
Timestamp 11/03/2014 08:13:25 PM
When I sample a very small % of t1 to make it only ca. 30 Mb the query runs okay but even 10% of the table1 causes a similar issue.
How can I profile this query?
to help me choose a better strategy
to enable me to perform the operation on the whole dataset
to limit the need for excessive I/O on the file system (i.e. I could process this batchwise and union the results)
First, this is a really big set of data, and the problem may be with the view. Second, if the data is in a database, you might want a pass-through query, so the processing is all done on the database side.
If the left joins are just looking up values, particularly individual values, you can rephrase the query as:
SELECT t1.foo,
(SELECT t2.bar FROM table t2 WHERE t1.key2 = t2.key2) as bar,
(SELECT t3.bat FROM table t3 WHERE t1.key3 = t3.key3) as bat,
. . .
FROM table1 t1;
This should eliminate any possible sort that would occur on table1.
If the joins are returning multiple rows, this won't work; it will generate errors.

SQL nolock and join

I am using a process that inserts data in 2 tables with rowlock, continuously. In the same time I want to use some queries on these tables. As I said the inserts are done with (rowlock) and I use for the queries the isolation level read uncomitted and nolock.
When I use the queries on a single table they work perfectly, but when I try to join the 2 tables I get this error:
Transaction (Process ID 88) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
Meanwhile, if I use the sp_lock procedure I found that the Key lock becomes a tab lock when I perform my queries.
Does anyone know if there is a special relation between (nolock) and join? And if there is how can I avoid it.
UPDATE:
Insert into tbl1 with (rowlock)
(
col1,
col2,
col3
)
select * from #tbl_temp
( this is in an infinite loop and the data from #tbl_temp is always changed. Actualy this is a more complex process but this is the idea.)
Insert into tbl2 with (rowlock)
(
col3,
col4,
col5
)
select * from #tbl_temp2
In the same time I perform
set transaction isolation level read uncomitted
select col1,col2,col3
from tbl1 with (nolock) -- works fine
select col1,col2,a.col3
from tbl1 with (nolock) join tbl2 with (nolock) on (tbl1.col3 = tbl2.col3)
-- deadlock
You might want to try turning on READ_COMMITTED_SHAPSHOT isolation level for your database.
(But be aware that this will put increased pressure on tempDB)

To execute SQL query takes a lot of time

I have two tables. Tables 2 contains more recent records.
Table 1 has 900K records and Table 2 about the same.
To execute the query below takes about 10 mins. Most of the queries (at the time of execution the query below) to table 1 give timeout exception.
DELETE T1
FROM Table1 T1 WITH(NOLOCK)
LEFT OUTER JOIN Table2 T2
ON T1.ID = T2.ID
WHERE T2.ID IS NULL AND T1.ID IS NOT NULL
Could someone help me to optimize the query above or write something more efficient?
Also how to fix the problem with time out issue?
Optimizer will likely chose to block whole table as it is easier to do if it needs to delete that many rows. In the case like this I delete in chunks.
while(1 = 1)
begin
with cte
as
(
select *
from Table1
where Id not in (select Id from Table2)
)
delete top(1000) cte
if ##rowcount = 0
break
waitfor delay '00:00:01' -- give it some rest :)
end
So the query deletes 1000 rows at a time. Optimizer will likely lock just a page to delete the rows, not whole table.
The total time of this query execution will be longer, but it will not block other callers.
Disclaimer: assumed MS SQL.
Another approach is to use SNAPSHOT transaction. This way table readers will not be blocked while rows are being deleted.
Wait a second, are you trying to do this...
DELETE Table1 WHERE ID NOT IN (SELECT ID FROM Table2)
?
If so, that's how I would write it.
You could also try to update the statistics on both tables. And of course indexes on Table1.ID and Table2.ID could speed things up considerably.
EDIT: If you're getting timeouts from the designer, increase the "Designer" timeout value in SSMS (default is 30 seconds). Tools -> Options -> Designers -> "Override connection string time-out value for table designer updates" -> enter reasonable number (in seconds).
Both ID columns need an index
Then use simpler SQL
DELETE Table1 WHERE NOT EXISTS (SELECT * FROM Table2 WHERE Table1.ID = Table2.ID)