我们有一张10 TB,50亿行的表。
create table dummy_table (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
type INT, -- ENUM type, only few fixed values
create_date DATE,
user VARCHAR(10),
A VARCHAR(10),
B VARCHAR(10),
C VARCHAR(10),
D VARCHAR(10)
)
数据是不可变的(不需要更新操作。仅批量插入(即每天数据加载)和批量删除(即每月数据清理))。
我们的主要用例是按用户搜索,然后键入,然后输入creation_date。为此,我正在分析两种策略
create index user_type_creation_date_idx on dummy_table(user, type, create_date)
alter table dummy_table PARTITION BY LIST(type)
SUBPARTITION BY HASH(YEAR(create_date) + MONTH(create_date)) (
PARTITION pA VALUES IN (0) (
SUBPARTITION s0,
SUBPARTITION s1,
.....)
create index user_idx on dummy_table(user)
SELECT操作的执行时间几乎相同。我面临的问题是批量插入。我们正在尝试从其中的s3文件中抽取3000万行(4.2 GB)。
没有索引和分区,加载这么多的数据大约需要360秒。但是,使用 STRATEGY2 时,数据加载时间增加到850秒,而使用 STRATEGY1 时,数据加载时间仍从过去的15000秒开始,并且仍在继续。
删除索引不在范围内,因为创建一个索引需要花费7多个小时,而且我们计划再增加四个复合索引
- index on user, A
- index on user, B
- index on user, C
- index on user, D
这是我的问题:
版本: MySQL:5.6
答案 0 :(得分:1)
计划A:包括索引,不进行分区,并按user + type + create_date对输入的数据进行预排序。这将是最快的。但是需要空间来对CSV文件进行预排序。
计划B:无索引,无分区,仅加载数据,然后ADD INDEX
。这需要大量的磁盘空间来进行排序。该计划可能接近计划A。
计划C:如果您不需要id
并且(用户+类型+创建日期)是唯一的,则删除id
并执行计划A。现在这是最好的方法。
问题:
user
作为PK中的 first 项。每个user
有多少行? (听起来像几百万?)PARTITION BY RANGE(TO_DAYS(...))
以及每月分区。这是因为DROP PARTITION
比DELETE
快得多。有关更多详细信息,请参见this。因此,现在我建议使用A或C,再加上每月分区。id
,那么为了受益于普通SELECT
(并且由于数据量巨大),做
PRIMARY KEY(user, type, create_date, id), -- clustered, unique, etc
INDEX(id) -- sufficient to keep AUTO_INCREMENT happy
数学使我感到困惑:5B行(每个行约100个字节)大约为1TB(扣除InnoDB开销之后),但是您说的是10TB。
我假设使用InnoDB;如果您使用的是其他引擎,则可能需要修改答案。
进一步思考“开箱即用” ...
对于InnoDB和并行加载,您应该能够对“可移动表空间”执行以下操作。但是直到5.7.4才可用于分区。
这将涉及一堆单独的加载,每个加载都加载到单独的表中。完成后,使用“可移动表空间”将它们作为分区移入主表。