MySQL innodb select for update concurrency - mysql

MySQL documentation says that SELECT FOR UPDATE sets an IX lock. IX lock is intention exclusive lock and when issued it means "Transaction T intends to set X (exclusive) locks on scanned rows". This means that before SELECT FOR UPDATE succeeds it must first get IX and then X. MySQL glossary says this about intention exclusive lock:
intention lock
A kind of lock that applies to the table level, used to indicate what kind of lock the transaction intends to acquire on rows in the table. Different transactions can acquire different kinds of intention locks on the same table, but the first transaction to acquire an intention exclusive (IX) lock on a table prevents other transactions from acquiring any S or X locks on the table. Conversely, the first transaction to acquire an intention shared (IS) lock on a table prevents other transactions from acquiring any X locks on the table. The two-phase process allows the lock requests to be resolved in order, without blocking locks and corresponding operations that are compatible. For more details on this locking mechanism, see Section 14.3.5.3, “InnoDB Lock Modes”.
Also IX and IX are compatible (lock type compatibility matrix) which means that if transaction 1 issues IX and right after another concurrent transaction issues IX it will succeed.
Is there a possibility that two concurrent IX are issued at the exact same moment and MySQL grants/acquires IX for both transactions for the same table. Or MySQL grants at any point only one IX if concurrent IX are issued. I'm thinking that MySQL grants only one of them, even if call is made and triggered at MySQL side at the exact same time.
EDIT: basically if I generalize my question: If two (concurrent) sql statements that lock rows (e.g. update, select for update, select lock in share mode, insert, delete) come to MySQL at the exact same time, I suppose MySQL treats them sequentially. Just want to make sure, that I am thinking right how MySQL works internally.

Locking operations necessarily are serialized. At the nanosecond level in the server's logical workflow there's no such thing as "multiple lock requests at precisely the same moment." Even if there were, the server's logic would arbitrarily place them into some order and grant them one after the other.
A really smart next-generation massively parallel server might be able to figure out that different lock requests were guaranteed never to interfere with each other, and handle them truly in parallel. But for now, there's no such thing as simultaneous.

Related

Is SX lock in MySQL the same as a update lock

According to All about locking in SQL Server, a update lock can be transformed into a exclusive lock when there is something to write. Meanwhile, the compatibility of the three locks(X,S and U) can be refer to the following table.
X S U
X ✗ ✗ ✗
S ✗ ✓ ✓
U ✗ ✓ ✗
However, It is mentioned in some blogs that there is a SX lock since MySQL 5.7 which implements an idea from the paper Concurrency of operations on B-trees(1977). From these blogs I find the SX lock is quite similar with the update lock. For example, they have the same compatibility table.
Since I can't find more "official" introduction about the SX lock in MySQL, I want to ask what's the difference between both of the locks?
Since the compatibility matrix defines a lock, having the same matrix makes the update lock and the sx lock equivalent.
Actually, in database theory, an update lock should behave asymmetrical, disallowing a new shared lock when there is already an update lock, see e.g. these lecture notes, penultimate page. Your reference also mentions this:
It is important to understand that update lock is asymmetrical in regards of shared locks. While the update lock can be imposed on a record that has the shared lock, the shared lock cannot be imposed on the record that already has the update lock
Practically though, both the MySQL sx-lock and the SQL Server (and others) update lock are symmetrical, like in your matrix.
The purpose of an update lock is to allow other transactions to still read the data (using a shared lock) while preventing a deadlock when two transactions want to escalate to a exclusive lock (as neither can do that when the other has a shared lock).
So, to conclude, the lock types are, in principle, the same, although I could imagine that they are named differently to emphasize that they are not intended to be asymmetric, and maybe to leave an option to later add the "real" update lock, so you may or may not want to treat them as unequal in that regard.
But there are major differences in how they are used. For example, in contrast to SQL Server, MySQL does not use update locks on rows: MySQL uses exclusive locks for updates, and to allow for concurrent reads, usually does not lock while reading, unless you use locking reads.
After acid requirements, the detailled behaviour (when which lock is applied on what object for what operation) is mostly relevant for performance and concurrency. While you could just lock the whole database for every query, this would only allow one query at a time, so the more fine-grained you lock specific objects, the more concurrency you allow (with the tradeoff to increase the risk of deadlocks).
Now to the purpose of the sx-locks in MySQL:
They were introduced to allow a more fine-tuned locking of indexes, see MySQL-5.7 improves DML oriented workloads, as some operations on indexes required the complete index to be exclusively locked, hindering concurrency. So the reason they are not more present int the documentation is that, although there might be other use cases for this type in the future, they are currently limited to very specific internal locking.

