数据库同步和软删除场景中的墓碑表与已删除标志

Lor*_*ori 18 delete

我需要跟踪已删除的项目以满足客户端同步需求。

一般来说,最好添加一个墓碑表和一个跟踪何时从服务器数据库中删除一行的触发器 - 基本上是将一个新行添加到带有已删除项目数据的墓碑表 - 或者将项目保留在原始表并将它们标记为已删除,通常带有一个类型为 bit 的列,以指示一行被删除,另一列在删除发生时进行跟踪?

Lei*_*fel 17

一般来说,最好了解具体要求,而不是根据在大多数情况下最有效的方式做出设计决策。 两者都可能更可取。以下是一些需要收集的具体信息:

  • 删除需要多快?
  • 取消删除需要多快?
  • 多久查询一次删除的数据,是否会查询到未删除的数据?
  • 对已删除数据的查询需要多快?
  • 您是否需要只保留已删除的项目或更改?
  • 您是否需要将主表上的表/索引保持较小?
  • 数据库平台上有哪些分区和/或更改跟踪技术可用?
  • 有多少可用磁盘空间?
  • 删除是即时发生还是批量操作?


Rol*_*DBA 6

也许您应该有意将这两种方法结合起来。为什么 ???

让我们使用该表(MySQL 方言)

CREATE TABLE mydata
(
    id int not null auto_increment
    firstname varchar(16) not null,
    lastname varchar(16) not null,
    zipcode char(5) not null,
    ...
    deleted tinyint not null default 0
    KEY (deleted,id),
    KEY (deleted,lastname,firstname,id),
    KEY (deleted,zipcode,id),
    KEY (lastname,firstname),
    KEY (zipcode),
    PRIMARY KEY (id)
);
Run Code Online (Sandbox Code Playgroud)

请注意,除了 PRIMARY KEY 之外,您创建的每个索引都应以deleted标志开头并以id.

让我们创建墓碑表

CREATE TABLE mytomb SELECT id FROM mydata WHERE 1=2;
ALTER TABLE mytomb ADD PRIMARY KEY (id);
Run Code Online (Sandbox Code Playgroud)

如果你的表已经有一个deleted标志,你可以填充 tommstone 表

INSERT INTO mytomb SELECT id FROM mydata WHERE deleted = 1;
Run Code Online (Sandbox Code Playgroud)

OK,现在数据和墓碑都准备好了。你如何执行删除?

假设您要删除 07305 邮政编码中的每个人。您将运行以下命令:

INSERT IGNORE INTO mytomb SELECT id FROM mydata WHERE deleted=0 AND zipcode='07305';
UPDATE mydata SET deleted=1 WHERE deleted=0 AND zipcode='07305';
Run Code Online (Sandbox Code Playgroud)

好吧,无论你怎么看,这似乎都是很多开销。

现在,您想查看所有已删除的数据吗?这里有两种不同的方式:

  • SELECT * FROM mydata WHERE deleted=1;
  • SELECT B.* FROM mytomb A INNER JOIN mydata B USING (id);

如果 mytomb 中的 id 数大于 mydata 行数的 5%,则为全表扫描。否则,对每一行进行查找的索引扫描。请注意这些方面的任何基准。查找解释计划。

现在,您想查看邮政编码 07304 中的每个人吗?这里有两种不同的方式:

  • SELECT * FROM mydata WHERE deleted=1 AND zipcode='07304';
  • SELECT A.* FROM mydata A LEFT JOIN mytomb B USING (id) WHERE B.id IS NULL AND A.zipcode='07304'

批量删除怎么办?这里有两种不同的方式:

  • DELETE FROM mydata WHERE deleted=1;
  • DELETE B.* FROM mytomb A INNER JOIN mydata B USING (id); DELETE FROM mytomb;

结论

现在,我并不是说要保留这两种方法。随着时间的推移这样做会揭示哪种方法在整体可操作性方面更快。您必须决定哪些基准用于查询实时数据、查询已删除数据和批量删除最适合您。