我的目标是在 MySQL 表中保存大约 6000 万行以进行高速读取,并正确地继续插入。
对于产品设计来说,这 6000 万行可以很自然的拆分成 3000 个块,所以我决定做一个分表策略,将一个 60M 的表拆分成 3000 个表。
我为以下测试获取了 300 万条数据:
1张表300万行:那么这300万条数据的平均插入时间为80秒,每1000次查询(每个查询从这张300万条数据表中提取1000行)大约需要10秒。
300 万行平均拆分为 3000 个表:将 300 万条数据插入 3000 个表:79 秒(不是真的更快);每 1000 次查询平均针对 3000 个表(其中每个表有 1000 行):120 秒(比上面慢 12 倍)
这是为什么?虽然我有 3000 张表,但基本上都是 MySQL 管理的文件,每次查询只打到一张只有 1000 行的表,但是为什么会那么慢呢?
我在具有以下配置的 15G RAM 的 8 核机器上运行:
open_files_limit 300000
table_open_cache 100000
经过2-3次模拟重试后,我也搜索了MySQL的“openED files”,如下所示,对于我的3000表设置似乎可以?
已打开表:9463
我怎样才能摆脱这个问题?
------------ 编辑和更多想法 ------------
我现在只是在尝试表分片的可能性,也许 MySQL Merge 引擎可以在这个方向上提供一点帮助。
另一方面,也许分区也不是一个坏主意……例如,以 MySQL 的 Range 分区为例,我可以将 Range 设置为 1000 万,然后 60M 的表变成具有 6 个分区的表……将查询和插入都更快?
----------- Trying Table Partition的更新-----------
正如下面所评论的那样,我在想可能 Table Partition 也可以是一个很好的解决方案,而不是 Table Sharding,特别是当它保持相同的表名并且对现有代码的影响最小时。
我试图在这个 6000 万张表上做 6 个分区;
1)起初,我做了一些看起来像下面的伪代码:
CREATE TABLE `datatable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` int(11) NOT NULL DEFAULT 0,
`description` varchar(255),
`datimeutc` datetime,
`datimelocal` datetime,
`value` double,
PRIMARY KEY (`id`),
KEY INDEX_TYPE ON (type)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
PARTITION BY RANGE (id) (
PARTITION p0 VALUES LESS THAN (10000000),
PARTITION p1 VALUES LESS THAN (20000000),
PARTITION p2 VALUES LESS THAN (30000000),
PARTITION p3 VALUES LESS THAN (40000000),
PARTITION p4 VALUES LESS THAN (50000000)
PARTITION p5 VALUES LESS THAN MAXVALUE
);
并且结果相当不错。导入 300 万条数据进行测试大约需要 1 分钟,导入全部 6000 万条数据总共需要 63 分钟。
每个查询的搜索时间(从基于 60-M 分区的表中获取 20000 行)大约为 90 毫秒。我没有针对单个 6000 万表的查询性能的任何比较数据,但是 90 毫秒是一个合理的值吗?
2)我尝试了“类型”字段上的分区,希望将传入的单个查询限制在单个分区上,因为 MySQL 对具有分区的唯一键有限制,伪代码如下所示:
CREATE TABLE `datatable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` int(11) NOT NULL DEFAULT 0,
`description` varchar(255),
`datimeutc` datetime,
`datimelocal` datetime,
`value` double,
KEY (`id`),
KEY INDEX_TYPE ON (type)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
PARTITION BY RANGE (type) (
PARTITION p0 VALUES LESS THAN (500),
PARTITION p1 VALUES LESS THAN (1000),
PARTITION p2 VALUES LESS THAN (1500),
PARTITION p3 VALUES LESS THAN (2000),
PARTITION p4 VALUES LESS THAN (2500)
PARTITION p5 VALUES LESS THAN MAXVALUE
);
这时候我插入60M的数据,插入时间比第一种情况要长。我还没有结果,但是到目前为止,只插入4M数据已经需要3个小时了……
这是为什么?
我在想,也许我是按顺序插入60M,即row Id从1开始到60000000。所以万一,我基本上打开并锁定第一个要插入的分区,一旦插入第一个10M,我打开第二个分区继续。
另一方面,在分区的情况2)中,我需要频繁随机打开所有6个分区(由'type'而不是'id'设计),所以表锁定和解锁花费了太多时间?这可能是原因吗?