请求不更新行但 returns 成功
Request not updating rows but returns successful
我正在尝试从另一个更新 table,请求最终成功,但没有更新任何行。每个 table 包含 ~32M 行。
我 运行 使用 PostgreSQL 11.12。
这是 2 table(我删除了请求中未使用的列):
CREATE TABLE IF NOT EXISTS public.sirene_geo
(
siret character varying(50) NOT NULL,
x numeric,
y numeric,
CONSTRAINT sirene_geo_etablissement_pkey PRIMARY KEY (siret)
)
CREATE TABLE IF NOT EXISTS public.sirene_eta
(
siret character varying(50) NOT NULL,
latitude numeric,
longitude numeric,
CONSTRAINT sirene_stock_etablissement_pk PRIMARY KEY (siret)
)
更新请求:
UPDATE sirene_eta eta
SET longitude = x,
latitude = y
FROM sirene_geo geo
WHERE eta.siret = geo.siret
在 pgAdmin (v5.4) 上,“受影响的行”字段显示为 -1。
Postgres 是使用 hash join 策略来完成更新的。
此外,sirene_geo 中的行数少于 sirene_eta,Postgres 仍在 sirene_geo 上构建散列 table(因此导致某些行不匹配)。
当我尝试在子查询 table 内进行限制更新时,它可以工作,但它使用绝对不是 suitable 的嵌套循环策略来更新整个 table。
更新:
没有并发写入 activity。我检查了日志,确实有一个错误:
ERROR: could not write to file "base/pgsql_tmp/pgsql_tmp9264.8256": No space left on device
您的存储设备上 space 已 运行 次。 在启动大 UPDATE
之前,在磁盘上腾出空间(或任何你用作存储的东西)。删除可有可无的文件(与数据库无关)。或者以某种方式缩小你的数据库。
普通的 VACUUM
可能 可以胜任。或者 VACUUM FULL
(阻止并发访问)以积极缩小物理存储。如果您无法阻止,请考虑使用 non-blocking 社区工具之一。参见:
- Optimize Postgres query on timestamp range
VACUUM FULL
最好在 sirene_eta
(目标 table)上 not 无论如何都会重用 UPDATE
中的死元组(在普通 VACUUM
之后)。并确保 VACUUM
没有被长 运行 事务阻塞。参见:
无论您做什么,如果您不希望 all 目标行实际发生变化,请添加 WHERE
条件来过滤空更新(全额付费! )
UPDATE sirene_eta eta
SET longitude = geo.x
, latitude = geo.y
FROM sirene_geo geo
WHERE eta.siret = geo.siret
AND (eta.longitude IS DISTINCT FROM geo.x -- !
OR eta.latitude IS DISTINCT FROM geo.y)
甚至可以通过减少要完成的工作(显着)来解决您的问题。 (事实证明,你的情况并非如此。
参见:
- How do I (or can I) SELECT DISTINCT on multiple columns?
我正在尝试从另一个更新 table,请求最终成功,但没有更新任何行。每个 table 包含 ~32M 行。 我 运行 使用 PostgreSQL 11.12。
这是 2 table(我删除了请求中未使用的列):
CREATE TABLE IF NOT EXISTS public.sirene_geo
(
siret character varying(50) NOT NULL,
x numeric,
y numeric,
CONSTRAINT sirene_geo_etablissement_pkey PRIMARY KEY (siret)
)
CREATE TABLE IF NOT EXISTS public.sirene_eta
(
siret character varying(50) NOT NULL,
latitude numeric,
longitude numeric,
CONSTRAINT sirene_stock_etablissement_pk PRIMARY KEY (siret)
)
更新请求:
UPDATE sirene_eta eta
SET longitude = x,
latitude = y
FROM sirene_geo geo
WHERE eta.siret = geo.siret
在 pgAdmin (v5.4) 上,“受影响的行”字段显示为 -1。
Postgres 是使用 hash join 策略来完成更新的。
此外,sirene_geo 中的行数少于 sirene_eta,Postgres 仍在 sirene_geo 上构建散列 table(因此导致某些行不匹配)。
当我尝试在子查询 table 内进行限制更新时,它可以工作,但它使用绝对不是 suitable 的嵌套循环策略来更新整个 table。
更新:
没有并发写入 activity。我检查了日志,确实有一个错误:
ERROR: could not write to file "base/pgsql_tmp/pgsql_tmp9264.8256": No space left on device
您的存储设备上 space 已 运行 次。 在启动大 UPDATE
之前,在磁盘上腾出空间(或任何你用作存储的东西)。删除可有可无的文件(与数据库无关)。或者以某种方式缩小你的数据库。
普通的 VACUUM
可能 可以胜任。或者 VACUUM FULL
(阻止并发访问)以积极缩小物理存储。如果您无法阻止,请考虑使用 non-blocking 社区工具之一。参见:
- Optimize Postgres query on timestamp range
VACUUM FULL
最好在 sirene_eta
(目标 table)上 not 无论如何都会重用 UPDATE
中的死元组(在普通 VACUUM
之后)。并确保 VACUUM
没有被长 运行 事务阻塞。参见:
无论您做什么,如果您不希望 all 目标行实际发生变化,请添加 WHERE
条件来过滤空更新(全额付费! )
UPDATE sirene_eta eta
SET longitude = geo.x
, latitude = geo.y
FROM sirene_geo geo
WHERE eta.siret = geo.siret
AND (eta.longitude IS DISTINCT FROM geo.x -- !
OR eta.latitude IS DISTINCT FROM geo.y)
甚至可以通过减少要完成的工作(显着)来解决您的问题。 (事实证明,你的情况并非如此。
参见:
- How do I (or can I) SELECT DISTINCT on multiple columns?