选择正确的分区规则

2024-01-16

我正在设置一个新的 PostgreSQL 9 数据库,其中将包含数百万(甚至数十亿)行。所以我决定使用 PostgreSQL 继承来分区数据。

我创建了一个像这样的主表(例如简化的):

CREATE TABLE mytable
(
  user_id integer,
  year integer,
  CONSTRAINT pk_mytable PRIMARY KEY (user_id, year)
);

和10个分区表:

CREATE TABLE mytable_0 () INHERITS (mytable);
CREATE TABLE mytable_1 () INHERITS (mytable);
...
CREATE TABLE mytable_9 () INHERITS (mytable);

我知道行将始终使用唯一的 user_id 条件从应用程序访问。 因此,我想使用基于 user_id 的规则将数据“相当”均匀地分布在 10 个表中。

为了调整主表上的查询,我的第一个想法是使用模数检查约束:

ALTER TABLE mytable_0 ADD CONSTRAINT mytable_user_id_check CHECK (user_id % 10 = 0);
ALTER TABLE mytable_1 ADD CONSTRAINT mytable_user_id_check CHECK (user_id % 10 = 1);
...

问题是,当我使用 user_id 条件查询主表“mytable”时,PostgreSQL 分析器会检查所有表,并且不会从检查约束中受益:

EXPLAIN SELECT * FROM mytable WHERE user_id = 12345;

"Result  (cost=0.00..152.69 rows=64 width=36)"
"  ->  Append  (cost=0.00..152.69 rows=64 width=36)"
"        ->  Seq Scan on mytable  (cost=0.00..25.38 rows=6 width=36)"
"              Filter: (user_id = 12345)"
"        ->  Seq Scan on mytable_0 mytable  (cost=0.00..1.29 rows=1 width=36)"
"              Filter: (user_id = 12345)"
"        ->  Seq Scan on mytable_1 mytable  (cost=0.00..1.52 rows=1 width=36)"
"              Filter: (user_id = 12345)"
...
"        ->  Seq Scan on mytable_9 mytable  (cost=0.00..1.52 rows=1 width=36)"
"              Filter: (user_id = 12345)"

而如果我使用像这样的经典检查约束(以及匹配该规则的重新分区):

ALTER TABLE mytable_0 ADD CONSTRAINT mytable_user_id_check CHECK (user_id BETWEEN 1 AND 10000);
ALTER TABLE mytable_1 ADD CONSTRAINT mytable_user_id_check CHECK (user_id BETWEEN 10001 AND 20000);
...

它将仅扫描符合条件的表(本例中为 mytable 和 mytable_1):

"Result  (cost=0.00..152.69 rows=64 width=36)"
"  ->  Append  (cost=0.00..152.69 rows=64 width=36)"
"        ->  Seq Scan on mytable  (cost=0.00..25.38 rows=6 width=36)"
"              Filter: (user_id = 12345)"
"        ->  Seq Scan on mytable_1 mytable  (cost=0.00..1.52 rows=1 width=36)"
"              Filter: (user_id = 12345)"

但是使用这种检查约束很难维护,因为表中填充的用户范围会随着时间的推移而变化。首先是数千,在不久的将来可能是数百万甚至更多......

我可以使用什么规则将数据均匀地分区到 10 个可以受益于检查约束的表上,以便主表上的 SELECT 只扫描正确的表...?

Thanks,

Nico


限制在于规划器而不是分区本身。手册中对此进行了详细介绍:

http://www.postgresql.org/docs/9.1/static/ddl-partitioning.html http://www.postgresql.org/docs/9.1/static/ddl-partitioning.html

您提到的有两件事需要考虑。

首先,您说所有访问都将通过主键进行。这意味着您不会从分区中获得任何性能优势(至少在正常使用中不会)。每个分区上的索引会更小,但是PG需要选择先检查哪个分区。如果您需要重新索引或类似的操作,您将受益匪浅 - 您可以分别为每个分区重新索引。

其次,你说你可能有数千到数十亿行。这让我得出两个结论:

  1. 也许留到以后再做决定吧。等到需要分区时。
  2. 您不太可能需要恰好 10 个包含 2000 行和 20 亿行的分区。

如果要分区,请按范围进行分区 - 例如每个分区 100,000 行或 100 万行。添加一个 cron 作业来检查使用的最大 ID,并根据需要创建一个新分区(也许每天一次)。

但就我个人而言,我会保留它直到我需要它为止。如果您认为稍后更有可能需要它们,则可以将单个分区作为包罗万象的东西。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

