【问题标题】:`active' flag or not?'活动'标志与否?
【发布时间】:2010-09-11 06:20:26
【问题描述】:

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

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

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

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

SELECT * FROM people WHERE active=True;

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

好奇心惊人...

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

谢谢

【问题讨论】:

    标签: sql mysql postgresql


    【解决方案1】:

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

    这是一个如何在 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问题的重复,作为新手我需要问一下,处理意外重复的程序是什么?

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

    【讨论】:

    • 您能否更具体地了解如何“分区”表。我的意思是为您喜欢的任何 RDBM 提供代码。
    • 根据要求,添加了分区表的示例。请查看 Oracle 的概念手册,了解有关表和索引分区的详细信息。我使用 Oracle 10.2,并参考此处的所有文档 -> oracle.com/pls/db102/homepage
    • 我建议不要使用“活动”标志,而是使用不同的字段名称,例如“已删除”。原因是,当下一个人处理它时,他们可能会对“活跃”的含义感到困惑。除此之外,+1 很棒的帖子。
    • @NotMe 已删除似乎同样模棱两可。如果某些内容被删除,为什么它仍然存在?听起来这种事情最好由文档处理。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              【解决方案7】:

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

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

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

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

              【讨论】:

              • 我还想使用 2 表方法,因为我在处理一个设计不佳的旧数据库,其中一些表有一个“active='T/F'”列用于审计目的和他们没有主键。您如何处理已删除的记录,您是使用标志将行标记为活动/已删除,还是将已删除的记录也移动到历史记录表中?此外,您是否也将所有相关数据级联移动到历史表中?谢谢!
              • 什么都没有被删除,您将所有记录移动到历史表并在它们上打一个标志。如果您需要记录删除(而不是随后修改),那么您只需要一个新列将它们标记为已删除。总有一天会有人问起死数据,你就能正确回答。我们不会级联相关记录 - 如果它们发生变化,那么它们的数据需要更新,但除非关系发生变化,否则您不需要这样做 - 但是,我们的数据架构非常简单,可以做到这一点,YMMV。跨度>
              • 话虽如此,我使用的新系统编写了一个完全独立的审计表,仅记录所有更改,“自动”为所有重要(不是所有)写入“列 X 从 Y 更改为 Z”数据变化。
              【解决方案8】:

              在您的架构中这样的二进制标志是一个坏主意。考虑查询

              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

              【讨论】:

              • 基数不应影响索引的使用。选择性确实如此。
              • 什么是选择性?这是否意味着如果只有 5 个活跃用户而不是 100 万,并且我们总是在查询活跃用户,即使基数为 2,使用上述索引也会对我们有所帮助(但数据严重偏向于低活跃用户,这这正是我们的应用程序在这个例子中可能想要的)?
              【解决方案9】:

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

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

              【讨论】:

                【解决方案10】:

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

                【讨论】:

                  【解决方案11】:

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

                  如果大部分人被埋没后就不再回来,并且只用于摘要/报告/其他,那么它会使你的主表更小,查询更简单,可能更快。

                  【讨论】:

                    【解决方案12】:

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

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

                    【讨论】:

                      【解决方案13】:

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

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

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

                      【讨论】:

                        【解决方案14】:

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

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

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

                        【讨论】:

                          【解决方案15】:

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

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

                          【讨论】:

                          • 命名方案是一种偏好。我认为只是建议坚持你对所有桌子的决定。许多人喜欢认为关系包含很多项目。
                          【解决方案16】:

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

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

                          这不会改善搜索吗?
                          但是我不知道这个答案在多大程度上取决于平台。

                          【讨论】:

                            【解决方案17】:

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

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

                            那么你的查询变成:

                            SELECT * FROM people WHERE dateInactivated is NULL;
                            

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

                            【讨论】:

                              【解决方案18】:

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

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

                              【讨论】:

                                猜你喜欢
                                • 2013-08-22
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2014-08-04
                                • 2013-11-16
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                相关资源
                                最近更新 更多