好的,所以几乎每个基于数据库的应用程序都必须处理“非活动”记录。软删除或标记为“被忽略”。我很好奇是否对“活动”列(或状态列)有任何激进的替代方案想法。
例如,如果我有一个人员列表
CREATE TABLE people (
id INTEGER PRIMARY KEY,
name VARCHAR(100),
active BOOLEAN,
...
);
这意味着要获取活跃人员列表,您需要使用
SELECT * FROM people WHERE active=True;
有没有人建议将非活动记录移到一个单独的表中,并且合适的UNION是否可以加入这两个记录?
好奇心引人注目......
编辑:我应该说清楚,我是从纯粹的角度来看这个。我可以看到数据归档对于大量数据可能是必要的,但这不是我来自的地方。如果您选择SELECT * FROM人员,那么这些条目在某种意义上是“活跃的”
由于
答案 0 :(得分:21)
您在活动标志上对表进行分区,以便活动记录位于一个分区中,而非活动记录位于另一个分区中。然后为每个表创建一个活动视图,该视图会自动在其上显示活动过滤器。数据库查询引擎自动将查询限制在其中包含活动记录的分区,这比甚至在该标志上使用索引要快得多。
以下是如何在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)
);
如果您愿意,可以将每个分区放在不同的表空间中。您也可以对索引进行分区。
顺便说一下,这似乎是this问题的重复,作为一个我需要问的新手,处理意外重复的程序是什么?
编辑:根据评论中的要求,提供了在Oracle中创建分区表的示例
答案 1 :(得分:8)
嗯,为了确保您在大多数情况下只绘制活动记录,您可以创建仅包含活动记录的视图。这样就可以更容易地忽略活动部分。
答案 2 :(得分:3)
我们在大多数表中使用枚举('ACTIVE','INACTIVE','DELETED'),所以我们实际上有一个三向标志。我觉得它在不同的情况下对我们很有用。您的里程可能会有所不同。
答案 3 :(得分:2)
移动不活跃的东西通常是一个愚蠢的想法。这是一个很大的开销,有很多潜在的bug,一切都变得更复杂,就像unarchiving东西等。你如何处理相关数据?如果您移动所有这些,则必须修改每个查询。如果你不移动它,你希望得到什么好处?
这导致了下一点:为什么要移动它?当大小加倍时,正确索引的表需要一个额外的查找。任何性能提升都必定可以忽略不计。为什么你会想到它,直到你实际遇到性能问题的遥远未来时期?
答案 4 :(得分:2)
我认为严格地将其视为一段数据然后原始帖子中显示的方式是正确的。活动标志数据直接取决于主键,应该在表中。
该表保存有关人员的数据,无论其数据的当前状态如何。
答案 5 :(得分:1)
活跃的旗帜有点难看,但它很简单并且效果很好。
您可以按照建议将它们移动到另一个表格。我建议查看活动/非活动记录的百分比。如果您有超过20或30%的非活动记录,那么您可以考虑将它们移动到其他位置。否则,这不是什么大问题。
答案 6 :(得分:1)
是的,我们愿意。我们目前在许多表中都有“active ='T / F'”列,主要是显示“最新”行。插入新行时,前一个T行标记为F以保留它以供审计。
现在,我们将转向2表方法,当插入新行时,前一行将移至历史表。这为大多数情况提供了更好的性能 - 查看当前数据。
成本略高于旧方法,以前你必须更新和插入,现在你必须插入和更新(即不是插入新的T行,而是用所有新数据修改现有行),因此,成本只是传递整行数据而不是只传入更改。这几乎不会产生任何影响。
性能优势在于您的主表索引要小得多,并且您可以更好地优化表空间(它们不会增长太多!)
答案 7 :(得分: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
答案 8 :(得分:0)
就性能而言,在大表的位标志上过滤数据并不是很好。如果“活动”确定虚拟删除,则可以创建具有相同结构的“ TableName_delted”表,然后使用删除触发器将删除的数据移到那里。
该解决方案将有助于提高性能并简化数据查询。
答案 9 :(得分:0)
我们经常使用活动标记。如果您的数据库非常大,我可以看到将非活动值迁移到单独的表中的值。
当有人想要查看所有记录,无论是活动还是非活动时,您只需要表的联合。
答案 10 :(得分:0)
这是一个古老的问题,但是对于那些搜索低基数/选择性索引的人,我想提出以下避免分区,辅助表等的方法:
技巧是使用“ dateInactivated”列来存储记录被停用/删除的时间戳。顾名思义,当记录处于活动状态时,该值为NULL,但一旦将其禁用,则将其写入系统日期时间。因此,随着“已删除”记录数的增加,该列上的索引最终具有很高的选择性,因为每个记录都将具有唯一的值(严格来说不是)。
然后您的查询将变为:
SELECT * FROM people WHERE dateInactivated is NULL;
索引将只提取您关心的正确的行集。
答案 11 :(得分:0)
关于索引布尔值,为什么不:
ALTER TABLE users ADD INDEX index_users_on_active (id, active) ;
这不会改善搜索吗? 但是我不知道答案中有多少取决于平台。
答案 12 :(得分:0)
从'纯粹主义的角度'看,现实模型不区分视图和表格 - 两者都是关系。因此,如果实体被正确命名,那么使用使用鉴别器的视图是非常有意义和有效的。人/ ActivePerson。
另外,从'纯粹主义的角度'来看,这个表应该被命名为person,而不是人,因为关系的名称反映了一个元组,而不是整个集合。
答案 13 :(得分:0)
不 - 这是一件很常见的事情 - 根据具体要求提供一些变化(但你已经覆盖了它们):
1)如果你希望有一个完整的BUNCH数据 - 比如多TB或更多 - 立即存档已删除的记录并不是一个坏主意 - 尽管你可能会使用标记为已删除的组合方法,然后复制到存档表。 / p>
2)当然,硬删除记录的选项仍然存在 - 虽然我们的开发人员往往是数据包 - 老鼠 - 我建议您应该查看业务流程并确定是否现在还需要保留数据 - 如果有的话 - 这样做......如果没有 - 你应该可以随意将这些东西扔掉.....根据具体的业务情景。
答案 14 :(得分:0)
这种情况确实决定了解决方案,其中包括:
如果表包含用户,则可以使用几个“flag”字段。一个用于删除,禁用等。或者如果空间有问题,那么禁用的标志就足够了,如果它们被删除则实际删除该行。
它还取决于存储数据的策略。如果有保存数据的策略,那么在很长一段时间后很可能需要一个单独的表。
答案 15 :(得分:0)
我们使用这两种方法来处理非活动记录。我们使用的方法取决于具体情况。对于基本上是查找值的记录,我们使用Active位字段。这允许我们停用条目以便它们不被使用,但也允许我们通过关系维护数据完整性。
我们使用“移动到分离表”方法,其中不再需要数据且数据不是关系的一部分。
答案 16 :(得分:0)
转移到另一张桌子并将它们重新启动需要时间。根据离线记录的数量以及您需要将其恢复的频率,这可能是也可能不是一个好主意。
如果它们被埋没后大部分都不会回来,并且仅用于摘要/报告/任何内容,那么它将使您的主表更小,查询更简单,可能更快。
答案 17 :(得分:0)
在大多数情况下,指示删除的二进制字段就足够了。通常有一种清理机制会在一段时间后删除那些已删除的记录,因此您可能希望使用已删除的时间戳启动架构。