我正在使用 MySQL 临时存储十亿或更多结果的结果,其中结果是由并行执行的进程计算的。每个结果都是使用函数 [f] 对分别由 [o1] 和 [o2] 标识的对象的表示 [r1] 和 [r2] 计算的。目前,我使用三个表来执行此过程: (1) 将对象标识符映射到其表示的表:
mysql> describe v2_3282_fp;
+----------------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------+------+-----+---------+-------+
| objid | text | YES | | NULL | |
| representation | text | YES | | NULL | |
+----------------+------+------+-----+---------+-------+
(2) 保存每个计算进程应检索并计算的作业的表:
mysql> describe v2_3282_job;
+----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------------------+------+-----+---------+----------------+
| jobid | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| workerid | int(11) | YES | | NULL | |
| pairid1 | text | YES | | NULL | |
| pairid2 | text | YES | | NULL | |
+----------+---------------------+------+-----+---------+----------------+
(3) 保存计算作业结果的表:
mysql> describe v2_3282_res;
+-----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+----------------+
| resultid | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| pairid1 | text | YES | | NULL | |
| pairid2 | text | YES | | NULL | |
| pairscore | double(36,18) | YES | | NULL | |
+-----------+---------------------+------+-----+---------+----------------+
(pairscore 类型是在执行期间动态确定的,而不是固定为 (36,18) 。)
注册表示后,一个进程会不断扫描结果表以查找新结果以传输到内存中存在的对象,其余进程检索作业以进行计算,直到它们收到带有一对标识符的作业,表示计算结束。
在进行 1,000,000 次左右计算的单元测试期间,该系统运行良好。然而,随着使用该系统的需求增长到 1,000,000,000+,我看到系统最终陷入内存和磁盘之间来回交换的困境。当我检查正在使用的系统内存和交换空间时,使用的系统内存已完全使用,但通常不到 20% 的交换空间被使用。
我已经读到,当整个表都可以读入内存时,MySQL 的性能是最好的,而磁盘 I/O 是主要的瓶颈。这似乎对我来说也是如此,因为在我的具有 12 GB 和 16 GB RAM 的系统上运行计算最终需要越来越多的工作进程周期之间的时间,尽管我只有 64 GB 的系统似乎从未遇到过这个问题。
虽然直截了当的回答是“嘿,伙计,买更多的 RAM。”,但我认为有一个更基本的设计问题导致我的系统随着需求的增长而降级。我知道 MySQL 是一个广泛使用的精心设计的产品,数据库和表的设计考虑会极大地影响性能。
因此,在不求助于购买更多内存的蛮力解决方案的情况下,我正在寻找有关如何改进我提出的 MySQL 表设计工程的建议。虽然我了解 MySQL 表规范化的基础知识并且可以创建查询来实现我的需求,但我对每种类型的数据库引擎、索引的详细信息以及其他特定于数据库的设计注意事项知之甚少。
我的问题是:(1)如果我将结果表和作业表拆分为较小的表而不是单个大表,性能会有所不同吗?(我认为不是。)(2)我目前以编程方式发出一个限制子句,以在每个检索周期中检索固定数量的结果。但是,我不知道这是否可以通过简单的“SELECT ... FROM [result table] LIMIT start, size”进一步优化。(我想是的。) (3)告诉工作进程在周期之间休眠以让 MySQL “赶上”是否有意义?(我想不是。)
我提前感谢那些在数据库和表设计方面经验丰富的人提供的任何建议。