Mysql High UPDATE SELECT导致滞后

时间:2011-11-26 21:33:59

标签: mysql sql

我有一个相当大的游戏,白天最多点30-40-50人。我们将关于他们的坦克的信息存储到一个mysql数据库中,当他们射击或失去健康时,我们将其转储到数据库。由于这个原因,我们看到了非常高的处理器和HDD Spike,结果是在游戏中滞后。

违规言论:

UPDATE MapData
SET Health = @1, X = @2, Y = @3,TotalPoints = @4
   , RankPoints = @5
WHERE MapID = @6
   AND TankID = @7
   AND Color = @8

我想知道是否有一些我可以做的事情来帮助解决滞后问题。

CREATE TABLE `mapdata` (
  `MapID` int(11) NOT NULL,
  `TankID` int(11) NOT NULL,
  `Color` tinyint(4) NOT NULL,
  `X` int(11) DEFAULT ''-1'',
  `Y` int(11) DEFAULT ''-1'',
  `Rank` tinyint(4) NOT NULL DEFAULT ''0'',
  `Health` int(11) NOT NULL DEFAULT ''1000'',
  `Armors` tinyint(4) NOT NULL DEFAULT ''0'',
  `Duals` tinyint(4) NOT NULL DEFAULT ''0'',
  `Missiles` tinyint(4) NOT NULL DEFAULT ''0'',
  `Homings` tinyint(4) NOT NULL DEFAULT ''0'',
  `Radars` tinyint(4) NOT NULL DEFAULT ''0'',
  `Beacons` tinyint(4) NOT NULL DEFAULT ''0'',
  `HasRankKill` bit(1) NOT NULL DEFAULT b''0'',
  `TotalPP` bigint(20) NOT NULL DEFAULT ''0'',
  `RankPP` bigint(20) NOT NULL DEFAULT ''0'',
  `KillCount` int(11) NOT NULL DEFAULT ''0'',
  `DeathCount` int(11) NOT NULL DEFAULT ''0'',
  `TimePlayed` time NOT NULL DEFAULT ''00:00:00'',
  `EnabledEquipment` tinyint(4) NOT NULL DEFAULT ''0'',
  `Prestige` tinyint(4) NOT NULL DEFAULT ''0'',
  PRIMARY KEY (`MapID`,`TankID`,`Color`),
  KEY `MapID` (`MapID`),
  KEY `TankID` (`TankID`),
  KEY `idx_mapdata` (`MapID`,`Color`,`TankID`),
  CONSTRAINT `mapdata_ibfk_1` FOREIGN KEY (`MapID`) REFERENCES `maps` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `mapdata_ibfk_2` FOREIGN KEY (`TankID`) REFERENCES `tank` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1

有没有我可以将表持久保存在内存中而不是hdd中,并将它经常转储回磁盘?

3 个答案:

答案 0 :(得分:2)

有些事情你可以做,但你已经达到了一个难以通过的门槛。你有一个写重系统而且编写速度不够快的那个。

有一些提高性能的方法

  1. 计算innodb_log_file_size
  2. 的神值
  3. innodb_flush_log_at_trx_commit设置为0或2.请注意,1(默认值)是唯一符合ACID的值,但将其更改为0或2会提供更好的性能。
  4. 当然还有更多方法,但这两个方面很重要。

答案 1 :(得分:2)

要检查的一件事是您的配置是否针对InnoDB进行了优化。默认的MySQL设置通常(取决于确切的版本,但仍然)未针对InnoDB进行优化,但更适合MyISAM引擎。

Percona的网站有一个很好的介绍: Innodb Performance Optimization Basics

该名单上的第5号(设置innodb_flush_log_at_trx_commit=2)正是安德烈亚斯提出的。还有更多选择需要检查。


关于您的问题,您可以使用 Memory engine 。当您的应用程序启动时,它会将表从磁盘复制到相同的内存表,然后将其用于所有操作,从而逐步更新磁盘表。或者它只能加载每次所需的数据(在游戏玩家的数据中激活)


或者,您可以在应用程序中添加一些(延迟)机制,该机制不会将每个更新作为单独的事务发送,而是分批发送。


您可以考虑的另一件事是对表进行垂直分区。如果您有一些很少更新的列和一些经常更新的列,您可以将表拆分为两部分。然后,更新将在宽度较小的表中完成。


你有4个索引但有些是多余的:

  PRIMARY KEY (`MapID`,`TankID`,`Color`),
  KEY `MapID` (`MapID`),
  KEY `TankID` (`TankID`),
  KEY `idx_mapdata` (`MapID`,`Color`,`TankID`),

根本不需要KEY MapID (MapID),因为可以使用主键的第一部分。

KEY idx_mapdata可以缩减为(MapID, Color)

答案 2 :(得分:1)

如果您希望扩展比现在更多,那么您显然需要研究可以促进这一点的软件更改,但是如果您希望快速提升性能,几乎不需要开发费用如果您还没有使用固态驱动器,那么您可以考虑切换到固态驱动器。

您是否考虑过读取/写入ram内存而不是活动播放器的数据库,然后只是在内存不再有效时将内存持久保存到数据库中?这需要一些开发时间,但肯定会解决你的问题。