【问题标题】:PostgreSQL slow on a large table with arrays and lots of updatesPostgreSQL 在带有数组和大量更新的大表上运行缓慢
【发布时间】:2011-03-07 05:12:55
【问题描述】:

我有一个相当大的表(20M 记录),它有一个 3 列索引和一个数组列。数组列每天更新(通过附加新值)所有行。也有插入,但没有更新那么多。

数组中的数据代表三个键对应的每日测量值,如下所示:[[date_id_1, my_value_for_date_1], [date_id_2, my_value_for_date_2]]。它用于绘制这些每日值的图表。假设我想随着时间的推移可视化键(a,b,c)的值,我做SELECT values FROM t WHERE a = my_a AND b = my_b AND c = my_c。然后我使用values 数组来绘制图形。

随着时间的推移,更新(每天一次批量更新)的性能显着恶化。

使用 PostgreSQL 8.3.8。

您能告诉我在哪里寻找解决方案吗?它可以是从调整 postgres 中的一些参数到甚至移动到另一个数据库(我猜非关系数据库会更适合这个特定的表,但我没有太多经验)。

【问题讨论】:

标签: performance optimization postgresql


【解决方案1】:

不确定数组是否适合这里。

为什么不将这些存储在单独的表中(每行一个值加键) 那么您的批量更新将是纯插入活动。

【讨论】:

    【解决方案2】:

    3 列的索引没什么好担心的。这并不一定会让它慢得多。但是那个数组列可能确实是问题所在。您说您每天都将值附加到该数组列。通过附加,您是指将值附加到所有 2000 万。表中的记录?还是只是一些记录?

    情况对我来说并不完全清楚,但我建议寻找摆脱该数组列的方法。例如,使其成为一个单独的表。但是,这取决于您的情况,可能不是一个选择。 可能只有我一个人,但我总是觉得在我的一张桌子上有这样的专栏很“脏”。大多数情况下,对于您尝试使用该数组列解决的问题,有更好的解决方案。话虽如此,在某些情况下这样的专栏是有效的,但目前我想不出。当然不是在一张有 2000 万的桌子上。记录数。

    【讨论】:

    • 我将元素附加到一些数组,而不是全部 2000 万。我曾经有一张不同的桌子,但这使它变得巨大并且性能更差。决定对这些数组进行非规范化和存储数据,这对选择进行了巨大改进,并且一开始并没有使更新恶化(尽管随着时间的推移它们似乎变得更糟)。
    • 您能否进一步解释一下表格和数组中数据的性质以及它们之间的关系?可能还有更好的解决方案。 :)
    • 添加了更多细节。见第二段。不过不确定它是否真的很重要。
    【解决方案3】:

    我会看一下表格的 FILLFACTOR。默认情况下它设置为 100,您可以将其降低到 70(开始)。在此之后,您必须执行 VACUUM FULL 来重建表。

    ALTER TABLE tablename SET (FILLFACTOR = 70);
    VACUUM FULL tablename;
    REINDEX TABLE tablename;
    

    这使 UPDATE 有机会将行的更新副本放置在与原始页面相同的页面上,这比将其放置在不同的页面上更有效。或者,如果您的数据库已经因许多以前的更新而有些碎片化,那么它可能已经足够闲置了。现在您的数据库还可以选择执行HOT updates,假设您正在更新的列不涉及任何索引。

    【讨论】:

    • 在我看来,HOT 是一种在执行 UPDATE 时避免更新索引的方法。正确的?如果是这样,为什么我的表现会随着时间的推移下降?我的索引在 4 个月前的更新方式与现在相同,但从那时起我的表现大幅下降。
    • 性能下降可能是因为记录的新版本(由于更新)将放置在不同的页面上。当你有很多记录时,你也会有很多页面。将新版本远离原始版本,将对查询计划产生影响。使用 EXPLAIN 查看会发生什么。还可以考虑 CLUSTER 以与索引存储其信息的顺序相同的顺序存储您的记录。您必须使用填充因子,更新的记录必须保持接近原始记录。
    • 另外,随着您的数组变大,您可以在单个页面上拥有的元组数量会减少。它将开始对大型数组使用 TOAST 存储,然后您将重新回到将数据保存在外部表中的位置,但添加元素的过程非常昂贵。
    • +1 用于“填充因子”和周期性“集群”。升级到 8.4 也可能有所帮助。
    • 解决了这个问题。带来了我每天从 9 点到 1 点的整批 4M 更新。 \o/ 我做了一些类似于 CLUSTER 的操作,但是是手动的。 CLUSTER 不仅会锁表,而且会占用大量资源。所以我只是创建了另一个具有相同结构的表,并按照我想要的顺序插入记录(INSERT INTO ... SELECT FROM ... ORDER BY a、b、c),并确保我的更新以与现在磁盘上的物理顺序(a、b、c)。在解决这个问题时学到了很多东西。谢谢大家!
    【解决方案4】:

    问题在于更新。每天将模式从基于数组更改为多行,性能问题就会消失。

    您可以稍后使用某种 cronjob 向数组添加汇总,但要避免更新。

    【讨论】:

    • 如果我必须从头开始构建数组,“汇总到数组”会非常慢(对于 a、b、c 的每种组合,每天都经过)。
    猜你喜欢
    • 1970-01-01
    • 2015-08-03
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2013-06-27
    • 2019-11-13
    • 2020-10-04
    相关资源
    最近更新 更多