MySQL 分区:按 ID 选择,但按日期删除

Posted

技术标签:

【中文标题】MySQL 分区:按 ID 选择,但按日期删除【英文标题】:MySQL Partitioning: SELECT by ID, but DELETE by date 【发布时间】:2013-10-05 16:27:04 【问题描述】:

考虑下表:

CREATE TABLE `event` (
  `uid` bigint(13) NOT NULL,
  `time` bigint(14) NOT NULL,
  `type` smallint(5) NOT NULL,
  `msg` varchar(2048) DEFAULT NULL,
  KEY `uid` (`uid`),
  KEY `time` (`time`),
  KEY `time_type_uid` (`time`,`type`,`uid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

我基本上是做什么的:

INSERT 每天约 100 万行,当前大小约为 1 亿条条目 DELETE 超过 100 天的所有行: 声明 #1:DELETE FROM event WHERE time < unix_timestamp()-100*86400; 声明 #2:DELETE FROM event WHERE time < unix_timestamp()-100*86400 LIMIT 1000; 用户将SELECT所有事件按UID,每天总共约500个查询,所以不是那么多: 声明 #1:SELECT * FROM event WHERE uid=4711 AND type IN (23,1002,12,1); 声明 #2:SELECT * FROM event WHERE uid=4711 AND type IN (23,1002,12,1) AND time BETWEEN 1381051061 AND 1381051861;

处理这张桌子变得很慢,特别是因为DELETE 作业阻塞了桌子上的INSERTs/SELECTs。如上所述(声明#1),我们尝试了每日批量DELETE,如果不阻塞表格,它就不再起作用了。目前我们每 30 秒删除一次(声明 #2),但这会阻塞 10 秒。

我们计划增加INSERT 负载,但第一次测试导致线程挂在“系统块”状态,我猜这是由于 I/O。服务器设置按照 mysqltuner.pl 的建议进行了优化。硬件系统肯定有 I/O 问题并且是“原样”,不幸的是它不能因为几个原因而改变。我们甚至没有 root 访问权限。

分区甚至是一种解决方案吗?MyISAM 是最好的引擎吗?在改进硬件之前,我们需要优化任何东西。

【问题讨论】:

投票结束:范围太广。令人着迷的问题,但过于宽泛,无法在这里明确回答,并且可以说不是严格意义上的编程问题。我们可以告诉你如何分区,但我们不能抽象地优化。为什么不是 InnoDB?服务器设置是什么?什么是系统规格和负载?还有哪些其他查询正在运行?你多久删除一次,可以更频繁吗?您是否有适合您的查询模式的索引? (我的猜测是,不完全是。)等等。 感谢您的 cmets。我知道为一个广泛的问题提供优化提示有点困难。我认为处理这样​​的数据可能是一个普遍的问题。我添加了更多细节,希望对您有所帮助。 dba.stackexchange 可能是一个更好的地方来询问哪种优化是合适的以及如何衡量它们的有效性。 【参考方案1】:

只需使用InnoDB with snapshot isolation 即可获取可读快照。这样读者就不会被你的大删除工作所阻止。我认为您不应该针对这种相当标准的情况进行分区。分区是一个大锤子和侵入性的。也许一些简单的措施就足够了。

【讨论】:

【参考方案2】:

在你去麻烦分区之前(它执行得很好,但可能是系统管理员的毛球)尝试一些事情。

每天多次(甚至一小时多次)运行您的 DELETE 清理操作,因此它不必每次运行时都处理一百万行。

尝试运行

    DELETE FROM event
          WHERE TIME < < unix_timestamp()-100*86400
         LIMIT 10000

一遍又一遍。这将减少每个 DELETE 操作锁定您的表的时间,并将其释放给其他操作。

弄清楚您是否拥有正确的复合索引(时间、类型、uid)。您向我们展示的查询不会利用该索引,并且索引会在您插入时占用时间。看起来您可以尝试简单地删除该索引。您可能需要在 (uid,type) 上为您提到的查询建立索引。

摆脱SELECT *的使用。相反,只检索您的应用程序需要的列。当 MySQL 准确地知道您需要哪些数据项时,它可以进行令人惊讶的优化。

您能承受每天或每周的停机时间吗?如果是这样,请使用

 OPTIMIZE NO_WRITE_TO_BINLOG TABLE  event

偶尔整理一下表和索引结构。

【讨论】:

谢谢,我们已经尝试过限制删除。它可以工作,但会阻塞大约 10 秒。绝对不会同时处理更多的 INSERT。

以上是关于MySQL 分区:按 ID 选择,但按日期删除的主要内容,如果未能解决你的问题,请参考以下文章

mysql 分区指定分区表数据存储路径,可以支持跨磁盘

mysql之表分区

如何使用diskpart 命令删除分区

使用mysql和django按日期时间删除数据库中的条目?

删除表分区以避免错误 ORA-00054

MySQL分区表-按月份归类