一个相对有效的方法是使用database partitions并通过删除分区来删除旧数据。它当然需要更复杂的维护,但它确实有效。
首先,启用innodb_file_per_table,以便每个表(和分区)转到它自己的文件而不是一个巨大的ibdata文件。
然后,创建一个分区表,每个时间段(日,月,周,你选择它)有一个分区,这会导致您的数据集有一些合理大小的文件。
create table foo(
tid INT(7) UNSIGNED NOT NULL,
yearmonth INT(6) UNSIGNED NOT NULL,
data varbinary(255) NOT NULL,
PRIMARY KEY (tid, yearmonth)
) engine=InnoDB
PARTITION BY RANGE(yearmonth) (
PARTITION p201304 VALUES LESS THAN (201304),
PARTITION p201305 VALUES LESS THAN (201305),
PARTITION p201306 VALUES LESS THAN (201306)
);
查看数据库数据目录,您会发现每个分区的文件。在此示例中,分区'p201304'将包含所有具有yearmonth的行< 201304,'p201305'将具有2013-04的行,'p201306'将包含2013-05的所有行。
在实践中,我实际上使用了一个包含UNIX时间戳的整数列作为分区键 - 这样,随着时间的推移,更容易调整分区的大小。分区边缘不需要与任何日历边界相匹配,它们可以每隔100000秒发生一次,或者任何可以产生合理数量的分区(数十个分区)的数据,同时仍然具有足够小的数据文件。
然后,建立一个维护过程,为新数据创建新分区:ALTER TABLE foo ADD PARTITION (PARTITION p201307 VALUES LESS THAN (201307))
并删除旧分区:ALTER TABLE foo DROP PARTITION p201304
。删除大分区几乎和删除文件一样快,它实际上会释放磁盘空间。另外,它不会通过在其中分散空的空间来分割其他分区。
如果可能的话,通过在WHERE子句中指定分区键(上例中的yearmonth)或其范围,确保您的频繁查询只访问一个或几个分区 - 这将使它们运行很多因为数据库不需要查看所有分区以查找数据,所以速度更快。
可能重复的[MySQL数据文件不会缩小](http://stackoverflow.com/questions/2646373/mysql-data-file-wont-shrink) –