- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
几周前我开始使用 Postgres,最近几天我一直在尝试解决这个问题,结果好坏参半:我有一个表(1000 万行)需要每月更新一次信息存储在其他几个表中。在此更新期间,没有人可以访问数据库,因此没有人正在读取/写入数据。在那段时间我将是唯一的数据库用户。
表 A 有 1000 万行。一栏(重建成本)需要更新。表 B、表 C 和表 D 为表 A 中的每一行重新计算了重建成本(因此表 B、C 和 D 各有 1000 万行)。哪个表用于更新表 A 取决于值,请参见下文。我一直在尝试使用此查询进行此更新:
UPDATE table_A a
SET rebuilding_costs =
CASE
WHEN b.rebuilding_costs BETWEEN 100000 AND 200000 THEN b.rebuilding_costs
WHEN c.rebuilding_costs BETWEEN 200001 AND 400000 THEN c.rebuilding_costs
WHEN d.rebuilding_costs BETWEEN 400001 AND 600000 THEN d.rebuilding_costs
ELSE NULL
END
FROM table_B b
LEFT OUTER JOIN table_C c
ON (b.address = c.address)
LEFT OUTER JOIN table_D d
ON (b.address = d.address)
WHERE a.address = b.address
;
这个查询给出了正确的结果,但是有点慢(25 分钟)。有趣的是:当表 A 有 100 万行(而不是 1000 万行)时,只需要 30 秒。因此,当在具有 1000 万行的表上运行此查询时,我预计该查询将运行 5 分钟,但实际运行了 25 分钟。那是当我尝试在 block 中更新时,所以我将此行添加到 WHERE 子句中的查询:
AND (a.id > 0 AND a.id < 1000000)
a.id 是表 A 的主键。在此示例中,仅更新表 A 的前百万行。但是,需要 3 分钟才能完成。你必须这样做 10 次才能更新所有 1000 万行,所以这将是 30 分钟..
我还试图通过添加以下内容来防止查询使用 UPDATE 不会更改的行来执行查询:
AND a.herbouwwaarde_indicatie IS DISTINCT FROM b.inhoud
AND a.herbouwwaarde_indicatie IS DISTINCT FROM c.inhoud
AND a.herbouwwaarde_indicatie IS DISTINCT FROM d.inhoud
将 fillfactor 设置为 70 和 50 确实有助于提高一点速度,但我无法在 20 分钟内完成。
我还尝试重新创建表 A,例如:
CREATE TABLE table_A_new
AS
SELECT a.address,
CASE
WHEN b.rebuilding_costs BETWEEN 100000 AND 200000 THEN b.rebuilding_costs
WHEN c.rebuilding_costs BETWEEN 200001 AND 400000 THEN c.rebuilding_costs
WHEN d.rebuilding_costs BETWEEN 400001 AND 600000 THEN d.rebuilding_costs
ELSE NULL
END rebuildingcosts
FROM table_A a
LEFT OUTER JOIN table_B b
ON (a.address = b.address)
LEFT OUTER JOIN table_C c
ON (a.address = c.address)
LEFT OUTER JOIN table_D d
ON (a.address = d.address)
;
这非常快(2 分钟)并给出了正确的结果。但是,您必须重新创建整个表。不知何故,这似乎不是很有效(并且占用大量存储空间),这就是我开始使用 UPDATE 查询的原因。
我的问题是:最好的方法是什么?有没有一种方法可以提高 UPDATE 查询的性能,或者最好寻找一种替代方法,例如上面示例中的“创建表”。
虽然我必须使用 Postrgres,但我不能切换到不同的 DBMS。
这是 UPDATE 查询的执行计划(现在表没有 1000 万行,但大约有 6 - 800 万行):
Update on tabel_A a (cost=902288.27..2150690.80 rows=6714762 width=65)
-> Hash Join (cost=902288.27..2150690.80 rows=6714762 width=65)
Hash Cond: ((b.adres)::text = a.adres)"
Join Filter: ((b.rebuilding_costs IS DISTINCT FROM a.rebuilding_costs)
AND (c.rebuilding_costs IS DISTINCT FROM a.rebuilding_costs))
AND (d.rebuilding_costs IS DISTINCT FROM a.rebuilding_costs))
-> Hash Left Join (cost=522527.27..1318059.42 rows=6716471 width=39)
Hash Cond: ((b.adres)::text = (d.adres)::text)
-> Hash Right Join (cost=295916.60..817658.93 rows=6716471 width=29)
Hash Cond: ((c.adres)::text = (b.adres)::text)
-> Seq Scan on Tabel_C c (cost=0.00..240642.35 rows=7600735 width=19)
-> Hash (cost=172605.71..172605.71 rows=6716471 width=19)
-> Seq Scan on tabel_B b (cost=0.00..172605.71 rows=6716471 width=19)
-> Hash (cost=103436.52..103436.52 rows=6709052 width=19)"
-> Seq Scan on tabel D d (cost=0.00..103436.52 rows=6709052 width=19)"
-> Hash (cost=217261.00..217261.00 rows=8000000 width=39)"
-> Seq Scan on Tabel_A a (cost=0.00..217261.00 rows=8000000 width=39)"
这是解释分析输出:
Update on Tabel_A a (cost=902288.27..2150690.80 rows=6714762 width=65) (actual time=2815452.997..2815452.997 rows=0 loops=1)
-> Hash Join (cost=902288.27..2150690.80 rows=6714762 width=65) (actual time=108861.999..214888.780 rows=5252864 loops=1)
Hash Cond: ((b.adres)::text = a.adres)
Join Filter: ((b.rebuilding_costs IS DISTINCT FROM a.rebuilding_costs) AND
(c.rebuilding_costs IS DISTINCT FROM a.rebuilding_costs))
(d.rebuilding_costs IS DISTINCT FROM a.rebuilding_costs))
Rows Removed by Join Filter: 670998
-> Hash Left Join (cost=522527.27..1318059.42 rows=6716471 width=39) (actual time=43138.635..116933.803 rows=6711432 loops=1)"
Hash Cond: ((b.adres)::text = (d.adres)::text)"
-> Hash Right Join (cost=295916.60..817658.93 rows=6716471 width=29) (actual time=34571.750..99040.256 rows=6710550 loops=1)"
Hash Cond: ((c.adres)::text = (b.adres)::text)"
-> Seq Scan on Tabel_C c (cost=0.00..240642.35 rows=7600735 width=19) (actual time=127.080..59703.935 rows=7595083 loops=1)"
-> Hash (cost=172605.71..172605.71 rows=6716471 width=19) (actual time=29925.787..29925.787 rows=6709229 loops=1)"
Buckets: 2048 Batches: 512 Memory Usage: 678kB"
-> Seq Scan on Tabel_B b (cost=0.00..172605.71 rows=6716471 width=19) (actual time=0.017..27245.069 rows=6709229 loops=1)"
-> Hash (cost=103436.52..103436.52 rows=6709052 width=19) (actual time=8566.848..8566.848 rows=6709229 loops=1)"
Buckets: 2048 Batches: 512 Memory Usage: 678kB"
-> Seq Scan on Tabel_D d (cost=0.00..103436.52 rows=6709052 width=19) (actual time=0.009..5970.010 rows=6709229 loops=1)"
-> Hash (cost=217261.00..217261.00 rows=8000000 width=39) (actual time=65721.815..65721.815 rows=8000000 loops=1)"
Buckets: 2048 Batches: 1024 Memory Usage: 612kB"
-> Seq Scan on Tabel_A a (cost=0.00..217261.00 rows=8000000 width=39) (actual time=0.056..55968.171 rows=8000000 loops=1)"
Total runtime: 2815453.549 ms"
表 A、B、C 和 D 的所有索引都在地址列上,该列用于连接。表没有其他索引。表 A 确实有一个主键 (id)。表 B、C 和 D 有 5 到 7 个额外的列未在此过程中使用。
最佳答案
此查询应产生相同的结果,但避免了 CASE
-- EXPLAIN ANALYZE
UPDATE table_a a
SET rebuilding_costs = drie.rebuilding_costs
FROM (
SELECT COALESCE(b.address, c.address, d.address) AS address
, COALESCE(b.rebuilding_costs, c.rebuilding_costs, d.rebuilding_costs)
AS rebuilding_costs
FROM table_b b
FULL OUTER JOIN table_c c ON c.address = b.address
AND c.rebuilding_costs BETWEEN 200001 AND 400000
FULL OUTER JOIN table_D d ON d.address = b.address
AND d.rebuilding_costs BETWEEN 400001 AND 600000
WHERE b.rebuilding_costs BETWEEN 100001 AND 200000
) drie
WHERE a.address = drie.address
AND a.rebuilding_costs <> drie.rebuilding_costs -- Avoid useless updates
;
更新:基于一组链式 CTE 的类似方法:
-- --------------------------------
EXPLAIN ANALYZE
WITH cte_b AS (
SELECT b.address, b.rebuilding_costs
FROM table_b b
WHERE b.rebuilding_costs BETWEEN 100001 AND 200000
)
, cte_c AS (
SELECT c.address , c.rebuilding_costs
FROM table_c c
WHERE c.rebuilding_costs BETWEEN 200001 AND 400000
AND NOT EXISTS (SELECT * FROM cte_b WHERE cte_b.address = c.address)
)
, cte_d AS (
SELECT d.address , d.rebuilding_costs
FROM table_d d
WHERE d.rebuilding_costs BETWEEN 400001 AND 600000
AND NOT EXISTS (SELECT * FROM cte_b WHERE cte_b.address = d.address)
AND NOT EXISTS (SELECT * FROM cte_c WHERE cte_c.address = d.address)
)
, cte_bcd AS (
SELECT cte_b.address, cte_b.rebuilding_costs FROM cte_b
UNION ALL SELECT cte_c.address, cte_c.rebuilding_costs FROM cte_c
UNION ALL SELECT cte_d.address, cte_d.rebuilding_costs FROM cte_d
)
UPDATE table_a a
SET rebuilding_costs = cte_bcd.rebuilding_costs
FROM cte_bcd
WHERE a.address = cte_bcd.address
-- avoid useless updates this way:
AND a.rebuilding_costs <> cte_bcd.rebuilding_costs
-- ,or this way:
-- AND cte_bcd.rebuilding_costs IS DISTINCT FROM a.rebuilding_costs
;
更新 2:CTE 可能很慢,因为它们充当优化障碍。一种快速而肮脏的方法是将 tem 重写为(临时)VIEW,并改为引用它们。这允许优化器将查询的各个部分混入和混出子查询,甚至组合和重用它们。
CREATE TEMP VIEW cte_b AS (
SELECT b.address, b.rebuilding_costs
FROM table_b b
WHERE b.rebuilding_costs BETWEEN 100001 AND 200000
);
CREATE TEMP VIEW cte_c AS (
SELECT c.address , c.rebuilding_costs
FROM table_c c
WHERE c.rebuilding_costs BETWEEN 200001 AND 400000
AND NOT EXISTS (SELECT * FROM cte_b WHERE cte_b.address = c.address)
);
CREATE TEMP VIEW cte_d AS (
SELECT d.address , d.rebuilding_costs
FROM table_d d
WHERE d.rebuilding_costs BETWEEN 400001 AND 600000
AND NOT EXISTS (SELECT * FROM cte_b WHERE cte_b.address = d.address)
AND NOT EXISTS (SELECT * FROM cte_c WHERE cte_c.address = d.address)
);
CREATE TEMP VIEW cte_bcd AS (
SELECT cte_b.address, cte_b.rebuilding_costs FROM cte_b
UNION ALL SELECT cte_c.address, cte_c.rebuilding_costs FROM cte_c
UNION ALL SELECT cte_d.address, cte_d.rebuilding_costs FROM cte_d
);
EXPLAIN -- ANALYZE
UPDATE table_a a
SET rebuilding_costs = cte_bcd.rebuilding_costs
FROM cte_bcd
WHERE a.address = cte_bcd.address
AND a.rebuilding_costs <> cte_bcd.rebuilding_costs -- avoid useless updates
-- AND a.address < 100000
;
关于postgresql - 在 PostgreSQL 中使用多个表进行大更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27144046/
我的 postgresql 有问题,我复制了所有文件,然后将其删除。然后,我安装了新的,问题就解决了。现在可以将旧文件和文件导入新文件吗? 最佳答案 如果它们是相同的主要版本(即 9.0 到 9.0.
我想使用 Postgresql 9.2.2 来存储我的应用程序的数据。我不得不构建一个应该基于数据库级别的触发器(当数据库启动时,这个触发器将被触发并执行。),当 postgresql 服务器启动时是
我已经使用下面的查询从 Postgresql 目录表中获取 Sequence 对象的完整信息 select s.sequence_name, s.start_value, s.minimum_valu
Postgres 版本:9.3.4 我需要执行驻留在远程数据库中的函数。该函数根据给定的参数返回一个统计数据表。 我实际上只是在我的本地数据库中镜像该函数,以使用我的数据库角色和授权来锁定对该函数的访
我在 CentOS 7 上,我正在尝试解决“PG::ConnectionBad: FATAL: Peer authentication failed for user”错误。 所以我已经想出我应该更改
我写了一个触发器函数,在触发器表列名上循环,我从具有不同列的不同表调用该函数。该函数将列名插入到数组中并在它们上循环,以便将值插入到另一个模式和表中。 函数和触发器创建脚本: DROP TRIGGER
PostgreSQL 的默认空闲连接超时是多少,我运行了 show idle_in_transaction_session_timeout 查询并返回了 0,但是值 0 表示此选项被禁用,但我想知道默
我需要将十六进制值存储到数据库表中,谁能推荐我需要用于属性的数据类型? 提前致谢 最佳答案 您可以使用bytea 来存储十六进制格式。更多信息 can be found in the postgres
我有一个具有复合主键的(大)表,由 5 列(a、b、c、d、e)组成。 我想高效地选择具有其中两列 (a + e) 的所有行到给定值。 在 PostgreSQL 中,我需要索引吗?或者数据库会使用主键
在阅读 PostreSQL (13) 文档时,我遇到了 this页面,其中列出了不同日期时间类型的存储大小。 除其他外,它指出: Name Storag
我有两个大整数的巨大表(500 000 000 行)。两列都被单独索引。我正在使用语法批量插入此表: INSERT into table (col1, col2) VALUES(x0, y0), (x
有一台 CentOS7 Linux 机器正在运行(不是由我管理;拥有有限的权限)。 请求在其中设置 PostgreSQL。 刚刚从 CentOS 存储库安装了 PostgreSQL: sudo yum
我在 Ubuntu 18.04 上安装了 Postgresql 10,但不知何故坏了,不会重新启动。我可以重新安装它而不破坏它的数据库,以便我可以再次访问数据库吗? pg_dump 不起作用。 最佳答
我想在 UNIX 中使用 crontab 自动备份 PostgreSQL 数据库。我已经尝试过,但它会创建 0 字节备份。 我的 crontab 条目是: 24 * * * * /home/desk
我已经完成了PG服务器的安装。我希望能够使用 pgAdmin 远程连接到它,但不断收到服务器不听错误。 could not connect to server: Connection refused
Oracle 支持波斯历但需要知道 PostgreSQL 是否支持波斯历? 如果是,那么我们如何在 PostgreSQL 中将默认日历类型设置为 Persian 而不是 Gregorian(在 Ora
假设我们有一个带有表的 SQL 数据库 Person以及访问它的几个应用程序。出于某种原因,我们想修改 Person表以向后不兼容的方式。 保持兼容性的一种潜在解决方案是将表重命名为 User并创建一
我使用 PostgreSQL 中的模式来组织我庞大的会计数据库。每年年底,我都会通过为下一年创建一个新模式来进行协调过程。 新模式的文件是否与旧模式物理分离?或者所有模式一起存储在硬盘上? 这对我来说
我正在尝试使用配置文件中的以下配置参数调整 PostgreSQL 服务器: autovacuum_freeze_max_age = 500000000 autovacuum_max_workers =
我的数据包含数据库列中的表情符号,即 message_text ------- 🙂 😀 Hi 😀 我只想查询包含表情符号的数据的行。在 postgres 中是否有一种简单的方法可以做到这一点?
我是一名优秀的程序员,十分优秀!