我们已经收集了一段时间,并使用timestamptz字段。我弄错了,应该使用时间戳。我们要做的是从不同的位置收集大量数据,然后自己计算UTC,然后再将数据推送到Postgres。据我了解,时间戳和时间戳数据两者都是相同的8个字节,时间戳为您提供了神奇(且不可见)的AT TIME ZONE
转换。意思是,数据没有什么不同,这就是Postgres处理不同数据的方式。在我们的案例中,这意味着我们正在通过将数据作为UTC推送到Postgres中,然后再次将其拉出到本地来搞砸。我们服务器的数据没有一个时区,这就是为什么我们像Postgres在内部将其设置为UTC的原因。为了使报告更简单,分析表通常具有一个用于local_dts和utc_dts的冗余列。这样,我们可以运行报告,比较不同时区中不同设施的“ 8月11日星期一早上”。不同的设施具有不同的时区,因此我们使用“本地”值,即此类查询的本地值。但是,如果我们需要统一的时间表,则可以使用UTC。简而言之:同一张表中的行可能来自具有不同时区的源。[好吧,那是背景,现在我要更新的行数达千万。结构修改看起来很简单:
-- Change the data type, this is instantaneous.
ALTER TABLE assembly
ALTER COLUMN created_dts
SET DATA TYPE timestamp;
-- Reset the default, it's probably not necessary, but the ::timestamptz is misleading/confusing here otherwise.
ALTER TABLE assembly
ALTER COLUMN created_dts
SET DEFAULT '-infinity'::timestamp
我必须删除并重新创建一些视图,但这仅是运行一些备份脚本的问题。
我的问题是如何在不拖拽服务器的情况下有效地进行更新?我正在想象一次按5K行进行批处理等。为了简单起见,假设我们所有的服务器都设置为“美国/中央”。当我们最初将数据作为UTC推送时,它又由Postgres转换,因此现在数据由于服务器时间和UTC之间的偏移而消失了。 (我认为。)如果是这样,最简单的更新可能如下所示:
SET TIME ZONE 'UTC'; -- Tell Postgres we're in UTC to line up the data with the UTC clock it's set to.
UPDATE analytic_scan
SET created_dts = created_dts at time zone 'US/Central' -- Tell Postgres to convert the value back to where we started.
这似乎可行(?),但忽略了处理夏时制的明显遗漏。我可以添加WHERE
子句来处理该问题,但这不会改变我的问题。现在的问题是,我的记录数是这样的:
analytic_productivity 728,708
analytic_scan 4,296,273
analytic_sterilizer_load 136,926
analytic_sterilizer_loadinv 327,700
record_changes_log 17,949,132
因此,不是巨大的,但并非没有。有没有一种方法可以合理地对SQL中的数据进行切片,以便
CREATE TABLE IF NOT EXISTS "data"."analytic_productivity" (
"id" uuid NOT NULL DEFAULT NULL,
"pg_con_id" integer GENERATED BY DEFAULT AS IDENTITY UNIQUE,
"data_file_id" uuid NOT NULL DEFAULT NULL,
"start_utc" timestamptz NOT NULL DEFAULT '-infinity',
"start_local" timestamptz NOT NULL DEFAULT '-infinity',
"end_utc" timestamptz NOT NULL DEFAULT '-infinity',
"end_local" timestamptz NOT NULL DEFAULT '-infinity')
我的一个主意是使用UUID::text
的子字符串或散列来进行较小的批处理:
select * from analytic_sterilizer_loadinv
where left(id::text,1) = 'a'
这似乎很慢而且很恐怖。哈希似乎更好一些:
select abs(hashtext(id::text)) % 64,
count(*)
from analytic_sterilizer_loadinv
存储桶的大小不是均匀的,但这可能已经足够了,如果需要,我可以增加存储桶的数量。不幸的是,我不知道如何使用存储桶在SQL循环中运行代码。如果有人指出如何做,我将不胜感激。而且,如果有一个简单的内置分块功能,我很想知道。
我还没有考虑过如何处理即将被修改所困扰的传入数据的明确问题,只是没有锁定整个表。我可能可以做到。
部署在RDS上的精简版Postgres 11.4。是否有内置或直接的方法来拆分表中的行以进行批处理更新?一旦有了桶方案,如何在...
UPDATE
,而要一次完成。主要缺点是,这会使表膨胀,因此之后应在表上运行VACUUM (FULL)
,这将导致停机。