A few notes on locking in MySQL

This is another article in a series of articles titled “A few notes …” in which I will be posting some important information about locking concepts, different types of locks and what locks table engines support. Just like the previous article, the purpose of this article is to highlight important aspects that you should have in the back of your mind when developing applications.

Classes of locks

There are two classes of locks:

Read Lock (Shared Lock)

Read locks as the name suggests, are locks taken on resources to provide consistent read by blocking writes to that resource. The read locks are also known as shared locks because many clients can acquire read locks on the same resource simultaneously. The other thing to know is that, while read lock is in place, no write lock can be acquired on that resource.

Following is how MySQL will grant read lock:

  • if there is no write lock set on the resource grant the read lock immediately
  • if there is a write lock on the resource, put the lock in the read lock queue

Write Lock (Exclusive Lock)

Write lock is taken on a resource when it needs to be modified. There can be only one write lock on a resource at a given time. While a write lock is held on a resource, all other read lock requests must also wait.

Following is how MySQL will grant write lock:

  • if there is no (read/write) lock on the resource, grant the write lock immediately
  • if there is a lock on the resource, put the write lock in the write lock queue

Priority of Read and Write Lock

Write lock has a higher priority than read lock. When a resource is unlocked, and if there are lock requests waiting in the queue, then the lock is granted in the following manner:

  • grant the lock first to the request waiting in the write lock queue
  • if there is no lock request for the resource in the write lock queue, then grant the lock to the first request in the read lock queue

Now let’s have a brief overview of the locking mechanism of two popular table engines.

Locking in MyISAM

MyISAM supports table-level locking and does not support row-level locking. Because of this behavior, MyISAM is typically well suited for applications which have a high percentage of reads as compared to writes. But because MyISAM supports locking at a high level, the memory needed for locking is typically less, say when you compare it to row-level locks.

However, MyISAM does allow concurrent INSERTs in some situations!

Concurrent INSERTs

If there are no holes in MyISAM table, then INSERTs happen at the end of the table, and in such a situation INSERTs and SELECTs are allowed to happen concurrently on the same table, with INSERT needing no write locks. But there is a caveat, if there are many INSERT requests, then the INSERTs are done serially, which implies that only one INSERT can execute concurrently with SELECTs on the same table. Now what exactly are hole? Holes are produced when rows are deleted and/or updated in the middle of a MyISAM table.

Locking in InnoDB

InnoDB unlike MyISAM supports both table-level locking as well as row-level locking, which allows for a more fine-grained control over the resource to be locked. Row-level locking allows InnoDB to be extremely efficient in case of heavy write-load.
InnoDB also has a very nice feature MVCC, which allows for non-locking consistent reads. This is achieved by having different snapshots of data available to different transactions. However, if you have the transaction isolation level set to SERIALIZABLE then plain SELECTs are automatically converted to locking SELECTs.

However, AUTO_INCREMENT columns need table-level locks.

Table-level AUTO_INC locks

INSERTs into AUTO_INCREMENT column need table-level lock for the duration of the INSERT statement. This is so that the INSERTs are safe for statement-based replication. However, as of MySQL >= 5.1, which also introduced row-based replication, this behavior is configurable using the variable innodb_autoinc_lock_mode, but you still need to be using row-based replication for the INSERTs to be safe for replication. Set the value of innodb_autoinc_lock_mode to 2, and then INSERT like statements will not take any table-level locks.

This post might not have been entirely exhaustive on the topic of locking, but I hope it provided you with enough understanding of locking to help you in designing applications that need them!

Ovais is a storage architect with keen focus on reliability, efficiency and performance of OLTP databases, more specifically MySQL. He currently works at Uber on ensuring storage reliability and scalability. Previously, he helped different web properties scale their MySQL infrastructure. He also worked at Percona as a Senior MySQL consultant and at a few other startups in various capacities.

  • Pingback: MySQL Table Locking « Lamp Stack()

  • Nitesh Kumar

    Hi ,

    I want to lock some specific rows for update or delete or insert and rest rows of the tables should remain unlocked i.e. available for any transaction whether read or write . Is it possible in mysql if yes then please help me on this.

  • Nitesh, you can use SELECT … FOR UPDATE for your purpose. But this is going to lock every row it scans not just the row that matches the WHERE clause, unless you have proper indexes in place to allow MySQL to scan only the rows needed.

  • Nitesh Kumar

    Thanks Ovais Tariq,
    I used select for update and I am using
    innodb table with innodb_file_per_table but still my purpose is not
    solved. It locks the complete table which is not my requirement . I have a table in which only two columns exist one is primary key and other is simple varchar column with no index . Update/Insert is not allowed on the table after select for update is apllied on some rows of the table. Please help me on this.

  • Nitesh,
    The reason whole table is getting locked is because your query would be reading all those rows and doing a table scan. Can you show me the explain output of the select … for update query

  • Sachin Agrawal

    Its very nice notes.