Take the 2-minute tour ×
Database Administrators Stack Exchange is a question and answer site for database professionals who wish to improve their database skills and learn from others in the community. It's 100% free, no registration required.

I have a MySQL 5.5.23 DB that performs about 3k qps, 5% of which are writes. Lately, I've been having a big problem with random write freezes. Everything is going great, and then all of a sudden any write that comes in stops in the "update" or "Updating" state. They stay in this state for about a minute or two and then finally finish. The problem is that with such high amount of connections, when they freeze randomly like this, the connection stays open and then I inevitably get too many connection errors.

It's happening on all tables during both INSERT and UPDATE queries.

Has anyone seen this before? Is there anything that can be done about it?

I'm using Amazon RDS with the biggest instance they offer. I'd be more than happy to provide any information you guys need, just let me know what that is.

UPDATE: The main table I'm inserting into is:

CREATE TABLE `mytable` (
 `hash` varchar(5) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
 `name` varchar(256) DEFAULT NULL,
 `ip` varchar(64) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
 `deletehash` char(15) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
 `datetime` datetime NOT NULL,
 `api_key` varchar(64) CHARACTER SET latin1 COLLATE latin1_general_cs DEFAULT NULL,
 `account_id` int(10) unsigned DEFAULT NULL,
 `type` varchar(15) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
 `width` int(10) unsigned NOT NULL DEFAULT '0',
 `height` int(10) unsigned NOT NULL DEFAULT '0',
 `size` int(10) unsigned NOT NULL DEFAULT '0',
 `animated` tinyint(1) NOT NULL DEFAULT '0',
 `views` int(10) unsigned NOT NULL DEFAULT '0',
 `lastviewed` datetime NOT NULL,
 PRIMARY KEY (`hash`),
 UNIQUE KEY `deletehash` (`deletehash`),
 KEY `datetime` (`datetime`),
 KEY `account_id` (`account_id`),
 KEY `ip` (`ip`),
 KEY `api_key` (`api_key`),
 KEY `views` (`views`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Sample insert:

insert into mytable (hash, name, ip, deletehashe, datetime, api_key, account_id, type, width, height, size, animated, views, lastviewed) values('abcde', 'file name', '127.0.0.1', 'abcdefghijklmn', '2012-05-31 00:00:00', NULL, NULL, 'mime/type', 0, 0, 0, 0, 0, '0000-00-00 00:00:00');

Sample update:

update mytable set views = views+1, lastviewed = NOW() where hash = 'abcde';

"Updating"

share|improve this question
1  
Can you provide a sample of an INSERT and an UPDATE. –  ypercube Jun 1 '12 at 8:27
    
Thanks for the reply. I've added some examples. –  Alan Jun 1 '12 at 17:54
    
can you post the output of SHOW ENGINE INNODB STATUS\G during a lockup? –  Derek Downey Jun 1 '12 at 18:08
    
What OS your running this database? Is disk busy during this time? I see your using Amazon RDS, not sure you can get this info. How big is your database in size? –  sfgroups Jun 2 '12 at 20:59
add comment

1 Answer 1

up vote 3 down vote accepted

I think the issue is due to the choice of the clustered index. From MySQL docs, Clustered and Secondary Indexes:

Every InnoDB table has a special index called the clustered index where the data for the rows is stored. Typically, the clustered index is synonymous with the primary key. To get the best performance from queries, inserts, and other database operations, you must understand how InnoDB uses the clustered index to optimize the most common lookup and DML operations for each table.


Also check the answer by @marc_s in this SO question: How to choose the clustered index in SQL Server?, where he mentions:

According to The Queen Of Indexing - Kimberly Tripp - what she looks for in a clustered index is primarily:

  • Unique
  • Narrow
  • Static

And if you can also guarantee:

  • Ever-increasing pattern

then you're pretty close to having your ideal clustering key!


Now, your clustered index is the (Primary Key):

hash varchar(5) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,

which (lets go through the check-list) is:

  • Unique (yes, OK)
  • Narrow (yes, OK)
  • Static (perhaps, you know that)

but is probably not:

  • Ever-increasing pattern (No, it probably isn't)

So, what happens when you use a non-ever-increasing clustered index?

I can't answer better than Kimberly L. Trip: Ever-increasing clustering key - the Clustered Index Debate..........again!

If the clustering key is ever-increasing then new rows have a specific location where they can be placed. If that location is at the end of the table then the new row needs space allocated to it but it doesn't have to make space in the middle of the table. If a row is inserted to a location that doesn't have any room then room needs to be made (e.g. you insert based on last name then as rows come in space will need to be made where that name should be placed). If room needs to be made, it's made by SQL Server doing something called a split. Splits in SQL Server are 50/50 splits - simply put - 50% of the data stays and 50% of the data is moved. This keeps the index logically intact (the lowest level of an index - called the leaf level - is a douly-linked list) but not physically intact. When an index has a lot of splits then the index is said to be fragmented. Good examples of an index that is ever-increasing are IDENTITY columns (and they're also naturally unique, natural static and naturally narrow) or something that follows as many of these things as possible - like a datetime column (or since that's NOT very likely to be unique by itself datetime, identity).

Note that despite the mention of SQL-Server, the same concept applies to InnoDB clustered indexes as well. I suppose that the clustered index has 2 issues:

  • When you are inserting a new row (the "random" hash guarantees that) it gets inserted in a random location of the index. This means that it sometimes will find no space there available to be inserted (note that InnoDB always leaves some space free in the index but when that free-available space is filled) there has to be some rearrangement of the index - and that takes time.

  • What the rearrangement is also causing over time is fragmentation of the index. Which will eventually make other queries and statements slower.

share|improve this answer
    
+1 my first thought is also the indexes. –  Derek Downey Jun 1 '12 at 18:35
    
Thanks so much for the in-depth answer. I'm in the process of changing the table to use an auto incrementing primary key instead. It sounds like that will fix the issue. –  Alan Jun 12 '12 at 17:29
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.