mysql - Mysql表批量导入数据,不删除索引

标签 mysql innodb

我们有一个表,大小为 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)
)

数据是不可变的(不需要更新操作。只需批量插入(即每日数据加载)和批量删除(即每月数据清理))。

我们的主要用例是按用户搜索,然后键入创建日期。为此,我正在分析两种策略

  1. 策略1:通过综合索引:

在 dummy_table(user, type, create_date) 上创建索引 user_type_creation_date_idx

  • 策略2:通过分区和索引
  • alter table dummy_table PARTITION BY LIST(类型) 按哈希进行子分区(年(create_date) + 月(create_date)) ( 将 pA 值划分为 (0) ( 子分区 s0, 子分区 s1, ……) 在 dummy_table(user) 上创建索引 user_idx

    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
    

    这是我的问题:

    • 在许多 SO 帖子中,我读过“不要创建分区”,但似乎分区概念对于批量插入表现良好。有什么问题吗 我正在使用 STRATEGY1?
    • 是否有办法提高批量插入速度,例如分区、子分区、mysql/innodb 属性,因为我们拥有单个(没有任何连接)表的优势,也没有更新需要吗?
    • 有没有办法通过并行加载多个文件来提高批量插入速度? 从 S3 加载数据正在阻止其他此类命令。我们可以以某种方式并行运行它们吗?

    版本: MySQL:5.6

    最佳答案

    A 计划:包含索引,不分区,并按 user+type+create_date 对传入数据进行预排序。这将是最快的。但它需要空间来预排序 CSV 文件。

    B 计划:无索引,无分区,仅加载数据,然后ADD INDEX。这需要大量的磁盘空间来进行排序。该计划可能与 A 计划一样快。

    计划 C:如果您不需要 id 并且 (user+type+create_date) 是唯一的,则删除 id 并执行A 计划。现在这是最好的方法。

    问题:

    • 分区不会为您的情况提供任何性能优势。
    • 按顺序插入行或通过排序构建索引 - 两者都比随机插入行快得多。
    • 更多索引:(用户 + A/B/C/D)——这进一步需要将用户作为 PK 中的第一个项。每个用户有多少行? (听起来有几百万?)
    • 您提到每月删除。这确实需要 PARTITION BY RANGE(TO_DAYS(...)) 以及每月分区。这是因为DROP PARTITIONDELETE 快得多。请参阅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 才支持分区。

    这将涉及进行一堆单独的加载,每个加载到一个单独的中。完成后,使用“可传输表空间”将每个表空间作为分区移动到主表中。

    关于mysql - Mysql表批量导入数据,不删除索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54919950/

    相关文章:

    java - 如果遇到暂时性异常,我可以重新使用 PreparedStatement 吗?

    mysql - 我应该总是更喜欢 MySQL InnoDB 而不是 MyISAM 吗?

    mysql - 如果MySQL的InnoDB PRIMARY列自动建立索引,为什么索引长度报告为零?

    mysql - 在 MySQL 中使用带有变量的 concat() 函数

    mysql - 在数据库中搜索超过 300 万条。条目

    mysql - 在 MySQL 中创建内存中和事务安全的表

    并非所有列都建立索引时的 MySQL 优化

    php - 使用 php/javascript 将 mysql 表动态导出到所有 Excel 版本...可能吗?

    php - 每 X 分钟刷新一些脚本函数的最佳方法是什么?

    javascript - 如何在我的数据表中实现 Timeago 函数?