MyISAM Table Formats

MyISAM supports 3 different table types. Two of them are chosen automatically depending on the type of columns you are using. The third, compressed tables, can only be created with the myisampack tool.

When you CREATE or ALTER a table that doesn't have BLOB values, you can force the table format to DYNAMIC or FIXED with the ROW_FORMAT=# table option. In the future you will be able to compress/decompress tables by specifying ROW_FORMAT=compressed | default to ALTER TABLE. See CREATE TABLE.

Static (Fixed-length) Table Characteristics

This is the default format. It's used when the table contains no VARCHAR, BLOB, or TEXT columns.

This format is the simplest and most secure format. It is also the fastest of the on-disk formats. The speed comes from the easy way data can be found on disk. When looking up something with an index and static format it is very simple. Just multiply the row number by the row length.

Also, when scanning a table it is very easy to read a constant number of records with each disk read.

The security is evidenced if your computer crashes when writing to a fixed-size MyISAM file, in which case myisamchk can easily figure out where each row starts and ends. So it can usually reclaim all records except the partially written one. Note that in MySQL all indexes can always be reconstructed:

  • All CHAR, NUMERIC, and DECIMAL columns are space-padded to the column width.

  • Very quick.

  • Easy to cache.

  • Easy to reconstruct after a crash, because records are located in fixed positions.

  • Doesn't have to be reorganized (with myisamchk) unless a huge number of records are deleted and you want to return free disk space to the operating system.

  • Usually requires more disk space than dynamic tables.

Dynamic Table Characteristics

This format is used if the table contains any VARCHAR, BLOB, or TEXT columns or if the table was created with ROW_FORMAT=dynamic.

This format is a little more complex because each row has to have a header that says how long it is. One record can also end up at more than one location when it is made longer at an update.

You can use OPTIMIZE table or myisamchk to defragment a table. If you have static data that you access/change a lot in the same table as some VARCHAR or BLOB columns, it might be a good idea to move the dynamic columns to other tables just to avoid fragmentation:

  • All string columns are dynamic (except those with a length less than 4).

  • Each record is preceded by a bitmap indicating which columns are empty ('') for string columns, or zero for numeric columns. (This isn't the same as columns containing NULL values.) If a string column has a length of zero after removal of trailing spaces, or a numeric column has a value of zero, it is marked in the bit map and not saved to disk. Non-empty strings are saved as a length byte plus the string contents.

  • Usually takes much less disk space than fixed-length tables.

  • Each record uses only as much space as is required. If a record becomes larger, it is split into as many pieces as are required. This results in record fragmentation.

  • If you update a row with information that extends the row length, the row will be fragmented. In this case, you may have to run myisamchk -r from time to time to get better performance. Use myisamchk -ei tbl_name for some statistics.

  • Not as easy to reconstruct after a crash, because a record may be fragmented into many pieces and a link (fragment) may be missing.

  • The expected row length for dynamic sized records is:

      3
      + (number of columns + 7) / 8
      + (number of char columns)
      + packed size of numeric columns
      + length of strings
      + (number of NULL columns + 7) / 8
      

    There is a penalty of 6 bytes for each link. A dynamic record is linked whenever an update causes an enlargement of the record. Each new link will be at least 20 bytes, so the next enlargement will probably go in the same link. If not, there will be another link. You may check how many links there are with myisamchk -ed. All links may be removed with myisamchk -r.

Compressed Table Characteristics

This is a read-only type that is generated with the optional myisampack tool (pack_isam for ISAM tables):

  • All MySQL distributions, even those that existed before MySQL went GPL, can read tables that were compressed with myisampack.

  • Compressed tables take very little disk space. This minimises disk usage, which is very nice when using slow disks (like CD-ROMs).

  • Each record is compressed separately (very little access overhead). The header for a record is fixed (1-3 bytes) depending on the biggest record in the table. Each column is compressed differently. Some of the compression types are:

    • There is usually a different Huffman table for each column.

    • Suffix space compression.

    • Prefix space compression.

    • Numbers with value 0 are stored using 1 bit.

    • If values in an integer column have a small range, the column is stored using the smallest possible type. For example, a BIGINT column (8 bytes) may be stored as a TINYINT column (1 byte) if all values are in the range 0 to 255.

    • If a column has only a small set of possible values, the column type is converted to ENUM.

    • A column may use a combination of the above compressions.

  • Can handle fixed- or dynamic-length records.

  • Can be uncompressed with myisamchk.