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 an indexed column that stores an MD5 hash. Thus, the column will always store a 32-character value. For whatever reason, this was created as a varchar rather than a char. Is it worth the trouble of migrating the database to convert it to a char? This is in MySQL 5.0 with InnoDB.

share|improve this question
add comment

3 Answers 3

It looks like you will save 1 byte per value or about 3% by converting to a char. Probably not worth it if you are storing MD5 in hex anyway - you could save 50% by using a binary instead.

Thanks to Ovais (see comments) for pointing out that char(32) can use a lot more than 32 bytes if you are using a multibyte character set.

share|improve this answer
    
Good call on changing to binary. –  RThomas May 10 '11 at 21:17
    
I'm planning on converting this into a binary. Now that I think about it though, the size shouldn't be any different just based on whether I'm using a byte or a char since our encoding is utf-8. Or am I wrong? –  Jason Baker May 17 '11 at 17:36
    
@Jason - encoding doesn't apply to binary - or have I misunderstood? –  Jack Douglas May 17 '11 at 18:53
1  
for a char(32) column with a character set of utf-8, every value would need 32x3 bytes for storage. Why would you need to set the MD5 hash value to be utf-8. Converting to binary(32) would need 32 bytes per value. –  ovais.tariq May 25 '11 at 12:05
    
MD5 can be 32 byte hex or 16 byte (128 bit) binary. Thanks for the useful info about charset - I'll update my answer –  Jack Douglas May 25 '11 at 12:25
add comment

A similar question was asked before

Performance implications of MySQL varchar sizes

Here is the excerpt of my answer

You must realize the tradeoffs of using CHAR vs VARCHAR

With CHAR fields, what you allocate is exactly what you get. For example, CHAR(15) allocates and stores 15 bytes, no matter how characters you place in the field. String manipulation is simple and straightforward since the size of the data field is totally predictable.

With VARCHAR fields, you get a completely different story. For example VARCHAR(15) actually allocates dynamically up to 16 bytes, up to 15 for data and, at least, 1 additional byte to store the the length of the data. If you have the string 'hello' to store that will take 6 bytes, not 5. String manipulation must always perform some form of length checking in all cases.

The tradeoff is more evident when you do two things: 1. Storing millions or billions of rows 2. Indexing columns that are either CHAR or VARCHAR

TRADEOFF #1 Obviously, VARCHAR holds the advantage since variable-length data would produce smaller rows and, thus, smaller physical files.

TRADEOFF #2 Since CHAR fields require less string manipulation because of fixed field widths, index lookups against CHAR field are on average 20% faster than that of VARCHAR fields. This is not any conjecture on my part. The book MySQL Database Design and Tuning performed something marvelous on a MyISAM table to prove this. The example in the book did something like the following:

ALTER TABLE tblname ROW_FORMAT=FIXED;

This directive forces are VARCHARs to behave as CHARs. I did this at my previous job back in 2007 and took a 300GB table and sped up index lookups by 20%, without changing anything else. It worked as published. However, it did produce a table almost double in size, but that simply goes back to tradeoff #1.

You could analyze the data being stored to see what MySQL recommends for column definition. Just run the following against any table:

SELECT * FROM tblname PROCEDURE ANALYSE();

This will traverse the entire table and recommend column definitions for every column based on the data it contains, the minimum field values, maximum field values, and so forth. Sometimes, you just have to use common sense with planning CHAR vs VARCHAR. Here is a good example:

If you are storing IP addresses, the mask for such a column is at most 15 characters (xxx.xxx.xxx.xxx). I would jump right at CHAR(15) in a heartbeat because the lengths of IP addresses will not vary all that much and the added complexity of string manipulation controlled by an additional byte. You could still do a PROCEDURE ANALYSE() against such a column. It may even recommend VARCHAR. My money would still be on CHAR over VARCHAR in this instance.

CHAR vs VARCHAR issues can be resolved only through proper planning. With great power comes great responsibility (cliche but true)

UPDATE

When it comes to MD5 the computation of strlen internally should be eliminated when switching the entire row format. There would be no need to change the field definition.

If the MD5 key is the only VARCHAR present, I would go for it and convert the table row format to fixed. If there is a signifcant number of other VARCHAR fields present, they would benefit as well. In exchange, the table would expand to about twice its size. But queries should accelerate about 20% more without additional tuning.

share|improve this answer
    
I think I'd use a char(4) or something like an unsigned integer for an IP address –  Jack Douglas May 10 '11 at 21:28
    
@JackPDouglas You are correct on that one that point. –  RolandoMySQLDBA May 10 '11 at 21:36
    
Aren't indexes stored with a fixed length anyway? I don't get how changing the storage format to fixed length improved index lookups. Do you mean it improved table scans? –  Marcus Adams Apr 15 '12 at 22:24
add comment

It is not worth changing in my opinion. If you look through the documentation here it should illustrate the difference between the two. In your usage scenario the one doesn't really offer any significant benefit over the other unless you are really concerned about the extra bit of overhead related to row size.

http://dev.mysql.com/doc/refman/5.0/en/char.html

Also note the first comment on the documentation I link to above... "CHAR will only speed up your access if the whole record is fixed size. That is, if you use any variable size object, you might as well make all of them variable size. You gain no speed by using a CHAR in a table that also contains a VARCHAR"

share|improve this answer
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.