2

简短的故事: 我有一个分区的 postgres 数据库,其中有一个表来跟踪分区和触发器。触发器需要更改分区表上的约束(它们的valid_date [daterange] 会根据另一个分区的valid_date 更改)并且最好能够删除表,但这会导致错误,因为触发器链正在使用这些表。

cannot ALTER TABLE "core_geometryrecord_8_2" because it is 
    being used by active queries in this session

完整的问题: 我正在对我的模式和触发器架构进行彻底的解释,以防万一,或者有人想知道为什么我觉得需要一个“复杂”的系统,尽管它可能没有必要。

我正在重构一个大型几何数据数据库,以使其更容易和更快地使用。旧系统具有保存相关几何的“几何表”(美国的 IE 县)。数据实际上应该按“date_valid”和“geometrytable_id”分组。

我们决定使用带有 date_valid(日期范围)和 geometrytable_id(外键)约束的 postgres 分区。

因为日期很敏感,并且需要大量的簿记才能保持正确,所以我亲自尝试使用触发器管理大部分数据库(我已经知道我需要一个分区表的插入触发器,所以为什么不这样做)。

我设计了一组触发器来管理分区列表并在您插入或删除几何图形时进行所有簿记。这就是他们所做的。

  • 在插入分区列表表时,创建分区表并应用约束。如果某个日期的 partitionvalid 与这个新的日期重叠(呼叫更新触发器),则修剪它。如果有一个分区在此日期之后的日期有效,则将新分区的结束日期修剪为下一个分区的开始日期(保持连续的时间线)。
  • 从分区列表表中删除时,删除分区表。重新计算已删除分区(如果有)周围的 partition_list 条目(调用更新触发器)的日期范围,以使日期连续。
  • 在更新分区列表表时,DROP OLD DATE CONSTRAINT,将分区表中所有行的 date_valid 更改为分区的新 date_valid 值,然后用新日期创建 DATE CONSTRAINT(约束是项目具有与分区完全相同的 date_valid )。
  • 在插入geometryrecord(分区表)时,找到应该使用的分区,或者插入到分区列表表中(TRIGGERS ON INSERT)。将 NEW 插入正确的分区。
  • 在从几何记录中删除时,如果分区表现在为空,则从分区列表表中删除分区条目(CALLS DELETE TRIGGER)。

如果我在链中的任何触发器中完全触摸过它,它就会因为试图以任何方式改变桌子而对我生气。如果我直接插入到该表中,分区列表表的触发器可以完美地工作,但是从几何表中删除(它调用相同的触发器)会翻转,即使它所做的只是一个选择(查看分区表是否为空)。插入分区几何表也可能导致问题,因为我必须删除约束才能更改行的 date_valid。

必须有一种方法可以做到这一点,我只是不明白。(我还必须使删除表变得更加被动,“将其标记为通过 cron 作业删除”,因为我无法从源自我要删除的表的触发器调用中删除该表。)

非常欢迎任何建议。我简直不敢相信没有人需要做这样的事情,所以我想我只是不知道我在做什么:)。

4

1 回答 1

1

所以在四处挖掘和试验之后,我弄清楚了我需要什么,并认为我会记录我的发现。

这是有关基本 postgres 分区如何为任何感兴趣的人工作的文档页面:http ://www.postgresql.org/docs/9.1/static/ddl-partitioning.html

要知道的关键点是,对于每个分区,您必须设置约束来指定可以在分区中找到的内容(拆分 id 以便每个表中只有 200,000 条记录只需要每个表一个约束)。这使得当您查询主表时,它会根据所有子表的约束快速检查请求。只有查询落在表约束范围内的表才会被进一步查询。如果您正确执行此操作,则只有一个表被真正查询。

至于我学到了什么:

首先,我认为根本不可能从自己的触发器中删除表。我对此的解决方案只是将其标记为通过其他机制删除(例如稍后要删除的表格)。问题在于它会一直存在,直到 Cron 作业运行。由于从自己的触发器更改表也是不可能的,因此该表仍将是一个分区,只是标记为稍后删除。如果您的分区正确,这可能不会导致任何问题。在我的情况下,可以有两个分区重叠(一个被标记为要删除,一个应该在那里)。这样做的副作用是,对于指定可能在这些表中的任何一个表中的内容的查询将同时命中这两个表。这对我来说很好,直到 Cron 工作到来,所以我很好,但有些情况可能不适用于这个问题。

其次,我意识到改变他们没有写入的表的插入工作正常,但是触发相同触发器链的删除和更新失败,因为会话正在使用这些表。我认为这很疯狂,但真正的问题是我在日期和外键上进行了分区,但被记录的 id 删除了。这导致 postgres 检查所有表的所有约束,这使其无法了解要使用哪个表,因此它只是检查了所有表。为了使删除工作,我所要做的就是指定我分区的信息,这样它就知道要查看哪个表,而不是扫描整个表集以查找 id。

TLDR如果您在一些任意(一组)列上对 postgres 表进行分区,请确保通过提供分区上的列来删除或更新记录,以便 postgres 可以知道要查看哪个表而不必扫描整个放。

于 2013-04-15T20:12:03.213 回答