I am reading a lot about locking and isolation levels in MySQL and InnoDB.
I understood the technical differences and basic approach, but I still fail to understand a situation where for example READ UNCOMMITTED
will give me better performance than READ COMMITTED
.
Here is my simulation:
CREATE TABLE `t` (
`i1` INT(11) NOT NULL,
`i2` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`i1`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
insert into t values(10,10), (20,20), (30,30), (40, 40), (50,50),(60,60);
T1:
MariaDB [maint]> begin;
Query OK, 0 rows affected (0.00 sec)
MariaDB [maint]> update t set i2=100 where i1=60;
Query OK, 1 row affected (0.00 sec)
T2 with READ UNCOMMITTED
:
MariaDB [maint]> SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
MariaDB [maint]> select i2 from t where i1 =60;
+------+
| i2 |
+------+
| 100 |
+------+
1 row in set (0.00 sec)
So the logic as expected, and no locks.
T2 with READ COMMITTED:
MariaDB [maint]> SET TRANSACTION ISOLATION LEVEL READ COMMITTED; START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
MariaDB [maint]> select * from t where i1 =60;
+----+------+
| i1 | i2 |
+----+------+
| 60 | 60 |
+----+------+
1 row in set (0.00 sec)
The logic works as I expected, and again no lock.
So simply the only difference is that READ UNCOMMITTED
just took the data before commit and READ COMMITTED
took a snapshot.
Can someone help me create a simulation or explain a situation in which UNCOMMITTED
will have no locks whereas COMMITTED
would have? Same for REPEATABLE READ
vs COMMITTED
.
Best Answer
In my opinion... If you are tweaking isolation levels for performance then you have inefficient/inadequate code/schema/indexes and should focus on that instead.
Think about it... You can perform hundreds of 'simple' queries per second from dozens of connections. So, if your queries are 'simple' and you don't have too many of them, then they will rarely collide -- hence, the isolation mode won't matter!
select i2 from t where i1 =60;
-- The obvious index isINDEX(i1)
. Better would bePRIMARY KEY(i1)
, but that may not be appropriate. Ifi1
were not the PK, then the best is a "covering" index:INDEX(i1,i2)
-- the query is performed in the index, not touching the data.You will be hard pressed to run enough of the queries you mentioned fast enough from enough connections to have them stumble over each other. In fact, you are more likely to be blocked by the "Query cache". For serious production work, that is usually turned completely off:
query_cache_size = 0
andquery_cache_type = 0
.Back to my first point... Changing the Isolation Level changes the results that you might get from queries! So, doing it for performance reasons could mess with the application output.