大型只写表上的 MySQL 性能

标签 mysql sql database amazon-aurora

预先感谢您的回答,抱歉我的英语不好,我不是母语人士。

我们实际上是在开发一款带有后端的手机游戏。在这个手机游戏中,我们有一个货币系统,我们会跟踪每笔交易以进行验证。

为了读取用户余额,我们有一个中间表,其中用户余额在每次交易时都会更新,因此用户永远不会直接读取交易表,以减少高流量时的负载。

后台不时读取交易表。

这是事务表的架构:

create table money_money_transaction (
  `id`              BIGINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
  `userID`          INT UNSIGNED NOT NULL,
  `amount`          INT NOT NULL,
  `transactionType` TINYINT NOT NULL,
  `created`         DATETIME NOT NULL,

  CONSTRAINT money_money_transaction_userID FOREIGN KEY (`userID`) REFERENCES `user_user` (`id`)
    ON DELETE CASCADE
);

我们计划有很多用户,事务表可能会增长到 10 亿行,所以我的问题是:

  • 会不会影响其他表的性能?
  • 如果数据库太大而无法放入 RAM,MySQL 是否进行某种优化,仅将最常读取的表存储在 RAM 中?
  • MySQL 是否能够正确扩展到这十亿行?知道我们主要是插入并且唯一的索引在 id 上(详细信息需要 id)并且没有“批量插入”(不会有 1M 插入要在此表上并发执行)
  • 此外,我们在 RDS 服务器上,因此我们可以切换到 Aurora 并在需要时尝试主-主或主-从复制。您认为这对这种情况有帮助吗?

最佳答案

您可能会考虑 MyRocks(请参阅 http://myrocks.io),这是一个第三方存储引擎,专为快速插入速度和压缩数据存储而设计。我不会建议您应该切换到 MyRocks,因为我没有足够的信息来针对您的工作量做出关于它的明确声明。但我会建议您花时间对其进行评估,看看它是否更适合您的应用程序。

If the database is too large to fit in RAM, does MySQL have some sort of optimisation, storing in RAM only the most read table ?

是的,MySQL(假设是 InnoDB 存储引擎)将部分表存储在缓冲池中的 RAM 中。它将表分解为页面,并在查询请求时将页面放入缓冲池。这就像一个缓存。随着时间的推移,请求最多的页面会保留在缓冲池中,其他页面会被逐出。因此,它或多或少地平衡了尽快为您的大部分查询提供服务。阅读https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool.html获取更多信息。

Will it affect the performance of other tables ?

表没有性能 — 查询有性能。

缓冲池有固定的大小。假设您有六个表需要共享它,它们的页面必须适契约(Contract)一个缓冲池。无法为每个表设置优先级,或为某些表专用缓冲池空间或将它们“锁定”在 RAM 中。所有表的所有页共享同一个缓冲池。因此,当您的查询请求来自不同表的页面时,它们确实会相互影响,因为来自一个表的频繁请求的页面可能会从另一个表中逐出页面。

Does MySQL will be able to scale correctly up to this billion row ?

MySQL 有很多特性可以帮助提高性能和可伸缩性(它们不是一回事)。同样,查询具有性能,而不是表。没有查询的表就放在那里。它是通过不同技术优化的查询。

Knowing we do mostly insert and that the only index is on the id (the id is needed for details) and that there is no "bulk insert" (there will not be 1M insert to do concurrently on this table)

索引确实会增加插入的开销。主键索引是不能去掉的,它是每张表的必要组成部分。但是例如,您可能会发现删除包含索引的 FOREIGN KEY 是值得的。

通常,大多数表的读取次数多于写入次数,因此值得保留一个索引来帮助读取(甚至是使用 WHERE 子句的 UPDATE 或 DELETE)。但是,如果您的工作负载几乎都是 INSERT,那么外键的额外索引可能纯粹是开销,对任何查询都没有任何好处。

Also, we're on a RDS server, so we could switch to Aurora and try a master-master or master-slave replication if needed. Do you think it would help in this case ?

我在 2017 年初研究了 Aurora 的基准测试,发现对于我们测试的应用程序,它不适合高写入流量。您应该始终针对您的应用程序对其进行测试,而不是依赖于互联网上某人的猜测。但我预测目前形式的 Aurora(大约 2017 年)将完全不适合您的全写工作负载。

关于大型只写表上的 MySQL 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48036966/

相关文章:

database - 无法在 VB.NET 中使用 "INSERT INTO table VALUES() ON DUPLICATE KEY UPDATE"

php - 包含 AS 的 SQL SELECT 语句

mysql - MySql 中 case 条件的内连接表

sql - 子选择的问题

mysql - Clojure HoneySQL - 如何将连接后的字符串值聚合到单行中?

mysql - 优化sql查询-wordpress-sql_big_selects

sql - GROUP BY 本身就意味着 DISTINCT 吗?

java - 将数据库表映射到 Java 类 - 依赖关系

mysql - 如何设计可扩展的数据库?

python - 错误 1064 (4200) - 当我在 MySQL 中输入 GRANT ALL 请求时