【问题标题】:MySQL Partitioning in a real-world exampleMySQL 分区的真实示例
【发布时间】:2016-04-11 12:03:06
【问题描述】:

我想在一个足球奇幻游戏中尝试 MySQL Partitioning,用户分布在联赛中,每个联赛都有一个用户可以出售或购买球员的市场。当很多用户同时玩时,我在这张表中遇到了一些僵局(撰写本文时大约有 50K 联赛,每个联赛有大约 20 名玩家在市场上每两天刷新一次),所以我在想关于使用 MySQL Partitioning,我之前没用过。

这是我要分区的表:

CREATE TABLE `market` (
  `leagueID` int(10) unsigned NOT NULL,
  `playerID` smallint(5) unsigned NOT NULL,
  `userID` int(10) unsigned DEFAULT,
  `price` int(10) unsigned NOT NULL ,
  `date` int(10) unsigned NOT NULL,
  UNIQUE KEY `league_player` (`leagueID`,`playerID`),
  KEY `user_date` (`userID`,`date`)
);

您推荐哪种方法(列、范围、分区数等)?

这是我最初的方法:

ALTER TABLE market
    PARTITION BY HASH(leagueID)
    PARTITIONS 10;

【问题讨论】:

标签: mysql google-app-engine partitioning database-partitioning


【解决方案1】:

为什么要分区?

我问是因为大多数分区尝试都没有收获。没有性能提升;有时性能下降。特别是 BY HASH 很少有帮助。

您在使用 MyISAM 吗?如果是这样切换到 InnoDB。既然你提到了“死锁”,也许你已经在使用 InnoDB 了?分区对事务死锁没有帮助;我们需要查看两个事务中的查询。解决方案可能就像对IN 列表进行排序一样简单。

但是...无论我们是否“解决”了您今天遇到的死锁,您都需要检查错误并重播已中止的整个事务。这是“解决”死锁的唯一可靠方法。

Datacharmer 的幻灯片为您提供血淋淋的细节; my blog 列出了 PARTITIONing 有用的极少数情况,从而使他的大部分幻灯片无用。

其他问题...

  • 我没有看到PRIMARY KEY。建议您将UNIQUE 密钥更改为PRIMARY KEY。 InnoDB 确实需要 PK。
  • 有一个DATE 数据类型;使用起来可能比一些INT 不那么笨拙。

【讨论】:

  • 当两个事务(我正在使用 InnoDB)试图在市场中插入一个新玩家时,就会产生死锁,两个事务都试图锁定 UNIQUE 键,因此其中一个失败了。我正在使用 Google App Engine 任务队列,因此重试整个事务直到成功。使用分区,UNIQUE 索引被拆分到多个表中,因此同时被锁定的机会要低得多。
  • 如果是 same 键,那么它将锁定 same 分区中的 same 行。没有好处。
  • 有了分区,每个事务只将key锁在对应联赛的对应分区中(我说的是两个事务试图在不同的联赛中插入新玩家)
  • 死锁是真的吗?还是想象的?您必须每天从多个客户端添加 100 万玩家才能碰巧遇到死锁。我怀疑你是否有那么多球员。拥有良好的索引并使查询保持快速和简单——这最大限度地减少冲突的机会,其中一些是死锁。
  • 同一时间每个联赛每天更新一次市场:一个任务队列限制为同时执行 500 个联赛
【解决方案2】:

我现在已经多次看到类似的情况,但我不相信分区会解决您的问题。

您在唯一索引上看到的死锁可能是由于两个非冲突插入使用锁定所在的同一数据库页面。由于索引的 B 树结构,如果单个联盟在特定时间窗口中写入大量(似乎是合理的),则该页面上的互斥体被命中的可能性更高。

我会考虑通过更改唯一约束中两个字段的顺序并将现有索引添加为常规索引(出于查找原因)来物理分布索引“热点”。

ALTER TABLE `market` 
ADD UNIQUE KEY player_league (`playerID`,`leagueID`),
DROP UNIQUE KEY `league_player`,
ADD KEY league_player (`leagueID`,`playerID`);

请注意,由于您还没有主键 (but InnoDB is gonna create one behind the scenes anyway),因此新键承担该角色在逻辑上是有意义的。

ALTER TABLE `market` 
ADD PRIMARY KEY (`playerID`,`leagueID`),
DROP UNIQUE KEY `league_player`,
ADD KEY league_player (`leagueID`,`playerID`);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-22
    • 2016-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-30
    • 2017-01-15
    • 1970-01-01
    相关资源
    最近更新 更多