我有大量的表是"插入一次",然后是只读的。 即:在记录的初始INSERT
之后,永远不会有任何UPDATE
或DELETE
语句。因此,表在磁盘上的数据碎片最小。
我现在正在考虑向每个表添加一个needs_action
布尔字段。此字段只会更新一次,并且会缓慢/定期完成。作为 MVCC 的结果,当VACUUM
在UPDATE
之后出现(时间表更慢)时,表变得非常碎片化,因为它清除了最初插入的元组,并且它们随后被新的插入回填。
简而言之:添加这个"始终更新一次"字段将表从设计上的最小碎片变为设计上的高度碎片化。
是否有某种方法可以有效地实现这种单一needs_action
记录标记,以避免由此产生的表碎片?
.
.
.
.
<现在了解一些背景/补充信息...
到目前为止考虑的一些选项...
冒着使这个问题变得庞大(因此被忽视?)的风险,以下是迄今为止已经考虑过的一些选项:
只需将列添加到每个表中,执行
UPDATE
,并且不必担心产生的碎片,直到它实际上被证明是一个问题。- 我意识到这里的优化过早,但随着一些表格变得很大(>1M,甚至>1B),我宁愿提前进行设计。
创建一个独立的跟踪表(对于每个表),仅包含 A) 主表中的 PK 和 B)
needs_action
标志。在跟踪表中使用主表中的AFTER INSERT
触发器创建记录- 这将在主表上保留"仅插入"最小碎片级别...以增加(大量?)前期写入开销为代价 将
- 跟踪表放在单独的架构中也会将功能与核心表整齐地分开
强制
needs_action
字段为 HOT 更新以避免元组复制- 需要
WHERE needs_action = TRUE
索引似乎排除了此选项,但也许还有另一种方法可以快速找到它们?
- 需要
使用表填充因子(50?)为不可避免的
UPDATE
留出空间- 例如:将填充因子设置为 50 为
UPDATE
留出空间,因此将其保留在同一页面中 - 但。。。只有一种
UPDATE
似乎这将使桌子包装分数永远保持在 50% 并占用两倍的存储空间?我还不是 100% 理解这个选项...还在学习。
- 例如:将填充因子设置为 50 为
在主表记录中查找一个特殊/神奇的字段/位,该字段/位可以在不影响 MVCC 的情况下进行微调。
- 这在邮政中似乎不存在。即使有,也需要对其进行索引(或者具有类似于
WHERE needs_action = TRUE
部分索引的其他快速查找机制) - 能够选择性地抑制特定列上的 MVCC 操作似乎在这里会很好(尽管肯定充满了危险)
- 这在邮政中似乎不存在。即使有,也需要对其进行索引(或者具有类似于
将
needs_action
存储在 postgres之外(例如:作为 redis 中的 PK<table_name>:needs_copying
列表)以避免由于 mvcc 而导致的碎片化。- 不过,我担心保持这种原子性。也许在
AFTER INSERT
触发器中使用redis_fdw
(或其他一些 fdw?)可以保持原子性?我需要了解更多关于 fdw 功能的信息...不过,似乎我能找到的所有 FDW 都是只读的。
- 不过,我担心保持这种原子性。也许在
使用背景碎片整理/压缩运行精美的视图,如这篇精彩的文章中所述
- 对于所有表来说似乎有点多。
只需在 postgres 表中跟踪需要复制的 ID/PK
- 只需将需要操作的 ID 作为记录存储到快速惰性表中(例如:无 PK),并在操作完成时
DELETE
记录 - 类似于
RPUSH
到离线 Redis 列表(但绝对是ACID) - 这似乎是目前最好的选择。
- 只需将需要操作的 ID 作为记录存储到快速惰性表中(例如:无 PK),并在操作完成时
还有其他选择需要考虑吗?
更多关于推动此工作的特定用例的信息...
我对如何避免这种碎片的一般情况感兴趣,但这里有更多关于当前用例的信息:
- 读取性能比所有表的写入性能重要得多(但避免疯狂的慢速写入显然是可取的)
- 某些表将达到数百万行。少数可能会达到数十亿行。
SELECT
查询将跨越广泛的表范围(不仅仅是最近的数据),范围可以从单个结果记录到 100k+- 桌子设计可以从头开始...无需担心现有数据
- PostgreSQL 9.6
我只会将填充因子降低到默认值 100 以下。
根据行的大小,使用 80 或 90 之类的值,以便一些新行仍适合块。更新后,旧行可以由下一个事务"修剪"和碎片整理,以便可以重用空间。
值 50 似乎太低了。诚然,这将为同时更新块中的所有行留出空间,但这不是您的用例,对吧?
您可以尝试使用继承的表。此方法不直接支持表的 PK,但可以通过触发器解决。
CREATE TABLE data_parent (a int8, updated bool);
CREATE TABLE data_inserted (CHECK (NOT updated)) INHERITS (data_parent);
CREATE TABLE data_updated (CHECK (updated)) INHERITS (data_parent);
CREATE FUNCTION d_insert () RETURNS TRIGGER AS $$
BEGIN
NEW.updated = false;
INSERT INTO data_inserted VALUES (NEW.*);
RETURN NULL;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER d_insert BEFORE INSERT ON data_parent FOR EACH ROW EXECUTE PROCEDURE d_insert();
CREATE FUNCTION d_update () RETURNS TRIGGER AS $$
BEGIN
NEW.updated = true;
INSERT INTO data_updated VALUES (NEW.*);
DELETE FROM data_inserted WHERE (data_inserted.*) IN (OLD);
RETURN NULL;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER d_update BEFORE INSERT ON data_inserted FOR EACH ROW EXECUTE PROCEDURE d_update();
-- GRANT on d_insert to regular user
-- REVOKE insert / update to regular user on data_inserted/updated
INSERT INTO data_parent (a) VALUES (1);
SELECT * FROM ONLY data_parent;
SELECT * FROM ONLY data_inserted;
SELECT * FROM ONLY data_updated;
INSERT 0 0
a | updated
---+---------
(0 rows)
a | updated
---+---------
1 | f
(1 row)
a | updated
---+---------
(0 rows)
UPDATE data_parent SET updated = true;
SELECT * FROM ONLY data_parent;
SELECT * FROM ONLY data_inserted;
SELECT * FROM ONLY data_updated;
UPDATE 0
a | updated
---+---------
(0 rows)
a | updated
---+---------
(0 rows)
a | updated
---+---------
1 | t
(1 row)
相关内容
- 从pandas数据框的每一行创建一个字符串短语
- 我如何在极地数据框架的所有列上执行一组函数?
- 在R中为双胞胎数据重塑数据框架
- Sklearn不会对连续数据进行回归
- 如何在Pandas中使用过滤后的数据?
- 在Swift/iOS应用中保存数据
- 在函数中过滤pandas数据框架并返回过滤后的数据框架
- 如何使用RabbitMQ仲裁队列进行数据复制
- 使用Python Selenium下拉数据
- SUMIF从只显示过滤数据的表中取出
- 如何使用jQuery json从数据属性中提取"?
- 在pandas数据框中有两列的数据.一列是可以重复的月份,另一列是购买量.每月需要总额
- 在工作表更改时运行宏(即更改工作表,而不是工作表中的数据)
- 使用Azure Redis缓存时如何处理故障转移和陈旧数据
- Vue 以编程方式强制刷新数据,即使使用 v-once
- 如何避免"INSERT once, UPDATE once"表中的数据碎片?
- "Run once"大量数据来插入...本地 VS 网络连接?
- 设置活动模式后,套接字服务器无法接受数据'once'
- 如何使用java/android从Firebase ONCE读取数据
- 无法使用 .once() 函数从 Firebase 数据库中读取数据
最新更新
- 使用ByRef更新记录集字段
- 提取多个XML文件中所有标签之间的文本,并将提取的文本复制到csv文件中
- 在Laravel和Vue之间共享数据的糟糕方式
- 可以在Azure Devops中找到需求文本文件
- 如何在tensorflow keras中引用ground truth变量?
- Json解析并分配给DTO
- 如何通过不重复结果来正确地循环一个范围
- 给出零最优值的AMPL程序
- 再次出现身份验证问题,GCP源存储库使用publickey
- 打印添加到数据库的记录数有问题
- 如何插入一行到一个表在sql是完全相同的另一个表,但只有一个列不同?
- 如何在jupyter notebook中导入两个或多个包?
- 对product类型的访问器进行泛型迭代
- 如何在 react 中"remember"昂贵的递归函数中先前计算的值?
- 在eclipse IDE上使用Tomcat服务器在本地机器上修复eclipse上的编译错误,我能做些什么?
- 在使用reactjs和Material UI上传组件向API发送图像/文件时遇到麻烦
- Firebase 事务方法是否与所有写入操作(包括云函数的写入操作)兼容?
- 违反了竞争条件和主键约束
- 使用REGEX捕获SGM标记之间的文本
- 为什么我无法分配所有填充值?
- 如何以编程方式将"LINK/URL"复制到 android 应用程序中的剪贴板?
- 用sql验证hive中的数据类型decimal(5.2)
- 如何在Redux状态更新时更新功能组件?
- 使用jsonata的日期范围
- clang在混合成员和非成员二进制运算符时是否错误地报告了歧义
- 是否有任何方法将其压缩成一个循环,而不是做几个迭代?
- 无法获得OpenAI生成图像的blob
- c# Httpclient请求在windows 10上工作正常返回403禁止在windows 7(相同的代码)
- 当键值直接从字典分配给变量时函数不工作
- micromamba是如何工作的,什么是"condabin"?
热门标签:
javascript python java c# php android html jquery c++ css ios sql mysql arrays asp.net json python-3.x ruby-on-rails .net sql-server django objective-c excel regex ruby linux ajax iphone xml vba spring asp.net-mvc database wordpress string postgresql wpf windows xcode bash git oracle list vb.net multithreading eclipse algorithm macos powershell visual-studio image forms numpy scala function api selenium