【问题标题】:MySQL multiple updates on the same table time outMySQL对同一张表的多次更新超时
【发布时间】:2012-04-18 04:42:55
【问题描述】:

我正在运行一个用 Java 编写的带有 MySQL 数据库的 MMORPG 服务器。几个月来它运行得很好,但是随着我们变得越来越流行并且数据库变得越来越大,我们开始遇到问题。查询都在处理数据包的同一线程中运行(是的,它的设计非常糟糕),这导致了严重的延迟——我们通过实现一个定期保存 10 分钟未保存的字符的 save-worker 来伪造这一点在 5 个线程中。此外,还有五个其他线程处理需要在游戏过程中即时处理的数据库查询。

我们的问题是访问包含字符一般信息的表的更新由于某种原因需要很长时间然后超时。

进程列表:http://i.imgur.com/Fr0kD.png

characters 更新包含大约 30 个以上字段,并以 WHERE id = ? 结尾。

出现在进程列表中的表格布局:

TABLE `characters` ( -- Contains about 300.000 rows
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `accountid` int(10) unsigned NOT NULL DEFAULT '0',
  `world` int(11) NOT NULL DEFAULT '0',
  `name` varchar(13) NOT NULL DEFAULT '',
  `level` int(11) NOT NULL DEFAULT '0',
  `exp` int(11) NOT NULL DEFAULT '0',
  `str` int(11) NOT NULL DEFAULT '0',
  `dex` int(11) NOT NULL DEFAULT '0',
  `luk` int(11) NOT NULL DEFAULT '0',
  `int` int(11) NOT NULL DEFAULT '0',
...
  `job` int(11) NOT NULL DEFAULT '0',
...
  PRIMARY KEY (`id`),
  KEY `accountid` (`accountid`),
  KEY `ranking1` (`level`,`exp`),
  KEY `ranking2` (`job`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

TABLE `items` ( -- contains 34 million rows
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `type` tinyint(3) unsigned NOT NULL,
  `inventoryType` tinyint(4) NOT NULL,
  `characterId` int(10) unsigned DEFAULT NULL,
  `accountId` int(10) unsigned DEFAULT NULL,
  `itemId` int(10) unsigned NOT NULL,
...
  PRIMARY KEY (`id`),
  KEY `FK_items_1` (`characterId`),
  KEY `FK_items_2` (`accountId`),
  CONSTRAINT `FK_items_1` FOREIGN KEY (`characterId`) REFERENCES `characters` (`id`) ON DELETE CASCADE,
  CONSTRAINT `FK_items_2` FOREIGN KEY (`accountId`) REFERENCES `accounts` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

TABLE `wishlists` ( -- contains ~75.000 rows
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `characterId` int(10) unsigned NOT NULL,
  `serialNumber` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_wishlists_1` (`characterId`),
  CONSTRAINT `FK_wishlists_1` FOREIGN KEY (`characterId`) REFERENCES `characters` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

它是运行 WS2008 R2、MySQL 5.5.22 和 Java 7 的专用服务器。Java 通过 JDBC(MySQL 连接器 5.1.18)连接到数据库,并且这些查询的 autoCommit 设置为 false,isloation 为 TRANSACTION_READ_UNCOMMITTED。服务器有 32 GB RAM,其中 24 个用于 Java,其余用于 MySQL。 一些设置:

innodb_buffer_pool_size=8G
innodb_log_file_size=1024M
innodb_thread_concurrency=10

这种行为的原因可能是什么?

【问题讨论】:

    标签: java mysql timeout


    【解决方案1】:

    您在访问表时是否正确使用了锁?我不知道你的访问设置,但听起来你可能会遇到读/写饥饿。

    【讨论】:

    • 不,我们没有在任何地方使用锁。你能解释一下我们将如何添加它们吗?保存字符的方法首先更新characters表,然后更新所有其他表(根据数据库负载需要一些时间),最后提交数据。