23

好的,所以实际上每个基于数据库的应用程序都必须处理“非活动”记录。无论是软删除还是将某些内容标记为“被忽略”。我很好奇在“活动”列(或状态列)上是否有任何激进的替代想法。

例如,如果我有一个人员列表

CREATE TABLE people (
  id       INTEGER PRIMARY KEY,
  name     VARCHAR(100),
  active   BOOLEAN,
  ...
);

这意味着要获取活跃人员列表,您需要使用

SELECT * FROM people WHERE active=True;

有没有人建议将非活动记录移到单独的表中,并在哪里进行适当的 UNION 来加入两者?

好奇心强...

编辑: 我应该说清楚,我是从纯粹主义者的角度来看的。我可以看到对于大量数据可能需要数据归档,但这不是我的出发点。如果您执行 SELECT * FROM people ,那么这些条目在某种意义上是“活跃的”对我来说是有意义的

谢谢

4

18 回答 18

23

您根据活动标志对表进行分区,以便活动记录在一个分区中,而非活动记录在另一个分区中。然后为每个表创建一个活动视图,该视图上自动具有活动过滤器。数据库查询引擎自动将查询限制在其中包含活动记录的分区,这甚至比在该标志上使用索引要快得多。

下面是一个如何在 Oracle 中创建分区表的示例。Oracle 没有布尔列类型,所以我修改了您的表结构以供 Oracle 使用。

CREATE TABLE people
(
   id       NUMBER(10),
   name     VARCHAR2(100),
   active   NUMBER(1)
)
PARTITION BY LIST(active)
(
   PARTITION active_records VALUES (0)
   PARTITION inactive_records VALUES (1)
);

如果您愿意,可以将每个分区放在不同的表空间中。您也可以对索引进行分区。

顺便说一句,这似乎是这个问题的重复,作为一个新手我需要问,处理意外重复的程序是什么?

编辑:根据评论中的要求,提供了在 Oracle 中创建分区表的示例

于 2008-09-19T14:36:08.290 回答
8

好吧,为了确保您只在大多数情况下绘制活动记录,您可以创建只包含活动记录的视图。这样就更容易不遗漏活动部分。

于 2008-09-19T14:32:22.853 回答
3

我们在大多数表中使用 enum('ACTIVE','INACTIVE','DELETED') 所以我们实际上有一个 3 路标志。我发现它适用于我们在不同的情况下。你的旅费可能会改变。

于 2008-09-19T14:55:03.453 回答
3

移动不活跃的东西通常是一个愚蠢的想法。这是一个很大的开销,有很多潜在的错误,一切都变得更加复杂,比如取消存档等。你如何处理相关数据?如果你也移动所有这些,你必须修改每一个查询。如果你不动它,你希望得到什么好处?

这就引出了下一点:你为什么要移动它?当大小翻倍时,正确索引的表需要一次额外的查找。任何性能提升都注定是微不足道的。为什么你还要等到遥远的未来真正遇到性能问题时才会考虑它?

于 2008-09-19T14:55:15.560 回答
2

我认为将其严格视为一条数据,那么原始帖子中显示的方式是正确的。活动标志数据块直接依赖于主键,应该在表中。

该表包含有关人员的数据,无论其数据的当前状态如何。

于 2008-09-19T14:57:15.103 回答
1

活动标志有点难看,但它很简单而且效果很好。

您可以按照您的建议将它们移动到另一个表。我建议查看活动/非活动记录的百分比。如果您有超过 20% 或 30% 的非活动记录,那么您可能会考虑将它们移到其他地方。否则,这没什么大不了的。

于 2008-09-19T14:32:37.737 回答
1

是的,我们会的。目前,我们的许多表格中都有“active='T/F'”列,主要是为了显示“最新”行。当插入新行时,前一个 T 行被标记为 F 以保留它以供审计。

现在,我们正在转向 2-table 方法,当插入新行时,前一行将移动到历史表中。这在大多数情况下为我们提供了更好的性能 - 查看当前数据。

成本略高于旧方法,以前您必须更新和插入,现在您必须插入和更新(即不是插入新的 T 行,而是用所有新数据修改现有行),所以成本只是传递一整行数据而不是只传递更改。这几乎不会产生任何影响。

性能优势是您的主表的索引明显更小,并且您可以更好地优化表空间(它们不会增长这么多!)

于 2008-09-19T14:35:55.840 回答
1

在你的模式中这样的二进制标志是一个坏主意。考虑查询

SELECT count(*) FROM users WHERE active=1

