InnoDB stores data (and indexes) in 16KB blocks.
It sounds like you are shrinking each row by an average of 7% (300/4K).
If the shrinkage had been more than 50%, then probably InnoDB would have noticed adjacent half-full blocks and coalesced them, thereby freeing up some of the predicted savings. (A block is 16KB.) I say only "some" because it is not aggressive at packing the blocks after
If you had not done the
OPTIMIZE, future inserts/deletes/updates, if they were scattered around the table, would have filled in the 'holes' and/or led to blocking coalescing. If, on the other hand, the main activity is to add new rows at the 'end' of the
PRIMARY KEY values, then this subsequent cleanup would not happen, and the
OPTIMIZE would be desirable.
How much did the
OPTIMIZE benefit you? Performance probably changed very little. Sure, you freed up some space, but, if you are not running out of disk space, that does not matter much.
Another issue... Tablespaces. The old default was to put all tables into a single tablespace (the file named
ibdata1). It would grow but never shrink. Any freed blocks would be available for future database work, but would not be given back to the OS.
The new default (
innodb_file_per_table) has the same problem. However, an explicit
OPTIMIZE rebuilds the table, and does give the freed space back to the OS. Caveat: During the process, you need 2x the disk space. So, if you were very tight on space,
OPTIMIZE would fail. However...
OPTIMIZE TABLE (for InnoDB) is "Performed in-place as of MySQL 5.6.17. In-place operation is not supported for tables with FULLTEXT indexes. The operation uses the INPLACE algorithm, but ALGORITHM and LOCK syntax is not permitted. " -- https://dev.mysql.com/doc/refman/5.6/en/innodb-online-ddl-operations.html