PostgreSQL 学习手册(模式 Schema)
一个数据库包含一个或多个命名的模式,模式又包含表。模式还包含其它命名的对象,包括数据类型、函数,以及操作符。同一个 对象名可以在不同的模式里使用而不会导致冲突; 比如,schema1 和 myschema 都可以包含叫做 mytable 的表。和数据库不同, 模式不是严格分离的:一个用户可以访问他所连接的数据库中的任意模式中的对象,只要他有权限。 我们需要模式有以下几个主要原因:
1). 允许多个用户使用一个数据库而不会干扰其它用户。
2). 把数据库对象组织成逻辑组,让它们更便于管理。
3). 第三方的应用可以放在不同的模式中,这样它们就不会和其它对象的名字冲突。
1. 创建模式:
CREATE SCHEMA myschema;
通过以上命令可以创建名字为 myschema 的模式,在该模式被创建后,其便可拥有自己的一组逻辑对象,如表、视图和函数等。
2. public 模式:
在介绍后面的内容之前,这里我们需要先解释一下 public 模式。每当我们创建一个新的数据库时,PostgreSQL 都会为我们自动 创建该模式。当登录到该数据库时,如果没有特殊的指定,我们将以该模式(public)的形式操作各种数据对象,如:
CREATE TABLE products ( ... ) 等同于 CREATE TABLE public.products ( ... )
3. 权限: 缺省时,用户看不到模式中不属于他们所有的对象。为了让他们看得见,模式的所有者需要在模式上赋予 USAGE 权限。为了让用 户使用模式中的对象,我们可能需要赋予额外的权限,只要是适合该对象的。PostgreSQL 根据不同的对象提供了不同的权限类型, 如:
GRANT ALL ON SCHEMA myschema TO public;
上面的 ALL 关键字将包含 CREATE 和 USAGE 两种权限。如果 public 模式拥有了 myschema 模式的 CREATE 权限,那么登 录到该模式的用户将可以在 myschema 模式中创建任意对象,如:
CREATE TABLE myschema.products (
product_no integer,
name text,
price numeric CHECK (price > 0),
);
在为模式下的所有表赋予权限时,需要将权限拆分为各种不同的表操作,如:
ALTER DEFAULT PRIVILEGES IN SCHEMA myschema
GRANT INSERT, SELECT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON TABLES TO public;
在为模式下的所有 Sequence 序列对象赋予权限时,需要将权限拆分为各种不同的 Sequence 操作,如:
ALTER DEFAULT PRIVILEGES IN SCHEMA myschema
GRANT SELECT, UPDATE, USAGE ON SEQUENCES TO public;
在为模式下的所有函数赋予权限时,仅考虑执行权限,如:
ALTER DEFAULT PRIVILEGES IN SCHEMA myschema
GRANT EXECUTE ON FUNCTIONS TO public;
可以看出,通过以上方式在 public 模式下为 myschema 模式创建各种对象是极为不方便的。下面我们将要介绍另外一种方式, 即通过 role 对象,直接登录并关联到 myschema 对象,之后便可以在 myschema 模式下直接创建各种所需的对象了。 CREATE ROLE myschema LOGIN PASSWORD '123456'; -创建了和该模式关联的角色对象。
CREATE SCHEMA myschema AUTHORIZATION myschema; -将该模式关联 到指定的角色,模式名和角色名可以不相 等。
在 Linux Shell 下,以 myschema 的角色登录到数据库 MyTest,在密码输入正确后将成功登录到该数据库。
/> psql -d MyTest -U myschema
Password:
MyTest=> CREATE TABLE test(i integer);
CREATE TABLE
MyTest=> \d -查看该模式下,以及该模式有权限看到的 tables信息列表。
List of relations
Schema | Name | Type | Owner
------------+---------+------+----------
myschema | test | table | myschema
(1 rows)
4. 删除模式:
DROP SCHEMA myschema;
如果要删除模式及其所有对象,请使用级联删除:
DROP SCHEMA myschema CASCADE;
5. 模式搜索路径:
我们在使用一个数据库对象时可以使用它的全称来定位对象,然而这样做往往也是非常繁琐的,每次都不得不键入 owner_name.object_name。PostgreSQL 中提供了模式搜索路径,这有些类似于 Linux 中的$PATH 环境变量,当我们执行一个 Shell 命令时,只有该命令位于$PATH 的目录列表中,我们才可以通过命令名直接执行,否则就需要输入它的全路径名。PostgreSQL 同样也通过查找一个搜索路径来判断一个表究竟是哪个表,这个路径是一个需要查找的模式列表。在搜索路径里找到的第一个表将被 当作选定的表。如果在搜索路径中 没有匹配表,那么就报告一个错误,即使匹配表的名字在数据库其它的模式中存在也如此。 在搜索路径中的第一个模式叫做当前模式。除了是搜索的第一个模式之外,它还是在 CREATE TABLE 没有声明模式名的时候,新 建表所属于的模式。要显示当前搜索路径,使用下面的命令:
MyTest=> SHOW search_path;
search_path
----------------
"$user",public
(1 row)
可以将新模式加入到搜索路径中,如:
SET search_path TO myschema,public;
为搜索路径设置指定的模式,如:
SET search_path TO myschema; -当前搜索路径中将只是包含 myschema 一种模式。
PostgreSQL 学习手册(表的继承和分区)
一、表的继承:
这个概念对于很多已经熟悉其他数据库编程的开发人员而言会多少有些陌生,然而它的实现方式和设计原理却是简单易懂,现在就 让我们从一个简单的例子开始吧。
1. 第一个继承表:
CREATE TABLE cities ( -父表
name text,
population float,
altitude int
);
CREATE TABLE capitals ( -子表
state char(2)
) INHERITS (cities);
capitals 表继承自 cities 表的所有属性。在 PostgreSQL 里,一个表可以从零个或多个其它表中继承属性,而且一个查询既可以 引用父表中的所有行,也可以引用父表的所有行加上其所有子表的行,其中后者是缺省行为。
MyTest=# INSERT INTO cities values('Las Vegas', 1.53, 2174); -插入父表
INSERT 0 1 MyTest=# INSERT INTO cities values('Mariposa',3.30,1953); -插入父表
INSERT 0 1 MyTest=# INSERT INTO capitals values('Madison',4.34,845,'WI');-插入子表
INSERT 0 1 MyTest=# SELECT name, altitude FROM cities WHERE altitude > 500; -父表和子表的数据均被取出。
name | altitude
-----------+----------
Las Vegas | 2174
Mariposa | 1953
Madison | 845
(3 rows)
MyTest=# SELECT name, altitude FROM capitals WHERE altitude > 500; -只有子表的数据被取出。
name | altitude
---------+----------
Madison | 845
(1 row)
如果希望只从父表中提取数据,则需要在 SQL 中加入 ONLY 关键字,如:
MyTest=# SELECT name,altitude FROM ONLY cities WHERE altitude > 500;
name | altitude
-----------+----------
Las Vegas | 2174
Mariposa | 1953
(2 rows)
上例中 cities 前面的"ONLY"关键字表示该查询应该只对 cities 进行查找而不包括继承级别低于 cities 的表。许多我们已经讨论过 的命令--SELECT,UPDATE 和 DELETE--支持这个"ONLY"符号。 在执行整表数据删除时,如果直接 truncate 父表,此时父表和其所有子表的数据均被删除,如果只是 truncate 子表,那么其父 表的数据将不会变化,只是子表中的数据被清空。 MyTest=# TRUNCATE TABLE cities; -父表和子表的数据均被删除。
TRUNCATE TABLE
MyTest=# SELECT * FROM capitals;
name | population | altitude | state
------+------------+----------+-------
(0 rows)
2. 确定数据来源: 有时候你可能想知道某条记录来自哪个表。在每个表里我们都有一个系统隐含字段 tableoid,它可以告诉你表的来源:
MyTest=# SELECT tableoid, name, altitude FROM cities WHERE altitude > 500;
tableoid | name | altitude
----------+-----------+----------
16532 | Las Vegas | 2174
16532 | Mariposa | 1953 1
6538 | Madison | 845
(3 rows)
以上的结果只是给出了 tableoid,仅仅通过该值,我们还是无法看出实际的表名。要完成此操作,我们就需要和系统表 pg_class 进行关联,以通过 tableoid 字段从该表中提取实际的表名,见以下查询:
MyTest=# SELECT p.relname, c.name, c.altitude FROM cities c,pg_class p WHERE c.altitude > 500 and c.tableoid = p.oid; relname | name | altitude
----------+-----------+----------
cities | Las Vegas | 2174
cities | Mariposa | 1953
capitals | Madison | 845
(3 rows)
3. 数据插入的注意事项:
继承并不自动从 INSERT 或者 COPY 中向继承级别中的其它表填充数据。在我们的例子里,下面的 INSERT 语句不会成功: INSERT INTO cities (name, population, altitude, state) VALUES ('New York', NULL, NULL, 'NY');
我们可能希望数据被传递到 capitals 表里面去,但是这是不会发生的:INSERT 总是插入明确声明的那个表。
4. 多表继承: 一个表可以从多个父表继承,这种情况下它拥有父表们的字段的总和。子表中任意定义的字段也会加入其中。如果同一个字段名出 现在多个父表中,或者同时出现在父表和子表的定义里,那么这些字段就会被"融合",这样在子表里面就只有一个这样的字段。要想 融合,字段必须是相同的数据类型,否则就会抛出一个错误。融合的字段将会拥有它所继承的字段的所有约束。
CREATE TABLE parent1 (FirstCol integer);
CREATE TABLE parent2 (FirstCol integer, SecondCol varchar(20));
CREATE TABLE parent3 (FirstCol varchar(200)); -子表 child1 将同时继承自 parent1 和 parent2 表,而这两个父表中均包含 integer 类型的 FirstCol 字段,因此 child1 可以创 建成功。
CREATE TABLE child1 (MyCol timestamp) INHERITS (parent1,parent2); -子表 child2 将不会创建成功,因为其两个父表中均包含 FirstCol 字段,但是它们的类型不相同。
CREATE TABLE child2 (MyCol timestamp) INHERITS (parent1,parent3); -子表 child3 同样不会创建成功,因为它和其父表均包含 FirstCol 字段,但是它们的类型不相同。
CREATE TABLE child3 (FirstCol varchar(20)) INHERITS(parent1);
5. 继承和权限: 表访问权限并不会自动继承。因此,一个试图访问父表的用户还必须具有访问它的所有子表的权限,或者使用 ONLY 关键字只从 父表中提取数据。在向现有的继承层次添加新的子表的时候,请注意给它赋予所有权限。 继承特性的一个严重的局限性是索引(包括唯一约束)和外键约束只施用于单个表,而不包括它们的继承的子表。这一点不管对引用 表还是被引用表都是事实,因此在上面的例子里,如果我们声明 cities.name 为 UNIQUE 或者是一个 PRIMARY KEY,那么也不会 阻止 capitals 表拥有重复了名字的 cities 数据行。 并且这些重复的行缺省时在查询 cities 表的时候会显示出来。实际上,缺省时 capitals 将完全没有唯一约束,因此可能包含带有同名的多个行。你应该给 capitals 增加唯一约束,但是这样做也不会避免与 cities 的重复。类似,如果我们声明 cities.name REFERENCES 某些其它的表,这个约束不会自动广播到 capitals。在这种条件下,你可 以通过手工给 capitals 增加同样的 REFERENCES 约束来做到这点。
二、分区表:
1. 概述分区表: 分区的意思是把逻辑上的一个大表分割成物理上的几块儿,分区可以提供若干好处:
1). 某些类型的查询性能可以得到极大提升。
2). 更新的性能也可以得到提升,因为表的每块的索引要比在整个数据集上的索引要小。如果索引不能全部放在内存里,那么在索 引上的读和写都会产生更多的磁盘访问。
3). 批量删除可以用简单地删除某个分区来实现。
4). 将很少用的数据可以移动到便宜的、慢一些地存储介质上。假设当前的数据库并不支持分区表,而我们的应用所需处理的数据量也非常大,对于这种应用场景,我们不得不人为的将该大表按 照一定的规则,手工拆分成多个小表,让每个小表包含不同区间的数据。这样一来,我们就必须在数据插入、更新、删除和查询之前,先计算本次的指令需要操作的小表。对于有些查询而言,由于查询区间可能会跨越多个小表,这样我们又不得不将多个小表的查询结 果进行 union 操作,以合并来自多个表的数据,并最终形成一个结果集返回给客户端。可见,如果我们正在使用的数据库不支持分区 表,那么在适合其应用的场景下,我们就需要做很多额外的编程工作以弥补这一缺失。然而需要说明的是,尽管功能可以勉强应付, 但是性能却和分区表无法相提并论。
目前 PostgreSQL 支持的分区形式主要为以下两种:
1). 范围分区: 表被一个或者多个键字字段分区成"范围",在这些范围之间没有重叠的数值分布到不同的分区里。比如,我们可以 为特定的商业对象根据数据范围分区,或者根据标识符范围分区。
2). 列表分区: 表是通过明确地列出每个分区里应该出现那些键字值实现的。
2. 实现分区:
1). 创建"主表",所有分区都从它继承。
CREATE TABLE measurement ( -主表
city_id int NOT NULL,
logdate date NOT NULL,
peaktemp int, );
2). 创建几个"子"表,每个都从主表上继承。通常,这些"子"表将不会再增加任何字段。我们将把子表称作分区,尽管它们就是普 通的 PostgreSQL 表。
CREATE TABLE measurement_yy04mm02 ( ) INHERITS (measurement);
CREATE TABLE measurement_yy04mm03 ( ) INHERITS (measurement);
...
CREATE TABLE measurement_yy05mm11 ( ) INHERITS (measurement);
CREATE TABLE measurement_yy05mm12 ( ) INHERITS (measurement);
CREATE TABLE measurement_yy06mm01 ( ) INHERITS (measurement);
上面创建的子表,均已年、月的形式进行范围划分,不同年月的数据将归属到不同的子表内。这样的实现方式对于清空分区数据而 言将极为方便和高效,即直接执行 DROP TABLE 语句删除相应的子表,之后在根据实际的应用考虑是否重建该子表(分区)。相比于 直接 DROP 子表,PostgreSQL 还提供了另外一种更为方便的方式来管理子表:
ALTER TABLE measurement_yy06mm01 NO INHERIT measurement;
和直接 DROP 相比,该方式仅仅是使子表脱离了原有的主表,而存储在子表中的数据仍然可以得到访问,因为此时该表已经被还 原成一个普通的数据表了。这样对于数据库的 DBA 来说,就可以在此时对该表进行必要的维护操作,如数据清理、归档等,在完成诸 多例行性的操作之后,就可以考虑是直接删除该表(DROP TABLE),还是先清空该表的数据(TRUNCATE TABLE),之后再让该表重 新继承主表,如: ALTER TABLE measurement_yy06mm01 INHERIT measurement;
3). 给分区表增加约束,定义每个分区允许的健值。同时需要注意的是,定义的约束要确保在不同的分区里不会有相同的键值。因 此,我们需要将上面"子"表的定义修改为以下形式:
CREATE TABLE measurement_yy04mm02 (
CHECK ( logdate >= DATE '2004-02-01' AND logdate < DATE '2004-03-01')
) INHERITS (measurement);
CREATE TABLE measurement_yy04mm03 (
CHECK (logdate >= DATE '2004-03-01' AND logdate < DATE '2004-04-01')
) INHERITS (measurement);
...
CREATE TABLE measurement_yy05mm11 (
CHECK (logdate >= DATE '2005-11-01' AND logdate < DATE '2005-12-01')
) INHERITS (measurement);
CREATE TABLE measurement_yy05mm12 (
CHECK (logdate >= DATE '2005-12-01' AND logdate < DATE '2006-01-01')
) INHERITS (measurement);
CREATE TABLE measurement_yy06mm01 (
CHECK (logdate >= DATE '2006-01-01' AND logdate < DATE '2006-02-01')
) INHERITS (measurement);
4). 尽可能基于键值创建索引。如果需要,我们也同样可以为子表中的其它字段创建索引。
CREATE INDEX measurement_yy04mm02_logdate ON measurement_yy04mm02 (logdate);
CREATE INDEX measurement_yy04mm03_logdate ON measurement_yy04mm03 (logdate);
...
CREATE INDEX measurement_yy05mm11_logdate ON measurement_yy05mm11 (logdate);
CREATE INDEX measurement_yy05mm12_logdate ON measurement_yy05mm12 (logdate);
CREATE INDEX measurement_yy06mm01_logdate ON measurement_yy06mm01 (logdate);
5). 定义一个规则或者触发器,把对主表的修改重定向到适当的分区表。
如果数据只进入最新的分区,我们可以设置一个非常简单的规则来插入数据。我们必须每个月都重新定义这个规则,即修改重定向 插入的子表名,这样它总是指向当前分区。
CREATE OR REPLACE RULE measurement_current_partition AS ON INSERT TO measurement DO INSTEAD INSERT INTO measurement_yy06mm01 VALUES (NEW.city_id, NEW.logdate, NEW.peaktemp);
其中 NEW 是关键字,表示新数据字段的集合。这里可以通过点(.)操作符来获取集合中的每一个字段。
我们可能想插入数据并且想让服务器自动定位应该向哪个分区插入数据。我们可以用像下面这样的更复杂的规则集来实现这个目标。
CREATE RULE measurement_insert_yy04mm02 AS
ON INSERT TO measurement WHERE (logdate >= DATE '2004-02-01' AND logdate < DATE '2004-03-01')
DO INSTEAD
INSERT INTO measurement_yy04mm02 VALUES (NEW.city_id, NEW.logdate, NEW.peaktemp);
...
CREATE RULE measurement_insert_yy05mm12 AS
ON INSERT TO measurement WHERE (logdate >= DATE '2005-12-01' AND logdate < DATE '2006-01-01')
DO INSTEAD
INSERT INTO measurement_yy05mm12 VALUES (NEW.city_id, NEW.logdate, NEW.peaktemp);
CREATE RULE measurement_insert_yy06mm01 AS
ON INSERT TO measurement WHERE (logdate >= DATE '2006-01-01' AND logdate < DATE '2006-02-01')
DO INSTEAD
INSERT INTO measurement_yy06mm01 VALUES (NEW.city_id, NEW.logdate, NEW.peaktemp);
请注意每个规则里面的 WHERE 子句正好匹配其分区的 CHECK 约束。 可以看出,一个复杂的分区方案可能要求相当多的 DDL。在上面的例子里我们需要每个月创建一次新分区,因此写一个脚本自动 生成需要的 DDL 是明智的。除此之外,我们还不难推断出,分区表对于新数据的批量插入操作有一定的抑制,这一点在 Oracle 中也 同样如此。 除了上面介绍的通过 Rule 的方式重定向主表的数据到各个子表,我们还可以通过触发器的方式来完成此操作,相比于基于 Rule 的重定向方法,基于触发器的方式可能会带来更好的插入效率,特别是针对非批量插入的情况。然而对于批量插入而言,由于 Rule 的额外开销是基于表的,而不是基于行的,因此效果会好于触发器方式。另一个需要注意的是,copy 操作将会忽略 Rules,如果我们 想要通过 COPY 方法来插入数据,你只能将数据直接 copy 到正确的子表,而不是主表。这种限制对于触发器来说是不会造成任何问 题的。基于 Rule 的重定向方式还存在另外一个问题,就是当插入的数据不在任何子表的约束中时,PostgreSQL 也不会报错,而是 将数据直接保留在主表中。
6). 添加新分区: 这里将介绍两种添加新分区的方式,第一种方法简单且直观,我们只是创建新的子表,同时为其定义新的检查约束,如:
CREATE TABLE measurement_y2008m02 (
CHECK ( logdate >= DATE '2008-02-01' AND logdate < DATE '2008-03-01' )
) INHERITS (measurement);
第二种方法的创建步骤相对繁琐,但更为灵活和实用。见以下四步:
/* 创建一个独立的数据表 (measurement_y2008m02) ,该表在创建时以将来的主表 (measurement) 为模板,包含模板表的 缺省值 (DEFAULTS) 和一致性约束 (CONSTRAINTS) 。 */
CREATE TABLE measurement_y2008m02
(LIKE measurement INCLUDING DEFAULTS INCLUDING CONSTRAINTS);
/* 为该表创建未来作为子表时需要使用的检查约束。 */
ALTER TABLE measurement_y2008m02 ADD CONSTRAINT y2008m02
CHECK (logdate >= DATE '2008-02-01' AND logdate < DATE '2008-03-01');
/* 导入数据到该表。下面只是给出一种导入数据的方式作为例子 。在导入数据之后,如有可能,还可以做进一步的数据处理,如 数据转换、过滤等。 */
\copy measurement_y2008m02 from 'measurement_y2008m02'
/* 在适当的时候,或者说在需要的时候,让该表继承主表。 */
ALTER TABLE measurement_y2008m02 INHERIT measurement;
7). 确保 postgresql.conf 里的配置参数 constraint_exclusion 是打开的。没有这个参数,查询不会按照需要进行优化。这里我 们需要做的是确保该选项在配置文件中没有被注释掉。
/> pwd
/opt/PostgreSQL/9.1/data
/> cat postgresql.conf | grep "constraint_exclusion"
constraint_exclusion = partition # on, off, or partition
3. 分区和约束排除:
约束排除(Constraint exclusion)是一种查询优化技巧,它改进了用上面方法定义的表分区的性能。比如:
SET constraint_exclusion = on;
SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
如果没有约束排除,上面的查询会扫描 measurement 表中的每一个分区。打开了约束排除之后,规划器将检查每个分区的约束 然后再视图证明该分区不需要被扫描,因为它不能包含任何符合 WHERE 子句条件的数据行。如果规划器可以证明这个,它就把该分 区从查询规划里排除出去。 你可以使用 EXPLAIN 命令显示一个规划在 constraint_exclusion 打开和关闭情况下的不同。用上面方法设置的表的典型的缺省 规划是:
SET constraint_exclusion = off;
EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01'; QUERY PLAN
-----------------------------------------------------------------------------------------------
Aggregate (cost=158.66..158.68 rows=1 width=0)
-> Append (cost=0.00..151.88 rows=2715 width=0)
-> Seq Scan on measurement (cost=0.00..30.38 rows=543 width=0)
Filter: (logdate >= '2006-01-01'::date)
-> Seq Scan on measurement_yy04mm02 measurement (cost=0.00..30.38 rows=543 width=0)
Filter: (logdate >= '2006-01-01'::date)
-> Seq Scan on measurement_yy04mm03 measurement (cost=0.00..30.38 rows=543 width=0)
Filter: (logdate >= '2006-01-01'::date)
...
-> Seq Scan on measurement_yy05mm12 measurement (cost=0.00..30.38 rows=543 width=0)
Filter: (logdate >= '2006-01-01'::date)
-> Seq Scan on measurement_yy06mm01 measurement (cost=0.00..30.38 rows=543 width=0)
Filter: (logdate >= '2006-01-01'::date) www.linuxidc.com
从上面的查询计划中可以看出,PostgreSQL 扫描了所有分区。下面我们再看一下打开约束排除之后的查询计划:
SET constraint_exclusion = on;
EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01'; QUERY PLAN
-----------------------------------------------------------------------------------------------
Aggregate (cost=63.47..63.48 rows=1 width=0)
-> Append (cost=0.00..60.75 rows=1086 width=0)
-> Seq Scan on measurement (cost=0.00..30.38 rows=543 width=0)
Filter: (logdate >= '2006-01-01'::date)
-> Seq Scan on measurement_yy06mm01 measurement (cost=0.00..30.38 rows=543 width=0)
Filter: (logdate >= '2006-01-01'::date)
请注意,约束排除只由 CHECK 约束驱动,而不会由索引驱动。目前版本的 PostgreSQL 中该配置的缺省值是 partition,该值是介于 on 和 off 之间的一种行为方式,即规划器只会将约束排除 应用于基于分区表的查询,而 on 设置则会为所有查询都进行约束排除,那么对于普通数据表而言,也将不得不承担由该机制而产生 的额外开销。约束排除在使用时有以下几点注意事项:
1). 约束排除只是在查询的 WHERE 子句包含约束的时候才生效。一个参数化的查询不会被优化,因为在运行时规划器不知道该 参数会选择哪个分区。因此像 CURRENT_DATE 这样的函数必须避免。把分区键值和另外一个表的字段连接起来也不会得到优化。
2). 在 CHECK 约束里面要避免跨数据类型的比较,因为目前规划器会无法证明这样的条件为假。比如,下面的约束会在 x 是整数 字段的时候可用,但是在 x 是一个 bigint 的时候不能用:
CHECK (x = 1) 对于 bigint 字段,我们必须使用类似下面这样的约束:
CHECK (x = 1::bigint) 这个问题并不仅仅局限于 bigint 数据类型,它可能会发生在任何约束的缺省数据类型与其比较的字段的数据类型不匹配的场合。 在提交的查询里的跨数据类型的比较通常是 OK 的,只是不能在 CHECK 条件里。
3). 在主表上的 UPDATE 和 DELETE 命令并不执行约束排除。
4). 在规划器进行约束排除时,主表上的所有分区的所有约束都将会被检查,因此,大量的分区会显著增加查询规划的时间。 5). 在执行 ANALYZE 语句时,要为每一个分区都执行该命令,而不是仅仅对主表执行该命令。