【问题标题】:Database performance: filtering on column vs. separate table数据库性能:按列过滤与单独的表
【发布时间】:2011-05-01 05:33:26
【问题描述】:

我想知道以下情况的最佳方法是什么:

我在数据库中有一个 Orders 表,其中显然包含所有订单。但这些实际上是所有订单,因此包括刚刚标记为“完成”的完整/完成的订单。从所有未结订单中,我想计算一些东西(如未结金额、未清项目等)。什么是更好的性能明智:

保留 1 个包含所有订单(包括完整/存档订单)的订单表,并通过过滤“完成”标志进行计算?

或者我应该创建另一个表,例如'Orders_Archive',以便 Orders 表只包含我用于计算的未结订单?

这些方法是否存在(明显的)性能差异?

(顺便说一句,我在 PostgreSQL 数据库上。)

【问题讨论】:

    标签: database performance database-design postgresql


    【解决方案1】:

    这是数据库设计中的一个常见问题:是否分离或“归档”不再“活动”的记录的问题。

    最常见的方法是:

    • 一张表中的所有内容,酌情将订单标记为“完成”。优点:最简单的解决方案(代码和结构方面),良好的灵活性(例如,易于“复活”订单)。缺点:表可能会变得非常大,这对于查询和例如查询都是一个问题。备份。
    • 将旧资料存档到单独的表格中。解决了第一种方法的问题,但代价是更复杂。
    • 使用基于值的分区表。这意味着逻辑上(对应用程序而言)一切都在一个表中,但在幕后,DBMS 根据某些列上的值将内容放入单独的区域。您可能会使用“完成”列或“订单完成日期”进行分区。

    最后一种方法结合了前两种的优点,但需要 DBMS 的支持并且设置起来更复杂。

    注意:

    仅存储“归档”数据的表通常称为“归档表”。一些 DBMS 甚至为这些表提供了特殊的存储引擎(例如 MySQL),这些引擎经过优化以允许快速检索和良好的存储效率,但代价是更改/插入缓慢。

    【讨论】:

      【解决方案2】:

      或者我应该创建另一个表,例如'Orders_Archive',以便 Orders 表只包含我用于计算的未结订单?

      是的。他们称之为数据仓库。人们这样做是因为它加速了交易系统以消除几乎不使用的历史记录。首先,表格体积更小,处理速度更快。其次,长期运行的历史报告不会干扰事务处理。

      这些方法是否存在(明显的)性能差异?

      是的。奖金。您可以重组您的历史,使其不再是 3NF(用于更新),而是星型模式(用于报告)。优势是巨大的。

      购买 Kimball 的 The Data Warehouse Toolkit 书籍,了解有关星型架构设计和将历史从活动表迁移到仓库表的更多信息。

      【讨论】:

      • 嗯,仅仅归档旧记录与数据仓库仍然相去甚远。这是一个开始......
      • 我同意这个答案。但是在你真正需要部署这样的东西之前,你正在谈论海量的海量数据。一个有 100000 个订单的订单表可能不需要这个
      • 我还以为叫表分区,你用一个视图来模拟完整的表
      • @Sam Saffron:大规模?不会。您会发现仅将数千行历史记录从活动表中移到星型模式“报告”表中的效果很好。数据仓库并不意味着大。这意味着针对报告进行了优化。这是一个独特的建筑。 “数据集市”是一些人喜欢称之为的名称,因此没有人会被规模问题吓倒。
      • @Sam Saffron:您可以使用多种技术。您可以通过实际设置单独的表来对表进行分区;然后您可以根据需要将它们组合成一个视图。您也可以让 DBMS 在内部处理分区;这就是所谓的基于值的分区。
      【解决方案3】:

      从不分离或分离当前/存档的数据。这是不正确的。它可能被称为“数据仓库”或一桶鱼,但这是错误的、不必要的,并且会产生原本不存在的问题。结果是:

      • 现在每个查询数据的人都必须在两个地方而不是一个地方查找它
      • 更糟糕的是,手动添加聚合值(在 Excel 或其他中)
      • 您在密钥中引入了异常,完整性就丢失了(否则它会因单个数据库约束而唯一)
      • 当需要更改已完成的订单(或多个)时,您必须将其从“仓库”中取出并放回“数据库”中

      如果且仅当桌子上的响应很慢,则解决该问题并提高速度。仅有的。没有其他的。这(在我见过的每种情况下)是一个索引错误(缺少索引或不正确的列或不正确的列序列都是错误)。通常,您只需要索引中的 IsComplete 列,以及您的用户最常用于搜索的任何内容,以包含/排除打开/完成订单。

      现在,如果您的 dbms 平台无法处理大型表或大型结果集,那就是另一个问题了,您必须使用工具中可用的任何方法。但作为数据库设计问题,这是完全错误的;除非您受到平台的限制,否则无需创建副本、填充和维护它(以及随之而来的所有问题)。

      去年和今年,作为普通绩效任务的一部分,我已经合并了具有数十亿行的拆分表(并且必须解决所有据称“不存在”的重复行问题,是的,对,2 天只是为了那个)。具有更正索引的合并表比拆分表快; “数十亿行减慢表格速度”的借口是完全错误的。用户喜欢我,因为他们不再需要使用两个工具和查询两个“数据库”来获得他们需要的东西。

      【讨论】:

      • 其实它不是定义的数据仓库。人们抛弃的许多错误定义之一。数据仓库是一个或包含报告副本 - 它没有说明删除原始副本。
      • @Tom。你说得对。这些天机房里松散蓬松的玩具太多了。
      • 我明白你在说什么。它是一个数据库分区,不是设计的一部分。
      【解决方案4】:

      由于您使用的是 postgresql,您可以利用 部分索引。假设你经常使用orderdate的未完成订单,你可以像这样指定索引:

      create index order_orderdate_unfinished_ix on orders ( orderdate )
        where completed is null or completed = 'f';
      

      当你设置这个条件时,postgresql 不会索引已完成的订单,从而节省硬盘空间并使索引速度更快,因为它只包含少量数据。这样您就可以在没有分表的麻烦的情况下获得好处。

      当您将数据分成 ORDERS 和 ORDERS_ARCHIVE 时,您将不得不调整现有报告。如果您有很多报告,那可能会很痛苦。

      查看本页部分索引的完整描述:http://www.postgresql.org/docs/9.0/static/indexes-partial.html

      编辑:对于存档,我更喜欢创建另一个具有相同架构的数据库,然后将旧数据从事务数据库移动到此存档数据库。

      【讨论】:

        猜你喜欢
        • 2010-09-16
        • 2013-08-14
        • 1970-01-01
        • 2021-09-07
        • 2020-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多