看起来很简单。但是当您拥有大量用户时会发生什么,以至于需要向该表添加索引。再一次,它看起来直截了当

ALTER TABLE users ADD INDEX index_users_on_active (active)

除了!!这个索引是没有用的,因为这一列的基数正好是二!任何数据库查询优化器都会忽略此索引,因为它的基数较低并进行表扫描。

在用有用的标志填充您的模式之前,请考虑您将如何访问该数据。

https://stackoverflow.com/questions/108503/mysql-advisable-number-of-rows

于 2008-09-21T13:41:01.260 回答
0

我们经常使用活动标志。但是,如果您的数据库将非常大,我可以看到将非活动值迁移到单独的表中的价值。

然后,当有人想要查看所有记录(无论是活动的还是非活动的)时,您只需要一个表的联合。

于 2008-09-19T14:32:15.757 回答
0

在大多数情况下,指示删除的二进制字段就足够了。通常有一种清理机制会在一定时间后删除那些已删除的记录,因此您可能希望使用已删除的时间戳启动模式。

于 2008-09-19T14:33:12.570 回答
0

搬到单独的桌子上并将它们重新带回需要时间。根据离线记录的数量以及您需要将它们恢复的频率,这可能是一个好主意,也可能不是一个好主意。

如果大多数人一旦被掩埋就不会回来,并且仅用于摘要/报告/其他任何内容,那么它将使您的主表更小,查询更简单并且可能更快。

于 2008-09-19T14:33:46.640 回答
0

我们使用这两种方法来处理非活动记录。我们使用的方法取决于具体情况。对于本质上是查找值的记录,我们使用 Active 位字段。这允许我们停用条目以便它们不会被使用,但也允许我们维护数据与关系的完整性。

我们使用“移动到分离表”方法,其中不再需要数据并且数据不是关系的一部分。

于 2008-09-19T14:37:56.490 回答
0

情况确实决定了解决方案,我认为:

如果表包含用户,那么可以使用几个“标志”字段。一个用于已删除、已禁用等。或者如果空间是一个问题,则禁用标志就足够了,如果它们已被删除,则实际删除该行。

它还取决于存储数据的策略。如果有保存数据存档的策略,那么在很长一段时间后很可能需要一个单独的表。

于 2008-09-19T14:39:57.673 回答
0

不 - 这是很常见的事情 - 根据特定要求有几个变化(但您已经涵盖了它们):

1) 如果您希望拥有一整套数据——比如数 TB 或更多——立即归档已删除的记录并不是一个坏主意——尽管你可以使用标记为已删除然后复制到归档表的组合方法。

2) 当然,硬删除记录的选项仍然存在——尽管我们的开发人员往往是数据包老鼠——我建议你应该查看业务流程并决定现在是否需要保留数据——如果有 - 这样做......如果没有 - 您可能应该随意扔掉这些东西......再次,根据具体的业务场景。

于 2008-09-19T14:42:35.590 回答
0

从“纯粹主义的角度”来看,现实模型并没有区分视图和表格——两者都是关系。因此,如果实体被正确命名,例如 Person/ActivePerson,则使用使用鉴别器的视图是完全有意义和有效的。

此外,从“纯粹主义者的角度”来看,表应该命名为 person,而不是 people,因为关系的名称反映了一个元组,而不是整个集合。

于 2008-09-19T16:49:49.623 回答
0

关于索引布尔值,为什么不:

ALTER TABLE users ADD INDEX index_users_on_active (id, active) ;  

这不会改善搜索吗?
但是我不知道这个答案有多少取决于平台。

于 2011-02-17T19:47:14.857 回答
0

这是一个老问题,但对于那些搜索低基数/选择性索引的人,我想提出以下避免分区、辅助表等的方法:

诀窍是使用“dateInactivated”列来存储记录被停用/删除时的时间戳。顾名思义,当记录处于活动状态时,该值为NULL,但一旦停用,则写入系统日期时间。因此,随着“已删除”记录数量的增加,该列上的索引最终具有高选择性,因为每条记录都将具有唯一的(不是严格意义上的)值。

然后您的查询变为:

SELECT * FROM people WHERE dateInactivated is NULL;

该索引将拉入您关心的正确行集。

于 2019-07-10T05:05:25.423 回答
0

就性能而言,为大表过滤位标志上的数据并不是很好。如果“活动”确定虚拟删除,您可以创建具有相同结构的“TableName_delted”表,并使用删除触发器将已删除的数据移动到那里。

该解决方案将有助于提高性能并简化数据查询。

于 2020-02-03T21:42:10.703 回答