In 2018, does it still hold true that MySQL (InnoDB) CHAR performs better VARCHAR speed-wise?

I've only found a performance comparison explanation that is 7 year old. I've checked the official MySQL 8 CHAR vs VARCHAR but the article speaks about storage only, not about performance. I've also read a notice that VARCHAR causes some problems with table fragmentation (see the very 1st comment to this answer.

  • Since the "this answer" link is tagged [sql-server], you should not assume that its answers apply to MySQL. (Mostly they do apply, but don't risk it.) – Rick James Jan 8 '19 at 6:39
  • By bad, I checked badly. Of course, I'm interested only in MySQL. Thx @RickJames – Amio.io Jan 8 '19 at 14:05
  • By memory this optimisation was true when everything was stored on disks due to the spinning issue. The aim was to have same size recorda to save some disk revolutions. – Toto Apr 10 at 21:24

I seriously doubt that it ever held true for InnoDB. Even for MyISAM (which really can have FIXED length rows) it was rarely true.

Roughly speaking, this is the order (most overhead first)

  1. Disk hit(s).
  2. Locate the record(s).
  3. Parse the record (split it into columns).
  4. Apply functions and evaluate expressions.

If the data is bigger (as in CHAR being padded), the #1 is impacted. The rest pales into insignificance.

Note: There are 4 flavors of InnoDB ROW_FORMAT.

  • For REDUNDANT, a CHAR(100) CHARACTER SET utf8mb4 always takes 400 bytes.
  • For COMPACT or DYNAMIC, it takes between 100 and 400 bytes.
  • For COMPRESSED, the padding spaces are highly compressible, but still take some space.

Allegedly, the "fixed" size of a CHAR (which, is not all that fixed), tends to prevent block splits. But I kinda doubt it.

My Rule of Thumb: CHAR should almost always be restricted to truly fixed length strings, and most of them are hex or ascii:

country_code CHAR(2) CHARACTER SET ascii
british_postal_code CHAR(6) CHARACTER SET ascii
zip5 CHAR(5) CHARACTER SET ascii
md5 CHAR(32) CHARACTER SET ascii  -- UNHEX() into BINARY(16) is tighter
base64 CHAR(?) CHARACTER SET ascii COLLATION ascii_bin  -- need case-significance

Note: latin1 works equally well as ascii, the 8.0 default of utf8mb4 does not.

(See also my answer to the first link. It starts "Most of the answers in this thread are 5 years old, written before InnoDB and utf8 were defaults. So, let me start over..")


There is insignificant difference especially considering CHAR has a maximum length of 255 (VARCHAR is 64K). With the effective equivalent limited to 255 that is a very quick comparison in the case of this field being used as join criteria.

The fragmentation is no longer an consideration as <768 bytes is stored inline. This is still strictly possible in utf8mb4, "InnoDB encodes fixed-length fields greater than or equal to 768 bytes in length as variable-length fields"1 so no difference between CHAR and VARCHAR.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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