【问题标题】:Mysql High UPDATE SELECT causing lagMysql High UPDATE SELECT导致滞后
【发布时间】:2011-11-27 06:43:06
【问题描述】:

我有一个相当大的游戏,白天最多有 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

有没有办法可以将表保存在内存中而不是硬盘上,并让它每隔一段时间转储回磁盘?

【问题讨论】:

  • EXPLAIN查询的输出是什么?

标签: mysql sql


【解决方案1】:

有些事情你可以做,但你已经达到了要通过的硬门槛之一。一个你有一个写繁重的系统,它只是写得不够快。

有一些方法可以提高性能

  1. 计算innodb_log_file_size的神值
  2. innodb_flush_log_at_trx_commit 设置为 0 或 2。请注意,1(默认值)是唯一符合 ACID 的值,但将其更改为 0 或 2 可以获得更好的性能。

当然还有更多方法,但这两个很重要。

【讨论】:

    【解决方案2】:

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

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

    该列表中的第 5 位(设置 innodb_flush_log_at_trx_commit=2)正是 Andreas 提出的。还有更多选项可供检查。


    关于您的问题,您可以使用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)

    【讨论】:

      【解决方案3】:

      如果您希望扩大比现在更多的规模,那么您显然需要研究有助于实现这一目标的软件更改,但如果您希望在几乎没有开发成本的情况下快速提高性能如果您还没有使用固态驱动器,那么您可能会考虑切换到固态驱动器。

      您是否考虑过为活跃玩家读取/写入 RAM 内存而不是数据库,然后在他们不再活跃时将该内存持久保存到数据库中?这需要一些开发时间,但肯定会解决您的问题。

      【讨论】:

      • 我们实际上有一个内存缓存系统,但两者都有其负面和正面。我总是可以恢复到那个系统,但我希望 mysql 可以处理它。我已经做了一些调整,它似乎运行顺利!
      • 实际上,如果您有一个有很多玩家的实时游戏服务器,我想添加一些类似于最吸引人的场景。将(游戏状态的)每个更改都存储在数据库中没有多大意义,除非在系统崩溃的情况下您必须 100% 安全。在极端情况下,您甚至可以将您的(游戏)应用程序服务器存储在数据库中,仅在游戏开始和结束时(以及“暂停”状态,如果这是一个选项,以便游戏可以稍后继续)。跨度>
      猜你喜欢
      • 2014-05-14
      • 2015-12-03
      • 2019-09-20
      • 1970-01-01
      • 1970-01-01
      • 2011-06-28
      • 2017-10-08
      • 2016-09-08
      • 1970-01-01
      相关资源
      最近更新 更多