MySQL lock compatibility

According to the official docs from here:
the lock compatibility matrix:
X IX S IS
X Conflict Conflict Conflict Conflict
IX Conflict Compatible Conflict Compatible
S Conflict Conflict Compatible Compatible
IS Conflict Compatible Compatible Compatible
The docs also say:
Thus, intention locks do not block anything except full table requests
(for example, LOCK TABLES ... WRITE). The main purpose of IX and IS
locks is to show that someone is locking a row, or going to lock a row
in the table.
If the intention locks only block full table requests, then how to explain the IX conflicts with S lock in the above lock compatibility matrix? To my understanding, the S and X in the lock compatibility matrix are both record locks, it's that right?
To my understanding, the S and X in the lock compatibility matrix are both record locks, it's that right?
That is correct. Incorrect is the assumption that you can directly compare table and record locks, which the documentation probably does not make completely clear, and the part "These rules can be conveniently summarized by means of the following lock type compatibility matrix" might be a bit misleading, as it does not cover everything (namely any conflict information about S/X-table locks with record locks).
Technically, that matrix defines the result when checking locks on some object, e.g. whenever MySQL tries to add a lock to something. If you try to get an S lock on a table, it would conflict with an IX lock on that table.
If a record could have an intention lock, it would conflict there too. Just because a lockable object doesn't use intention locks doesn't change the (general) compatibility matrix.
Technically, the internal datatype for locks is the same for records and tables, the intention locks are just never set for records. A record lock will actually never be compared to a table lock (as these are two different objects), and the only reason a record lock interferes with a table lock is the locking protocol (which requires a lock on both the table and the record to lock a record).
So to lock a record, you will typically require a different table lock. The compatibity matrix is the same, but the value for the table can and usually will differ from the value of the record.
So
Thus, intention locks do not block anything except full table requests (for example, LOCK TABLES ... WRITE).
is correct because only full table requests require a lock that conflicts with an existing intention lock, and records do not use intention locks. But to repeat it: you still have to compare tow different locks. An S-lock on a record cannot conflict with the lock on a table, as these two object will never be compared.
The manual is mixing table and record locks a bit. It actually defines IS and IX as:
Intention shared (IS): Transaction T intends to set S locks on individual rows in table t.
Intention exclusive (IX): Transaction T intends to set X locks on those rows.
so if you want, IS and IX in the matrix can somewhat be interpreted as properties of rows (which they technically are not), while you read them as the lock on the table (as it can only be set for a table, but which is a different lock). But the matrix still only describes the situation to compare records (which the manual probably does not make clear enough), and it does not include any compatibility information with an S or X table lock.
So to summarize: you do not need "to explain the IX conflicts with S lock in the above lock compatibility matrix", as it simply does not cover that situation.

Can range lock in SQL be acquired in share mode

I have a query such as
Select count(*) from table log where num = ?;
If I set the isolation level to serializable, then the range lock will be acquired for the where clause.
My question is: Can other transaction also acquire the range lock in share mode to read the count as the above OR the range lock is exclusive and all other transactions have to wait until the current transaction commits before executing the above read query.
Background: I am trying to implement a view counter for heavy traffic website. To reduce IO to the database, I create a log table so that every time there is a view, I only write a new row in the log table. Once a while, I (randomly) decide if I want to clear the log table and add the number of rows in the log table into a column of a view count table. This means I have to be careful with interleaving transaction.
The statements below are relevant only to SQL Server and were made before the OP made clear this was really about MySQL, about which I know nothing. I'm leaving it here since it (and the resulting discussion) might be of some use nevertheless, but it is not a complete, relevant answer to the question.
SELECT statements only ever acquire shared locks, on all isolation levels (unless overridden with a table hint). And shared locks are always compatible with each other (see Lock Compatibility), so there's no problem if other transactions want to acquire shared (range) locks as well. So yes, you can have any number of queries performing SELECT COUNT(*) in parallel and they will never block each other.
This doesn't mean other transactions don't have to wait. In particular, a DELETE query must eventually acquire an exclusive lock, and it will have to wait if the SELECT is holding a shared lock. Normally this is not an issue since the engine releases locks as soon as possible. When it does become an issue, you'll want to look at solutions like snapshot isolation, which uses optimistic concurrency and conflict detection rather than locking. Under that model, a SELECT will never block any other query (save those that want table locks). Of course, this isn't free; the row versioning is uses takes up disk space and I/O.

