MySQL Isolation levels, Measuring their impact on deadlocks - mysql

I'm trying to generate a few graphs using the sysbench benchmark (default configuration) trying to show the relationship between deadlocks and isolation level in MySQL.
But I get some strage results: I was under the impression that repeatable read would have more deadlocks than read committed (which is the case), but significantly more than read uncommitted. In fact it turns out that read uncommitted has more deadlocks than either.
Is this normal? And if so, why?

Deadlock can happen in any isolation level. It's hard to tell without the actual tests, but I guess that in case of read commited / repeatable read, if you have to read a value of a row being updated, the value is being read from the rollback log, but in case of read uncommited rollback log is not used, so it the row is locked for update, the read has to wait for the actual value to be written. But it's a wild guess, having more deadlocks in read uncommited is a strange behaviour and most likely - implementation dependent. I would be interested if you could provide the actual tests, and if the test can be repeated in different versions of MySQL.

Related

Would it be advantagous to have MySQL default transaction mode on READ ONLY and READ UNCOMMITTED and only override when needed?

The following strategy seems to be working, but am I overlooking something? Why not do this always for read-intensive systems that for most queries don't need data consistency? Like for instance blogging / publication systems. Seems to me
Set the database-default to read-only mode. This will catch programming errors and probably give better read performance
-- MySQL / MariaDB schema creation example
-- in a read intensive system, default to read only for security and speed
SET GLOBAL TRANSACTION READ ONLY;
Set the database-default to the least strict transaction isolation level. This will prevent locking and probably increase read performance
-- MySQL / MariaDB schema creation example
-- if data integrity is not critical for most queries, choose maximum performance
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Override only for queries that do need write-access and / or higher transaction isolation levels.
In a read intensive system these extra query-statements around write-statements won't be noticeable
-- MySQL / MariaDB example
...
SET SESSION TRANSACTION READ WRITE;
UPDATE table_x SET field_y=10;
SET SESSION TRANSACTION READ ONLY;
...
I have never heard of a situation where READ UNCOMMITTED was the right thing to do. It seems clear that reading changes from other transactions that aren't committed yet — and may be rolled back — is likely to lead to a lot of phantom reads and other logic problems.
I would be in favor of setting the default transaction isolation level to READ COMMITTED, although this also depends on the application needs. Some applications require that they use REPEATABLE READ semantics by default. We can't say that one or the other of these is "better" because it depends what the application needs.
I am not aware that there's any performance advantage to setting a transaction access mode to READ ONLY. It prevents that transaction from changing any data, but in my opinion if you have code bugs such that you don't know if a given transaction is going to change data, then you have bigger problems.
InnoDB has a read-only mode that affects the whole instance, not individual transactions. Read about it here: https://dev.mysql.com/doc/refman/8.0/en/innodb-read-only-instance.html I doubt this would give significant performance benefits for an average application. It would have to be a very high-traffic application, so you have some bottleneck caused by some of the background threads that are disabled in InnoDB read-only mode. But in that type of application, you'd naturally need read-write mode.

Does using higher isolation level decreases the probability of having deadlocks?

So I am trying to learn MySQL and I came across the isolation levels (SERIALIZED, REPEATABLE READ, READ COMMITED, READ UNCOMMITED)
I believe my question is quite simple, but I did not find any information in the web so here it goes:
If I change the default REPEATABLE READ to SERIALIZED or even from READ UNCOMMITED to another higher level of isolation does I have less probabilities of having deadlock problems?
Thanks in advance!
Actually, deadlocks between SELECT operations on the one hand and INSERT or UPDATE on the other hand will be less likely if you use the more permissive READ UNCOMMITTED isolation level for your SELECT operations.
If it's OK for your SELECT operations not to get the results of concurrent changes to your tables, use that.
The possibility of deadlocks is not affected by isolation level. Isolation level changes the behavior of read operations, but deadlock occurs due to write operations. However, isolation level sets fewer locks, hence it can help you to avoid certain lock types (e.g. gap locking).
These tips to avoid dead_lock are very helpful https://www.percona.com/community-blog/2018/09/24/minimize-mysql-deadlocks-3-steps/

What transactions does commit / rollback affect?

Does it only affect whatever commands were after the relevant BEGIN transaction?
For example:
BEGIN TRAN
UPDATE orders SET orderdate = '01-08-2013' WHERE orderno > '999'
Now, assume someone else performs a data import that inserts 10,000 new records into another table.
If I subsequently issue a ROLLBACK command, do those records get discarded or is it just the command above that gets rolled back?
Sorry if this a stupid question, I'm only just starting to use COMMIT and ROLLBACK.
Any transaction is confined to the connection it was opened on.
One of the four ACID properties of any relational database management system is Isolation. That means your actions are isolated from other connections and vice versa until you commit. Any change you do is invisible to other connections and if you roll it back they will never know it happened. That means in turn that changes that happened somewhere else are invisible to you until they are committed. Particularly that means that you can't ROLLBACK anyone else's changes.
The Isolation is achieved in one of two ways. One way is to "lock" the resource (e.g. the row). If that happens any other connection trying to read from that row has to wait until you finish your transaction.
The other way is to create a copy of the row that contains the old values. In this case all other connections will see the old version until you commit your transaction.
SQL Server can use both isolation methods. Which one is used depends on the isolation level you choose. The two Snapshot Isolation Levels provide the "copy method" the other four use the "lock method". The default isolation level of "read committed" is one of the "lock method" isolation levels.
Be aware however that the isolation level "READ UNCOMMITTED" basically circumvents these mechanisms and allows you to read changes that others started and have not yet committed. This is a special isolation level that can be helpful when diagnosing a problem but should be avoided in production code.

Read changes from within a transaction

Whatever changes made to the MySQL database, are those changes readable within the same transaction? Or should I commit the transaction to read the changes?
I could easily test this. But putting a question in SO brings up a lot of good suggestions. Thanks for any input.
Assuming you're using InnoDB, the answer to your first question is generally yes, implying the answer to your second is generally no.
By default MySQL's InnoDB uses a technique called consistent non-locking reads:
The query sees the changes made by
transactions that committed before
that point of time, and no changes
made by later or uncommitted
transactions. The exception to this
rule is that the query sees the
changes made by earlier statements
within the same transaction.
That being said, there's a lot of stuff to know about transactions. You can change the isolation level of a transaction in order to control the transaction results more thoroughly.
The chapter on the InnoDB Transaction Model is a great place to start.

mysql isolation levels

I'm a bit confused by the documentation here. I have a transaction, which
start transaction
does some updates
does some selects
does some more updates
commit
I want my selects at step 3 to see the results of updates in step 2 but I want to be able to roll back the whole thing.
read committed seems to imply that selects only show data that's been committed, and repeatable read seems to imply that all subsequent selects will see the same data as existed at the time of the 1st select - thus ignoring my updates. read uncommitted seems to do the right thing, but: "but a possible earlier version of a row might be used" -- this is also not acceptable, as my selects MUST see the result of my updates.
is serializable really my only hope here?
I'm working off the documentation here
Transaction isolation levels describe only the interaction between concurrent transactions. With any isolation level, stuff that you have updated within the same transaction will be updated when you re-select them from that transaction.
The right isolation level in your case seems to be read commited, so you can rollback at any point and uncommited data is not visible in other transactions.