MySQL optimize table request 在写入操作和复制环境中使用是否安全?

Is MySQL optimize table request safe to use during write operations and in replication enviorement?

我有 MySQL 数据库,最多 300 个 InnoDB tables 具有相似的结构,每个数据库大约有 700k 行,正常情况下大小约为 160M。这个table是相互独立的,没有外键。

此 table 主要用于 RW 操作 table 使用模式如下所示:

  1. 每 15 分钟向每个 table
  2. 中插入新的数据部分(300-1200 行新行)
  3. 每天一次,从每个 table.
  4. 中删除超过 30 天的数据
  5. 根据用户请求定期从随机 table 中读取数据。

几个月后,数据库性能显着下降。经过排查发现问题:table个文件变大了,每个space占用了300M左右的磁盘空间。 运行 手动 table 优化后,问题已解决,但几周后数据库性能又开始下降。

作为保持数据库健康的解决方案,在每次数据删除后添加了 OPTIMIZE TABLE 请求。

问题是:

  1. MySQL性能下降问题还有其他解决方案吗?
  2. Is it possible to lost data inserted into table when OPTIMIZE TABLE is 运行 (if INSERT request executed when OPTIMIZE TABLE request is still in progress) ?
  3. OPTIMIZE TABLE 请求对于意外 MySQL 服务器关闭是否安全(如果在 INSERT 操作完成但 OPTIMIZE TABLE 的情况下发生 PC 断电,是否有可能丢失提交的数据不要求)?
  4. 在简单复制的情况下,OPTIMIZE TABLE 请求是否可以安全使用(OPTIMIZE TABLE 请求在主服务器上执行并在从属服务器上复制,该从属服务器仅用作备份设施并且没有 IO 除了复制)?

编辑:MySQL 5.7.15,InnoDB tables。复制环境是使用 MySQL 8.0.4 RC.

构建的

编辑 2:table 结构:

CREATE TABLE `data_2235353676` (
`id` BIGINT(20) NOT NULL,
`inst` VARCHAR(100) NULL DEFAULT NULL,
`if_i` BIGINT(20) NOT NULL,
`prt` BIGINT(20) NULL DEFAULT NULL,
`if_t` BIGINT(20) NULL DEFAULT NULL,
`path` BIGINT(20) NULL DEFAULT NULL,
`period` BIGINT(20) NOT NULL,
`type` BIGINT(20) NOT NULL,
`servicetype` INT(11) NOT NULL,
`sdv_time` BIGINT(20) NULL DEFAULT NULL,
`srv_time` BIGINT(20) NOT NULL,
`err_c` BIGINT(20) NULL DEFAULT NULL,
`err_s` BIGINT(20) NULL DEFAULT NULL,
`srv_err_s` BIGINT(20) NULL DEFAULT NULL,
`una_s` BIGINT(20) NULL DEFAULT NULL,
`valid` BIGINT(1) NULL DEFAULT NULL,
`r_err` BIGINT(20) NULL DEFAULT NULL,
`k_err` BIGINT(20) NULL DEFAULT NULL,
`l2CounterType` BIGINT(20) NOT NULL,
`l2Count` BIGINT(20) NULL DEFAULT NULL,
PRIMARY KEY (`id`, `if_i`, `period`, `type`, `servicetype`, `srv_time`, `l2CounterType`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
;

INSERTOPTIMIZE互相争斗;我的建议将以多种方式减少这种冲突,最重要的是摆脱 OPTIMIZE.

GA 8.0 可用 -- 请更新;你的 RC 版本在生产中不应该被信任。

哪一列控制 "older then 30 days"?在一个非分区的table中,看看把它放在PRIMARY KEY中是否可行。通过 "clustering" 将所有行一起插入,I/O 显着减少。在分区的 table 中(如下所述),尝试将该列移动到 PK 中较晚的位置。 (分区将减少 I/O,因为您将仅在 'last' 分区中插入。)

确保您使用的是 innodb_file_per_table=ON

不要盲目使用8字节BIGINT;找到一个合适的 INT 口味,它会更小,但范围足够。

使用PARTITION BY RANGE(TO_DAYS(...))将table分成大约32个分区。这将使旧数据的删除非常快速和高效,而不需要 OPTIMIZE TABLE。更多讨论:http://mysql.rjweb.org/doc.php/partitionmaint

注意:分区的 tables 有一些额外的 "free space",所以我的建议仍然会导致每个 table 大约 300MB。但是,免费 space 不会影响性能。如果可行,减少分区——比如 12 个 3 天分区。

你是如何插入的?一个LOAD DATA?一个'batch'INSERT? (我希望你不是一次插入一行。)

大部分栏目真的是 NULLable 吗?

OPTIMIZE 在所有方面都是 'safe',因为它锁定 table,复制所有数据,然后重命名新副本以代替旧副本。 (实际上有一个很小的 ​​window 漏洞,但 8.0 用 "Data Dictionary" 覆盖了它。)