选择正确的分区规则 的相关文章

  • SQL where 连接集必须包含所有值,但可以包含更多值

    我有三张桌子offers sports和连接表offers sports class Offer lt ActiveRecord Base has and belongs to many sports end class Sport lt
  • 如何覆盖 Ruby Ranges 的 .. 和 ... 运算符以接受 Float::INFINITY?

    我想覆盖 and Ruby 中的运算符Range 原因是 我正在处理数据库中的无限日期范围 如果你拉一个infinty从 Postgres 中取出日期时间 你会得到一个Float INFINITY在红宝石中 问题是 我无法使用Float I
  • JSON 值的模式匹配

    运行 Postgres 12 5 的本地 docker 实例 4MBwork mem 我正在实施这个图案 https dba stackexchange com q 108447 3684搜索 json 中的任意字段 目标是搜索并返回 JS
  • 多个连接到同一个表

    我有这组表格和数据 CREATE TABLE item id INT PRIMARY KEY name VARCHAR CREATE TABLE property id INT PRIMARY KEY name VARCHAR CREATE
  • 如何以编程方式使用包含多列的 where-in 子句执行 PostgreSQL 查询?

    我的查询是这样的 select from plat customs complex where code t code s in 01013090 10 01029010 90 它在 psql 控制台中运行良好 我的问题是如何在客户端代码中
  • 如何从 postgresql 函数或触发器发送一些 http 请求

    我需要通过 http 协议 GET 或 POST 请求 从函数或触发器发送数据 是否可以 您可以尝试用 PL Python 编写触发器并使用 urllib2 进行 POST
  • 返回年份数组作为年份范围

    我正在尝试查询一个包含以下内容的表character varying 年份列 并将这些年份作为逗号分隔的年份范围字符串返回 年份范围将由数组中存在的连续年份确定 不连续的年份 年份范围应以逗号分隔 数据类型的原因是character var
  • postgresql中数组的区别

    我有两个数组 1 2 3 4 7 6 and 2 3 7 在 PostgreSQL 中可能有共同的元素 我想做的是从第一个数组中排除第二个数组中存在的所有元素 到目前为止我已经取得了以下成果 SELECT array SELECT unne
  • Postgres 中 -Infinity 和 Infinity 的适当值

    在一种情况下 我们必须在 Postgres DB 中存储 无穷大和 无穷大的值 应该考虑什么合适的值 如果没有 请建议最合适的替代方案 你实际上可以使用 infinity and infinity for FLOAT4 and FLOAT8
  • PostgreSQL 仅当列存在时才重命名该列

    我在中找不到PostgreSQL 文档 https www postgresql org docs 12 sql altertable html如果有办法运行 ALTER TABLE tablename RENAME COLUMN IF E
  • 计算包含字母/数字的行数

    我想要实现的目标很简单 但是解释起来有点困难 我不知道在 postgres 中这是否真的可能 我处于相当基础的水平 SELECT FROM WHERE LEFT JOIN ON HAVING 等等基本的东西 我正在尝试计算包含特定字母 数字
  • 手动更改postgresql中查询的执行计划?

    是否可以在postgresql中手动更改执行计划的操作顺序 例如 如果我总是想在过滤之前进行排序操作 尽管这在 postgresql 的正常使用中没有意义 是否可以通过例如手动强制执行该操作改变运营的内部成本 如果我实现自己的功能呢 是否可
  • 唯一约束与唯一索引?

    之间有区别吗 CREATE TABLE p product no integer name text UNIQUE price numeric and CREATE TABLE p product no integer name text
  • PostgreSQL 在递归查询中找到所有可能的组合(排列)

    输入是一个长度为 n 的数组 我需要生成数组元素的所有可能组合 包括输入数组中元素较少的所有组合 IN j A B C OUT k A AB AC ABC ACB B BA BC BAC BCA 随着重复 所以AB BA 我尝试过这样的事情
  • pg_dump 没有对象注释?

    有没有办法执行 pg dump 并排除表 视图和列的 COMMENT ON 我广泛使用 COMMENT ON 命令来描述所有对象 并且经常在其中包含换行符以获得更清晰的描述 例如 COMMENT ON TABLE mytable1 IS M
  • 在 PostgreSql 中计算百分比

    例如我有一个这样的表 string adm A 2 A 1 B 2 A 1 C 1 A 2 通过 SQL 查询 我想要这样的结果 string perc adm A 50 B 100 C 0 我想要每个字符串中数字 2 出现的百分比 我可以
  • SQL 错误:ORA-14006:无效的分区名称

    我正在尝试使用以下 SQL 语句对 Oracle 12C R1 中的现有表进行分区 ALTER TABLE TABLE NAME MODIFY PARTITION BY RANGE DATE COLUMN NAME INTERVAL NUM
  • 带有可变 WHERE 子句的批量 UPDATE 表

    我有一堆值对 foo1 bar1 foo2 bar2 我想做一堆更新 将 foo 列设置为 foo1 其中 bar 列为 bar1 我正在使用 psycopg2 在 Python 中执行此操作 我可以executemany与查询UPDATE
  • 为 PostgreSQL 查询选择正确的索引

    简化表 CREATE TABLE products product no integer PRIMARY KEY sales integer status varchar 16 category varchar 16 CREATE INDE
  • TimescaleDB 查询选择列值较上一行发生更改的行

    最近刚刚开始使用 TimescaleDB 和 Postgres 来处理大多数数据请求 然而 我遇到了一个问题 即我对时间序列数据的请求效率极低 它是一个可以是任意时间长度 具有特定整数值的数据系列 大多数时候 除非出现异常 否则该值将是相同

随机推荐