Drupal cache_form Table Eating Disk Space? Here's a Fix.
A problem we hear about quite often is a huge cache_form table. Drupal by default caches all form data (typically for 6 hours). During peak traffic times, that can be a lot of form data being cached. When the form cache is cleared during Drupal's cron, the following DELETE query is used:
DELETE FROM cache_form WHERE (expire <> 0) AND (expire < UNIX_TIMESTAMP(NOW()));
However, InnoDB does not release disk space back to the file system on DELETE queries, and that can easily lead to a very large .ibd file for that table.
The three most common "fixes" we see being discussed are:
- mysqldump - Many people recommend exporting the table via mysqldump and then importing it again. While this does reclaim the disk space, your cache_form table will be locked during the dump and the import, and any users who filled out forms during that small time gap in between the dump and the import will have their form data lost.
- OPTIMIZE TABLE (or ALTER TABLE "Engine=InnoDB") - Another recommendation often seen is to run OPTIMIZE TABLE on the cache_form table. However, this will also negatively impact your users by locking the cache_form table during the process. The ALTER TABLE is also mentioned here because it essentially does the same thing on InnoDB.
- TRUNCATE - Probably the most common recommendation we see is to simply TRUNCATE the cache_form table. That will instantly free up all of the disk space that table is using, but it will also delete ALL cached form data.
Fortunately, Percona Toolkit contains a great tool to do online schema changes, and it even works if you are running a cluster. We have a client whose cache_form table legitimately grows to ~20GB during peak traffic times, but their site has almost no form usage outside of normal business hours. Running the following as a maintenance task just before the start of the day when there is the least amount of data that legitimately resides in cache_form typically results in a shrinkage down to less than 50MB:
pt-online-schema-change --host 127.0.0.1 --port 3306 --user bender --alter "ENGINE=InnoDB" D=database,t=cache_form --execute
This runs an ALTER TABLE, but with a few extra things going on under the hood. Instead of simply copying the table, it also creates triggers on the original table so that any new data being written to the original table are also written to the new table. When the process is done, it then atomically renames the tables and drops the original.