Mysql优化算法,保存历史变化的变种

Posted

技术标签:

【中文标题】Mysql优化算法,保存历史变化的变种【英文标题】:Mysql optimization algorithm , variants to saving changes in history 【发布时间】:2019-02-25 09:32:31 【问题描述】:

我有一个包含实际用户信息的主表

CREATE TABLE user
(
  id                            bigint                              NOT NULL
    PRIMARY KEY,
  updated                       timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP,
  username                      varchar(40)                         NULL,
  full_name                     varchar(255)                        NULL,
  biography                     varchar(512)                        NULL,
  profile_pic_id                varchar(40)                         NULL,
  profile_pic_url               varchar(255)                        NULL,
  hd_profile_pic_url            varchar(255)                        NULL,
  follower_count                int                                 NULL,
  following_count               int                                 NULL,
  media_count                   int                                 NULL,
  usertags_count                int                                 NULL,
  following_tag_count           int                                 NULL,
  external_url                  longtext                            NULL,
  reel_auto_archive             varchar(255)                        NULL,
  has_biography_translation     tinyint(1)                          NULL,
  has_anonymous_profile_picture tinyint(1)                          NULL,
  has_highlight_reels           tinyint(1)                          NULL,
  is_business                   tinyint(1)                          NULL,
  is_active                     tinyint(1)                          NULL,
  is_verified                   tinyint(1)                          NULL,
  is_private                    tinyint(1)                          NULL,
  is_blocked                    tinyint(1)                          NULL
)

用于保存历史记录的表也几乎相同:

CREATE TABLE user_history
(
  id                            int AUTO_INCREMENT
    PRIMARY KEY,
  user_id                  bigint                              NULL,
  added                         timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
  username                      varchar(40)                         NULL,
  full_name                     varchar(255)                        NULL,
  biography                     varchar(512)                        NULL,
  profile_pic_id                varchar(40)                         NULL,
  profile_pic_url               varchar(255)                        NULL,
  hd_profile_pic_url            varchar(255)                        NULL,
  follower_count                int                                 NULL,
  following_count               int                                 NULL,
  media_count                   int                                 NULL,
  usertags_count                int                                 NULL,
  following_tag_count           int                                 NULL,
  external_url                  longtext                            NULL,
  reel_auto_archive             varchar(255)                        NULL,
  has_biography_translation     tinyint(1)                          NULL,
  has_anonymous_profile_picture tinyint(1)                          NULL,
  has_highlight_reels           tinyint(1)                          NULL,
  is_business                   tinyint(1)                          NULL,
  is_active                     tinyint(1)                          NULL,
  is_verified                   tinyint(1)                          NULL,
  is_private                    tinyint(1)                          NULL,
  is_blocked                    tinyint(1)                          NULL,
  CONSTRAINT FK_F19A7E3C5AFE2D44
    FOREIGN KEY (user_id) REFERENCES user (id)
)
  COLLATE = utf8mb4_unicode_ci;

CREATE INDEX IDX_F19A7E3C5AFE2D44
  ON user_history (user_id);

用于保存历史记录的触发器:

CREATE TRIGGER user_update
  AFTER UPDATE
  ON user
  FOR EACH ROW
BEGIN
  INSERT INTO `user_history` (`user_id`, `username`, `full_name`, `biography`, `profile_pic_id`,
                                   `profile_pic_url`, `hd_profile_pic_url`, `follower_count`, `following_count`,
                                   `media_count`, `usertags_count`, `following_tag_count`, `external_url`,
                                   `reel_auto_archive`, `has_biography_translation`, `has_anonymous_profile_picture`,
                                   `has_highlight_reels`, `is_business`, `is_active`, `is_verified`, `is_private`,
                                   `is_blocked`, `added`)
  VALUES (NEW.id, NEW.username, NEW.full_name, NEW.biography, NEW.profile_pic_id, NEW.profile_pic_url,
          NEW.hd_profile_pic_url,
          NEW.follower_count, NEW.following_count, NEW.media_count, NEW.usertags_count, NEW.following_tag_count,
          NEW.external_url,
          NEW.reel_auto_archive, NEW.has_biography_translation, NEW.has_anonymous_profile_picture,
          NEW.has_highlight_reels,
          NEW.is_business, NEW.is_active, NEW.is_verified, NEW.is_private, NEW.is_blocked, now());
END;

所以我有一些问题:

    有什么变种可以提高写入速度以保存历史记录? 我尝试通过 LOAD DATA LOCAL INFILE,而不是触发 - 没有速度提升。

    有哪些变体可以用更少的数据量保存历史记录? 例如,我想我可以运行一些外部脚本,检查 user_history 数据并将相同的值设置为 NULL? 我尝试使用另一个触发器来保存 - 更大,它在写入之前比较每个值并只写入更改的值 - 但它的执行时间很长。 还是将数据差异(可重用)保存到数据库的任何更好的变体?

【问题讨论】:

System versioned tables @danblack 看起来只有 MariaDB 才有这个功能,对吗?我用的是 mysql 8.0 在 MySQL 中不支持像 danblack sent 这样的临时表。 澄清:这是否正确:user 始终包含 当前 值,user_history 有完整的历史记录? 【参考方案1】: 将计数器移动到并行表。将这些拆分出来也可以加快UPDATE 的速度。 “UPDATE”的内部处理涉及构建整个行的副本,以防其他连接访问同一行。 此外,不要保留它们的历史记录。我猜大多数“更新”都在这个领域。 将所有has_%is_% 标志组合成一个SETTINYINT UNSIGNED(最多8 个,或SMALLINT UNSIGNED 最多16 个)。 没有has 标志——当您需要检查“有”时,只需使用LEFT JOINEXISTS。 制作is_% 标志(可能还有其他列)NOT NULL。一般来说,您应该有意识地确定NULL 是否对业务逻辑有意义,而不是简单地将所有列都设为NULLable

(我的建议适用于所有版本的 MySQL 和 MariaDB。)

【讨论】:

以上是关于Mysql优化算法,保存历史变化的变种的主要内容,如果未能解决你的问题,请参考以下文章

梯度下降优化算法综述

梯度下降优化算法综述

自编码器及相关变种算法简介

Mysql 优化器内部JOIN算法hash join Nestloopjoin及classic hash join CHJ过程详解

MySQL 优化

粒子群算法 | 启发式优化算法