July 13, 2006

How much memory Innodb locks really take ?

Posted by peter

After playing yesterday a bit with INSERT ... SELECT I decided to check is Innodb locks are relly as efficient in terms of low resource usage as they are advertised.

Lets start with a bit of background - in Innodb row level locks are implemented by having special lock table, located in the buffer pool where small record allocated for each hash and for each row locked on that page bit can be set. This in theory can give overhead as low as few bits per row, so lets see how it looks in practice:

I used the same sample table as yesterday:

SQL:
  1. CREATE TABLE `sample` (
  2.   `i` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  3.   `j` varchar(255) DEFAULT NULL,
  4.   PRIMARY KEY  (`i`),
  5.   KEY `j` (`j`)
  6. ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  7.  
  8. mysql> SHOW TABLE STATUS LIKE "sample" \G;
  9. *************************** 1. row ***************************
  10.            Name: sample
  11.          Engine: InnoDB
  12.         Version: 10
  13.      Row_format: Compact
  14.            Rows: 1638757
  15.  Avg_row_length: 61
  16.     Data_length: 100253696
  17. Max_data_length: 0
  18.    Index_length: 128974848
  19.       Data_free: 0
  20.  AUTO_INCREMENT: 1638401
  21.     Create_time: 2006-07-12 07:31:51
  22.     Update_time: NULL
  23.      Check_time: NULL
  24.       Collation: utf8_general_ci
  25.        Checksum: NULL
  26.  Create_options:
  27.         Comment: InnoDB free: 1591296 kB
  28. 1 row IN SET (0.27 sec)

Table with rather small row size, containing 1638400 rows.

Now lets lock all rows in this table and see how long does it take:

SQL:
  1. mysql> begin;
  2. Query OK, 0 rows affected (0.00 sec)
  3.  
  4. mysql>  SELECT count(i) FROM sample LOCK IN share mode;
  5. +----------+
  6. | count(i) |
  7. +----------+
  8. 1638400 |
  9. +----------+
  10. 1 row IN SET (7.02 sec)

Looking at SHOW INNODB STATUS we can see:

History list length 5
Total number of lock structs in row lock hash table 6092
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 42306982, ACTIVE 89 sec, process no 10099, OS thread id 1878960
6093 lock struct(s), heap size 503104

So 503104 bytes are used to lock 1638400 rows, making it less than 3 bits per locked row;

Now lets see how much exclusinve locks take:

SQL:
  1. mysql> begin;
  2. Query OK, 0 rows affected (0.00 sec)
  3.  
  4. mysql>  SELECT count(i) FROM sample FOR UPDATE;
  5. +----------+
  6. | count(i) |
  7. +----------+
  8. 1638400 |
  9. +----------+
  10. 1 row IN SET (8.60 sec)

Interestingly enough this statement already takes 1.5 seconds longer (I repeated runs many time to ensure it is repeatable) so exclusive locks seems to be more expensive to set.

On other hand it still consumes exactly same amount of memory:

History list length 5
Total number of lock structs in row lock hash table 6092
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 42306989, ACTIVE 195 sec, process no 10099, OS thread id 1878960
6093 lock struct(s), heap size 503104
MySQL thread id 7429, query id 24542 localhost root
show innodb status

Note, running statement in consistent read mode which does not set any locks is going to be faster than any of locking modes, however we can see locking overhead is not that large:

SQL:
  1. mysql> SELECT count(i) FROM sample;
  2. +----------+
  3. | count(i) |
  4. +----------+
  5. 1638400 |
  6. +----------+
  7. 1 row IN SET (4.50 sec)

So we can lock 1638400 rows in 2.5 seconds on this pretty old box, which means locking speed will be few millions per second on modern systems.

So we have tested how much memory is using locking all the rows - so all rows are locked from the page. In other test we'll lock small random portion of rows (about 1/16) with random distribution to the pages (column j was populated by md5(rand()) values) :

SQL:
  1. mysql> begin;
  2. Query OK, 0 rows affected (0.00 sec)
  3.  
  4. mysql> SELECT count(*) FROM sample WHERE j LIKE "5%" LOCK IN share mode;
  5. +----------+
  6. | count(*) |
  7. +----------+
  8. |   102216 |
  9. +----------+
  10. 1 row IN SET (4.44 sec)

Looking at SHOW INNODB STATUS we can see:

Total number of lock structs in row lock hash table 440
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 42306999, ACTIVE 133 sec, process no 10099, OS thread id 1878960
441 lock struct(s), heap size 44352

So we locked over 100K rows using about 44KB. This is still quite efficient using less than 4 bits per locked row.

In practice this means memory consumption by row level locks should not be the problem even for rather large databases - even billion of locked rows should take half GB of memory, which is small fraction of memory used on serious systems. Furtermore you would unlikely need or want to lock every row in your table/database which makes it even smaller problem.

Related posts: :SELECT LOCK IN SHARE MODE and FOR UPDATE::Innodb locking and Foreign Keys::INFORMATION_SCHEMA tables in the InnoDB pluggable storage engine:
 

3 Comments »

  1. [...] Lock table Innodb can lock tables but it will still need to set row level locks which is memory and CPU overhead. For some bulk operations it would be more efficient to use table locks. As I tested it really takes some resources. [...]

    Pingback :: August 6, 2006 @ 1:56 pm

  2. [...] Update (23-Oct-2006) Found what I was looking for about the InnoDB lock table and it’s behavior at MySQL Performance Blog. Update (21-Oct-2006) Found an explanation here which says: “The SQL statement sets locks on all the records it scans. If you have a small buffer pool, then the InnoDB lock table may indeed grow so big that it does not fit in the buffer pool. “ [...]

    Pingback :: October 23, 2006 @ 1:32 pm

  3. [...] artigo no MySQL Performance Blog (que eu assino o feed) também explica como ocorre o lock em tabelas innodb: in Innodb row level locks are implemented by having special lock table, located in the buffer pool [...]

    Pingback :: June 7, 2008 @ 11:06 pm

 



Subscribe without commenting


This page was found by: mysql show locks innodb list of locks innodb lock exclusiv... mysql lock innodb update innodb memory