2

考虑下表:

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;
  • 用户将按SELECTUID 处理所有事件,每天总共大约 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。DELETE我们尝试了如上所述的每日批量(声明#1),如果不阻塞表,它就不再起作用了。目前我们每 30 秒删除一次(声明 #2),但这会阻塞 10 秒。

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

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

4

2 回答 2

0

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

每天多次运行您的 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

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

于 2013-10-05T17:48:45.117 回答
0

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

于 2013-10-05T17:39:07.853 回答