Transaction vs locking in mysql

I have some confusing regarding transaction and locking in MySQL.
What is difference between transaction and locking in MySQL and how it related to each other?
Is transaction related to DML (INSERT, UPDATE and DELETE) only or it also related to SELECT query?
Is transaction cover the Truncate?
for example:
START TRANSACTION;
SELECT * from XYX;
UPDATE abc SET summary=788 WHERE type=1;
TRUNCATE TABLE pqr;
INSERT INTO ABL VALUE('OK');
COMMIT;
It's requires a large explanation to full cover your question.
In short a transaction is an "atomic operation". If it's committed all inside it is committed, if it's rolled back all inside it is rolled back.
Locks are a mechanism to avoid dirty and ghost reads (and two process to make updates at the same time, messing with one another) in parallel/concurrent environments.
In a general saying transaction levels defines locks strategies.
Almost everything is contained in a transaction, including the select and truncate.
I suggest you to hit the books to learn about transaction levels, locks (strategies, granularity, performance, deadlocks, starvation, glutton philosophers...)
What is transaction?
A transaction comprises a unit of work performed within a database
management system (or similar system) against a database, and treated
in a coherent and reliable way independent of other transactions.
Also, there is a documentation on MySQL site
What is database lock?
A lock, as a read lock or write lock, is used when multiple users need
to access a database concurrently.
So, it's completely different things, you can't 'compare' them.

How can priority be given to write/update over read in MySQL?

In my application, I want any insert to the database to be executed as soon as a request comes for writing some data.
I am using InnoDB engine.
Since insertion requires an exclusive lock, it is possible that while current read query has a shared lock, some other reads might come which again have a shared lock and the write operation might have to wait for a long time.
I want that when there is a write operation in queue, no read operation gets a shared lock. As soon as the reads which were initiated before the current write request are completed, the write operation should be executed. After that all other read operations should take place.
How can this be implemented?
Edit
Since I am using InnoDB tables and I am not implementing table lock, there should not be a conflict between select and insert. It would be select and update. (Please correct me if there can be a conflict between select and insert as well)
In MySQL, update has higher priority than select. But if there are some read queries being executed, then update query comes in followed by some read queries. In that case, will the read queries coming after update wait for the update to finish as mentioned here http://dev.mysql.com/doc/refman/5.0/en//table-locking.html OR they will get shared lock along with the read queries which were there before the update query was fired?
You don't need to acquire shared locks when reading from the database. In fact, with the default transaction isolation level REPEATABLE READ ordinary SELECT queries within one transaction read from a consistent snapshot. No locks are acquired and required, within this transaction you will simply not see any changes committed in other transactions.
Since no shared locks are acquired, exclusive locks for updating queries are immediately granted to other sessions in the order they are filed.
MySQL doc says the following
Consistent read is the default mode in which InnoDB processes SELECT statements in READ COMMITTED and REPEATABLE READ isolation levels. A consistent read does not set any locks on the tables it accesses, and therefore other sessions are free to modify those tables at the same time a consistent read is being performed on the table.
Suppose that you are running in the default REPEATABLE READ isolation level. When you issue a consistent read (that is, an ordinary SELECT statement), InnoDB gives your transaction a timepoint according to which your query sees the database. If another transaction deletes a row and commits after your timepoint was assigned, you do not see the row as having been deleted. Inserts and updates are treated similarly.
You can try looking at INSERT DELAYED Mysql Insert Delayed
Unfortunatelly it is not available on innodb.
PS: A exclusive lock cannot be acquired if there is already a shared lock on the table. So basicly, in your situation: 3 reads obtain a shared lock, one insert needs exclusive lock. The insert will only be able to obtain the lock after the selects have finished.