7

My MySQL server is running out of HD space fast. Most of my larger tables use the InnoDB engine (for no mission-critical reason). In an effort to avoid the dreaded 'drop database to recover innodb disk-space' response, I'd like to better understand how the two engines store data on the disk.

  1. If I were to use MyISAM would I be able to more-easily recover disk space by removing rows? Is there a command I would have to run in addition to the delete/truncate/empty query?
  2. Assuming #1 were true: Would it be possible/feasible to convert existing InnoDB tables to MyISAM and recover space that way?
Mike B
  • 213
  • 1
  • 3
  • 7

2 Answers2

13

MySQL use of DiskSpace is quite predictable.

The information_schema can quickly give away how much space is used by both storage engines. However, it is far better to configure InnoDB with innodb_file_per_table. That way, you can micromanage the diskspace of individual InnoDB tables. If you do not have innodb_file_per_table, the ibdata1 will grow and NEVER, EVER SHRINK.

I wrote nice articles about Cleaning Up InnoDB once and for all.

As for MyISAM, you need to periodically run one of the following:

  • OPTIMIZE TABLE myisam-tablename;
  • ALTER TABLE myisam-tablename ENGINE=MyISAM; ANALYZE TABLE myisam-tablename;

These will compress MyISAM so that there are not unused data and index pages in the MyISAM table components (.MYD and .MYI)

You can manually monitor the disk space usage with this query:

SELECT IFNULL(B.engine,'Total') "Storage Engine", CONCAT(LPAD(REPLACE(FORMAT(B.DSize/POWER(1024,pw),3),',',''),17,' '),' ',SUBSTR(' KMGTP',pw+1,1),'B') "Data Size", CONCAT(LPAD(REPLACE(FORMAT(B.ISize/POWER(1024,pw),3),',',''),17,' '),' ',SUBSTR(' KMGTP',pw+1,1),'B') "Index Size", CONCAT(LPAD(REPLACE(FORMAT(B.TSize/POWER(1024,pw),3),',',''),17,' '),' ',SUBSTR(' KMGTP',pw+1,1),'B') "Table Size" FROM (SELECT engine,SUM(data_length) DSize,SUM(index_length) ISize,SUM(data_length+index_length) TSize FROM information_schema.tables WHERE table_schema NOT IN ('mysql','information_schema','performance_schema') AND engine IS NOT NULL GROUP BY engine WITH ROLLUP) B,(SELECT 3 pw) A ORDER BY TSize;

This will tell how much space is occupied by data and index for engine storage engine. Notice at the end of the query the clause: (SELECT 3 pw). Change the number to generate the report in different units

(SELECT 0 pw) for Bytes
(SELECT 1 pw) for KiloBytes
(SELECT 2 pw) for MegaBytes
(SELECT 3 pw) for GigaBytes
(SELECT 4 pw) for TeraBytes
(SELECT 5 pw) for PetaBytes (Write me if you every get numbers this high)

UPDATE 2012-05-26 22:29 EDT

When it comes to InnoDB, if you use innodb_file_per_table, you may find that there is a difference between the file size of the .ibd file and the sum of data_length + index_length.

For an InnoDB table mydb.mytable, here is the comparison you should make:

  • Get the size of file by running ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print %5}'
  • Get the size of the table from the information schemna's point of view: SELECT data_length+index_length FROM information_schema.tables WHERE table_schema='mydb' AND table_name='mytable';
  • If the filesize > (data_length+index_length) * 1.1, then you should drag the table like this: ALTER TABLE mydb.mytable ENGINE=InnoDB;

This will make a temp table, copy only real data pages and index pages into the temp table, delete the original, and rename the temp table back to mydb.mytable. Instant table compression with one command. Please plan all table compressions during off hours.

RolandoMySQLDBA
  • 16,364
  • 3
  • 47
  • 80
  • @RolandoMySQLDBA. I've found that the data size, index size and free space columns don't always match the size of the table's `.idb` file. I've found the sum of these columns is almost always smaller than the the actual `.idb` file -- up to 33% smaller. Is there another column that I'm missing? Looking at your query above I see that you're only using data size and index size. – John Rocha May 28 '12 at 00:39
  • If data_length+index_length is significantly less than the actual `.ibd` file, this makes the `.ibd` file the perfect candidate for defragmentation. I add that to my answer. – RolandoMySQLDBA May 28 '12 at 02:30
  • I just updated my answer !!! – RolandoMySQLDBA May 28 '12 at 02:30
  • I ran both OPTIMIZE and ANALYZE on a 849mb table and it jumped to 894mb after OPTIMIZE.. seems like this didn't work at all and made it worse – NaturalBornCamper Mar 07 '17 at 09:58
3

MyISAM allocates to disk reflecting the actual space utilized. If you are not using foreign keys, transactions, or any other feature unique to InnoDB, you could convert to MyISAM easily. InnoDB is quicker for writing and MyISAM is quicker for reading. Ultimately, I would recommend researching the differences between the engines in detail before arbitrarily changing storage engines.

Here is a procedure I have used for freeing up InnoDB tablespace in the past:

Deleting huge chunks of data from mysql innodb

Warner
  • 23,440
  • 2
  • 57
  • 69