Citus 分布式 PostgreSQL 集群 - SQL Reference(创建和修改分布式表 DDL)
创建和分布表
要创建分布式表,您需要首先定义表 schema
。 为此,您可以使用 CREATE TABLE 语句定义一个表,就像使用常规 PostgreSQL
表一样。
CREATE TABLE github_events
(
event_id bigint,
event_type text,
event_public boolean,
repo_id bigint,
payload jsonb,
repo jsonb,
actor jsonb,
org jsonb,
created_at timestamp
);
接下来,您可以使用 create_distributed_table()
函数指定表分布列并创建工作分片。
SELECT create_distributed_table('github_events', 'repo_id');
该函数通知 Citus github_events
表应该分布在 repo_id
列上(通过哈希列值)。该函数还使用 citus.shard_count
和 citus.shard_replication_factor
配置值在工作节点上创建分片。
此示例将创建总共 citus.shard_count
个分片,其中每个分片拥有一部分哈希令牌空间并根据默认的 citus.shard_replication_factor
配置值进行复制。在 worker
上创建的 shard
副本与 coordinator
上的表具有相同的表 schema
、索引和约束定义。 创建副本后,此函数将所有分布式元数据保存在协调器上。
每个创建的分片都分配有一个唯一的分片 ID
,并且它的所有副本都具有相同的分片 ID
。 每个分片在工作节点上表示为一个名为 tablename_shardid
的常规 PostgreSQL
表,其中 tablename
是分布式表的名称,shardid
是分配给该分片的唯一 ID
。 您可以连接到工作节点(worker) postgres
实例以查看或在各个分片上运行命令。
您现在已准备好将数据插入分布式表并对其运行查询。您还可以在文档的 Citus Utility Functions 中了解有关本节中使用的 UDF
的更多信息。
- Citus Utility Functions
引用表
上述方法将表分布到多个水平分片中,但另一种可能是将表分布到单个分片中并将分片复制到每个工作节点。以这种方式分布的表称为引用表
。 它们用于存储集群中多个节点需要频繁访问的数据。
引用表的常见候选包括:
- 较小的表需要与较大的分布式表连接。
- 多租户应用程序中缺少
租户 ID
列或不与租户关联的表。 (在某些情况下,为了减少迁移工作,用户甚至可以选择从与租户关联但当前缺少租户 ID
的表中创建引用表。) - 需要跨多个列的唯一约束并且足够小的表。
例如,假设一个多租户电子商务网站需要为其任何商店的交易计算销售税。 税务信息并非特定于任何租户。 将其合并到共享表中是有意义的。 以美国为中心的引用表可能如下所示:
-- a reference table
CREATE TABLE states (
code char(2) PRIMARY KEY,
full_name text NOT NULL,
general_sales_tax numeric(4,3)
);
-- distribute it to all workers
SELECT create_reference_table('states');
现在,诸如为购物车计算税款之类的查询可以在没有网络开销的情况下加入 states
表,并且可以将外键添加到 state
代码中以进行更好的验证。
除了将表分布为单个复制分片之外,create_reference_table
UDF 将其标记为 Citus
元数据表中的引用表。Citus
自动执行两阶段提交 (2PC) 以修改以这种方式标记的表,这提供了强大的一致性保证。
如果您有一个现有的分布式表,您可以通过运行将其更改为引用表:
SELECT undistribute_table('table_name');
SELECT create_reference_table('table_name');
有关在多租户应用程序中使用引用表的另一个示例,请参阅在租户之间共享数据。
分布协调器数据
如果将现有的 PostgreSQL
数据库转换为 Citus
集群的协调器节点,则其表中的数据可以高效地分布,并且对应用程序的中断最小。
前面描述的 create_distributed_table
函数适用于空表和非空表,对于后者,它会自动在整个集群中分布表行。您将通过消息 NOTICE: Copying data from local table…
来了解它是否这样做,例如:
CREATE TABLE series AS SELECT i FROM generate_series(1,1000000) i;
SELECT create_distributed_table('series', 'i');
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$public.series$$)
create_distributed_table
--------------------------
(1 row)
迁移数据时会阻止对表的写入,一旦函数提交,挂起的写入将作为分布式查询处理。 (如果函数失败,则查询再次变为本地。)读取可以正常继续,一旦函数提交,将变为分布式查询。
分布表 A
和 B
时,其中 A
对 B
有外键,首先需对目标表 B
设置分布键。 当以错误的顺序执行会导致错误:
ERROR: cannot create foreign key constraint
DETAIL: Referenced table must be a distributed table or a reference table.
如果无法以正确的顺序分布,则删除外键,分布表,然后重新创建外键。
表分布后,使用 truncate_local_data_after_distributing_table
函数删除本地数据。Citus
查询无法访问分布式表中剩余的本地数据,并且可能导致协调器上的不相关约束违规。
- truncate_local_data_after_distributing_table
从外部数据库迁移数据时,例如从 Amazon RDS
迁移到 Citus Cloud
,首先通过 create_distributed_table
创建 Citus
分布式表,然后将数据复制到表中。 复制到分布式表中可以避免协调节点上的空间不足。
共置表
共置是一种策略性地划分数据的做法,将相关信息保存在同一台机器上以实现高效的关系操作,同时利用整个数据集的水平可扩展性。 有关更多信息和示例,请参阅表共置。
表在组中是共置(co-location)
的。要手动控制表的 co-location
分配,请使用 create_distributed_table
的可选 colocate_with
参数。 如果您不关心表的 co-location
,请忽略此参数。它默认为 'default'
值,它将表与具有相同分布列类型、分片计数和复制因子的任何其他默认 co-location
表分组。如果要中断或更新此隐式 colocation
,可以使用 update_distributed_table_colocation()
。
-- these tables are implicitly co-located by using the same
-- distribution column type and shard count with the default
-- co-location group
SELECT create_distributed_table('A', 'some_int_col');
SELECT create_distributed_table('B', 'other_int_col');
当新表与其潜在的隐式 co-location
组中的其他表不相关时,请指定 colocated_with => 'none'
。
-- not co-located with other tables
SELECT create_distributed_table('A', 'foo', colocate_with => 'none');
将不相关的表拆分为它们自己的 co-location
组将提高分片再平衡性能,因为同一组中的分片必须一起移动。
- 分片再平衡
当表确实相关时(例如,当它们将被连接时),显式地将它们放在一起是有意义的。 适当的 co-location
所带来的收益比任何重新平衡开销都更重要。
要显式共置多个表,请分布一张表,然后将其他表放入其 co-location
组。 例如:
-- distribute stores
SELECT create_distributed_table('stores', 'store_id');
-- add to the same group as stores
SELECT create_distributed_table('orders', 'store_id', colocate_with => 'stores');
SELECT create_distributed_table('products', 'store_id', colocate_with => 'stores');
有关 co-location
组的信息存储在 pg_dist_colocation 表中,而 pg_dist_partition 显示哪些表分配给了哪些组。
- pg_dist_colocation
- pg_dist_partition
从 Citus 5.x
升级
从 Citus 6.0
开始,我们将 co-location
作为 first-class
的概念,并开始在 pg_dist_colocation
中跟踪表对 co-location
组的分配。由于 Citus 5.x
没有这个概念,因此使用 Citus 5
创建的表没有在元数据中明确标记为位于同一位置,即使这些表在物理上位于同一位置。
由于 Citus
使用托管元数据信息进行查询优化和下推,因此通知 Citus
以前创建的表的此 co-location
变得至关重要。要修复元数据,只需使用 mark_tables_colocated
将表标记为 co-located
:
-- Assume that stores, products and line_items were created in a Citus 5.x database.
-- Put products and line_items into store's co-location group
SELECT mark_tables_colocated('stores', ARRAY['products', 'line_items']);
- mark_tables_colocated
该函数要求表以相同的方法、列类型、分片数和复制方法分布。它不会重新分片或物理移动数据,它只是更新 Citus
元数据。
删除表
您可以使用标准的 PostgreSQL DROP TABLE
命令来删除您的分布式表。与常规表一样,DROP TABLE
删除目标表存在的任何索引、规则、触发器和约束。此外,它还会删除工作节点上的分片并清理它们的元数据。
DROP TABLE github_events;
修改表
Citus
会自动传播多种 DDL
语句,这意味着修改协调器节点上的分布式表也会更新工作器上的分片。其他 DDL
语句需要手动传播,并且禁止某些其他语句,例如那些会修改分布列的语句。尝试运行不符合自动传播条件的 DDL
将引发错误并使协调节点上的表保持不变。
以下是传播的 DDL
语句类别的参考。 请注意,可以使用配置参数启用或禁用自动传播。
添加/修改列
Citus
会自动传播大多数 ALTER TABLE
命令。 添加列或更改其默认值的工作方式与在单机 PostgreSQL
数据库中一样:
-- Adding a column
ALTER TABLE products ADD COLUMN description text;
-- Changing default value
ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;
对现有列进行重大更改(例如重命名或更改其数据类型)也可以。但是,不能更改分布列的数据类型。此列确定表数据如何在 Citus
集群中分布,修改其数据类型将需要移动数据。
尝试这样做会导致错误:
-- assuming store_id is the distribution column
-- for products, and that it has type integer
ALTER TABLE products
ALTER COLUMN store_id TYPE text;
/*
ERROR: cannot execute ALTER TABLE command involving partition column
*/
作为一种解决方法,您可以考虑更改分布列,更新它,然后再改回来。
添加/删除约束
使用 Citus
可以让您继续享受关系数据库的安全性,包括数据库约束(请参阅 PostgreSQL
文档)。由于分布式系统的性质,Citus
不会交叉引用工作节点之间的唯一性约束或引用完整性。
在这些情况下可能会创建外键:
- 在两个本地(非分布式)表之间
- 在两个引用表之间
- 在引用表和本地表之间(默认启用,通过 citus.enable_local_reference_table_foreign_keys (boolean))
- 当键包含分布列时,在两个共置的分布式表之间
- 作为引用表的分布式表
不支持从引用表到分布式表的外键。
Citus
支持从本地到引用表的所有外键引用操作,但不支持反向支持 ON DELETE/UPDATE CASCADE
(引用本地)。
主键和唯一性约束必须包括分布列。 将它们添加到非分布列将产生错误(请参阅无法创建唯一性约束)。
- 无法创建唯一性约束
这个例子展示了如何在分布式表上创建主键和外键:
--
-- Adding a primary key
-- --------------------
-- We'll distribute these tables on the account_id. The ads and clicks
-- tables must use compound keys that include account_id.
ALTER TABLE accounts ADD PRIMARY KEY (id);
ALTER TABLE ads ADD PRIMARY KEY (account_id, id);
ALTER TABLE clicks ADD PRIMARY KEY (account_id, id);
-- Next distribute the tables
SELECT create_distributed_table('accounts', 'id');
SELECT create_distributed_table('ads', 'account_id');
SELECT create_distributed_table('clicks', 'account_id');
--
-- Adding foreign keys
-- -------------------
-- Note that this can happen before or after distribution, as long as
-- there exists a uniqueness constraint on the target column(s) which
-- can only be enforced before distribution.
ALTER TABLE ads ADD CONSTRAINT ads_account_fk
FOREIGN KEY (account_id) REFERENCES accounts (id);
ALTER TABLE clicks ADD CONSTRAINT clicks_ad_fk
FOREIGN KEY (account_id, ad_id) REFERENCES ads (account_id, id);
同样,在唯一性约束中包含分布列:
-- Suppose we want every ad to use a unique image. Notice we can
-- enforce it only per account when we distribute by account id.
ALTER TABLE ads ADD CONSTRAINT ads_unique_image
UNIQUE (account_id, image_url);
非空约束可以应用于任何列(分布与否),因为它们不需要工作节点之间的查找。
ALTER TABLE ads ALTER COLUMN image_url SET NOT NULL;
使用 NOT VALID 约束
在某些情况下,对新行实施约束,同时允许现有的不符合要求的行保持不变是很有用的。Citus
使用 PostgreSQL
的 “NOT VALID”
约束指定,为 CHECK
约束和外键支持此功能。
例如,考虑将用户配置文件存储在引用表中的应用程序。
-- we're using the "text" column type here, but a real application
-- might use "citext" which is available in a postgres contrib module
CREATE TABLE users ( email text PRIMARY KEY );
SELECT create_reference_table('users');
随着时间的推移,想象一些非地址进入表中。
INSERT INTO users VALUES
('foo@example.com'), ('hacker12@aol.com'), ('lol');
我们想验证地址,但 PostgreSQL
通常不允许我们添加对现有行失败的 CHECK
约束。 但是,它确实允许标记为无效的约束:
ALTER TABLE users
ADD CONSTRAINT syntactic_email
CHECK (email ~
'^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'
) NOT VALID;
这成功了,并且新行受到保护。
INSERT INTO users VALUES ('fake');
/*
ERROR: new row for relation "users_102010" violates
check constraint "syntactic_email_102010"
DETAIL: Failing row contains (fake).
*/
稍后,在非高峰时段,数据库管理员可以尝试修复错误行并重新验证约束。
-- later, attempt to validate all rows
ALTER TABLE users
VALIDATE CONSTRAINT syntactic_email;
PostgreSQL
文档在 ALTER TABLE
部分中有更多关于 NOT VALID
和 VALIDATE CONSTRAINT
的信息。
添加/删除索引
Citus
支持添加和删除索引:
-- Adding an index
CREATE INDEX clicked_at_idx ON clicks USING BRIN (clicked_at);
-- Removing an index
DROP INDEX clicked_at_idx;
添加索引需要写锁,这在多租户“记录系统”中可能是不可取的。 为了最大限度地减少应用程序停机时间,请改为同时创建索引。 与标准索引构建相比,此方法需要更多的总工作量,并且需要更长的时间才能完成。 但是,由于它允许在构建索引时继续正常操作,因此此方法对于在生产环境中添加新索引很有用。
-- Adding an index without locking table writes
CREATE INDEX CONCURRENTLY clicked_at_idx ON clicks USING BRIN (clicked_at);
- SQL-CREATEINDEX-CONCURRENTLY
手动修改
目前其他 DDL
命令不会自动传播,但是,您可以手动传播更改。请参阅手动查询传播。
更多
Citus 分布式 PostgreSQL 集群 - SQL Reference(创建和修改分布式表 DDL)的更多相关文章
- Citus 分布式 PostgreSQL 集群 - SQL Reference(摄取、修改数据 DML)
插入数据 要将数据插入分布式表,您可以使用标准 PostgreSQL INSERT 命令.例如,我们从 Github 存档数据集中随机选择两行. INSERT http://www.postgresq ...
- Citus 分布式 PostgreSQL 集群 - SQL Reference(查询分布式表 SQL)
如前几节所述,Citus 是一个扩展,它扩展了最新的 PostgreSQL 以进行分布式执行.这意味着您可以在 Citus 协调器上使用标准 PostgreSQL SELECT 查询进行查询. Cit ...
- Citus 分布式 PostgreSQL 集群 - SQL Reference(查询处理)
一个 Citus 集群由一个 coordinator 实例和多个 worker 实例组成. 数据在 worker 上进行分片和复制,而 coordinator 存储有关这些分片的元数据.向集群发出的所 ...
- Citus 分布式 PostgreSQL 集群 - SQL Reference(手动查询传播)
手动查询传播 当用户发出查询时,Citus coordinator 将其划分为更小的查询片段,其中每个查询片段可以在工作分片上独立运行.这允许 Citus 将每个查询分布在集群中. 但是,将查询划分为 ...
- Citus 分布式 PostgreSQL 集群 - SQL Reference(SQL支持和变通方案)
由于 Citus 通过扩展 PostgreSQL 提供分布式功能,因此它与 PostgreSQL 结构兼容.这意味着用户可以使用丰富且可扩展的 PostgreSQL 生态系统附带的工具和功能来处理使用 ...
- 分布式 PostgreSQL 集群(Citus)官方教程 - 迁移现有应用程序
将现有应用程序迁移到 Citus 有时需要调整 schema 和查询以获得最佳性能. Citus 扩展了 PostgreSQL 的分布式功能,但它不是扩展所有工作负载的直接替代品.高性能 Citus ...
- 分布式 PostgreSQL 集群(Citus),分布式表中的分布列选择最佳实践
确定应用程序类型 在 Citus 集群上运行高效查询要求数据在机器之间正确分布.这因应用程序类型及其查询模式而异. 大致上有两种应用程序在 Citus 上运行良好.数据建模的第一步是确定哪些应用程序类 ...
- 分布式 PostgreSQL 集群(Citus),官方快速入门教程
多租户应用程序 在本教程中,我们将使用示例广告分析数据集来演示如何使用 Citus 来支持您的多租户应用程序. 注意 本教程假设您已经安装并运行了 Citus. 如果您没有运行 Citus,则可以使用 ...
- 在 Kubernetes 上快速测试 Citus 分布式 PostgreSQL 集群(分布式表,共置,引用表,列存储)
准备工作 这里假设,你已经在 k8s 上部署好了基于 Citus 扩展的分布式 PostgreSQL 集群. 查看 Citus 集群(kubectl get po -n citus),1 个 Coor ...
随机推荐
- 大厂偏爱的Agent技术究竟是个啥
搜索关注微信公众号"捉虫大师",后端技术分享,架构设计.性能优化.源码阅读.问题排查.踩坑实践. hello大家好,我是小楼,今天给大家分享一个关于Agent技术的话题,也是后端启 ...
- 【剑指 Offer II 001. 整数除法】同leedcode 29.两数相除
剑指 Offer II 001. 整数除法 解题思路 在计算的时候将负数转化为正数,对于32位整数而言,最小的正数是-2^31, 将其转化为正数是2^31,导致溢出.因此将正数转化为负数不会导致溢出. ...
- 【C#】COM线程模型-套间 ApartmentState
线程模式是微软的COM基础中的极其重要的概念.一定要吃透!初始一个STA套间实际上是相当于开了一个消息窗口,所有调用经此窗口过程调度到组件内. [STAThread] 可以理解成CoInitializ ...
- 解决 “Project ERROR: Unknown module(s) in QT: webengine”以及“Your MaintenanceTool appears to be older than 3.0.2. .” 的办法
1.环境 Windows10,Qt5.8.0 2.问题描述 需要使用到WebEngineView组件,在工程.pro中增加webengine后,Qt Creator应用程序输出中打印了 Project ...
- linux多进/线程编程(1)—— 基础概念(PCB、MMU、进程状态)
学习大概就是不断迭代.重构的过程,不复习的学习是不负责任的,亦是无用的. 本系列博客主要作为个人记录,主要是贴图和代码,不做详细解释,以后有时间可能会重写:从下一篇开始上代码,代码可以运行是对自己的最 ...
- python实用脚本-定时导出数据库中的数据并且发送数据到邮箱
1.发送邮件脚本 #coding=utf-8 import smtplib from email.header import Header from email.mime.text import MI ...
- Python——条件语句及其循环
条件语句及其循环 一. 条件语句 在条件语句中可以使用以下所有的运算符: 算术运算符:+.-.*././/.%.** 关系运算符:>.<.==.<=.>=.!= 测试运算符:i ...
- JZ-006-旋转数组的最小数字
旋转数组的最小数字 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. NOTE:给出的所有元素都大于0,若数组 ...
- LeetCode-048-旋转图像
旋转图像 题目描述:给定一个 n × n 的二维矩阵 matrix 表示一个图像.请你将图像顺时针旋转 90 度. 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵.请不要 使用另一个矩 ...
- think php 公共目录common.php json封装
<?php function getJsonData($code,$massage,$data){ $result=[ 'code'=>$code, 'massage'=>$mass ...