Postgresql逻辑结构整理

前端之家收集整理的这篇文章主要介绍了Postgresql逻辑结构整理前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。


数据库

创建数据库

create database name

[with owner = user_name --指定新建数据库属于哪个用户,不指定则属于当前执行命令的用户

template = template --模板名,不指定则默认使用 template1.

encoding = encoding --数据库使用的字符编码, 编码与区域设置必须与模板相一致。template0公认不包含任何受字符集编码或排序影响的数据或索引,故可作为任意字符集数据库的模板。

lc_collate = lc_collate

lc_ctype - lc_ctype

tablespace tablespace --指定和新数据库关联的表空间的名字

connection limit = connlimit] -数据库可以接受多少并发连接数,默认为-1,表示没有限制。

日常使用中很少指定数据库的字符集,因为Postgresql数据库服务端不支持通常的字符集“GBK,GB18030,所以一般都使用“UTF8”字符集来支持中文

修改数据库

ALTER DATABASE name rename TO new_name;

ALTER DATABASE name owner TO new_owner;

ALTER DATABASE name SET tablespase new_tablespace;

ALTER DATABASE name SET configuration_parameter{TO|=}{value|DEFAULT};

ALTER DATABASE name SET configuration_parameter FROM CURRENT;

ALTER DATABASE name RESET configuration_parameter;

ALTER DATABASE name RESET ALL;

--修改数据库最大连接数

postgres=# alter database testdb2 connection limit 100;

ALTER DATABASE

postgres=#

drop database [IF EXISTS] name ;

如果还有人连接该库,将不能删除

常见问题:

1.能否在事务块中创建或删除数据库

答:不能

2.能否在数据库修改数据库

答:能

-------------------------------------------------------------------------

模式

模式(schema):可理解为一个命名空间或目录,不同的模式下可以有相同名称的表、函数等对象且不冲突。

允许多个用户在使用同一个数据库时彼此互不干扰;

数据库对象放在不同模式下,然后组织成逻辑组,便于管理;

第三方的应用可以放在不同的模式中,就不会和其他对象名字冲突了。

--创建

CREATE SCHEMA schemaname ;

postgres=# \c testdb2;

You are now connected to database "testdb2" as user "postgres".

testdb2=# \dn;

List of schemas

Name | Owner

--------+----------

public | postgres

(1 row)

testdb2=# create schema test;

CREATE SCHEMA

testdb2=# \dn

List of schemas

Name | Owner

--------+----------

public | postgres

test | postgres

(2 rows)

testdb2=#

--删除

postgres=# drop schema test_schema;

DROP SCHEMA

postgres=#

--下面的命令为用户osdba建的模式,名字也定为osdba;

create schema authorization osdba;

公共模式

schema_name.table_name;

通常创建和访问表的时候都不用指定模式,默认访问的是public”模式。

模式搜索路径

public模式总是在搜索路径中,所以public为建表的默认模式。

testdb2=# show search_path;

search_path

-----------------

"$user",public

(1 row)

模式权限

默认情况下,用用户无法访问不属于他们的对象。若要访问,模式的所有者必须在模式上赋予他们USAGE”权限。为了让用户使用模式中的对象,可能需要赋予适合该对象的额外权限。

默认情况下,每个人在public”模式上都有“create"和”usage“权限。如果撤销该权限:

revoke create on schema public from PUBLIC;

第一个public是模式名称,第二个PUBLIC是所有用户意思。

模式移植性:

因其它数据库没有模式概念,需考虑数据库的兼容;

------------------------------------------------------------------

-------------------------------------------------------------------

主键约束

一般的表都有主键,如果由一个字段组成,直接在字段定义后加上primary key”关键字;

create table test1(id int primary key,note varchar(20));

如果为两个以上字段,则为复合主键,语法为:

create table test02(id1 int,id2 int,note vachar(20),CONSTRAINT pk_test02 primary key(id1,id2));

唯一约束

create table test03(id1 int,id3 int,CONSTRAINT pk_test03 primary key(id1,id2),CONSTRAINT uk_test03_id3 UNIQUE(id3));

检查约束

create table child(name varchar(20),age int,note text,CONSTRAINT ch_child_age CHECK(age >0 and age<18));

复杂表结构:

create table baby(like child);

注意:没有把源表上的约束复制过来,如果要复制,需加上INCLUDING,可用的“INCLUDES”选项为:

INCLUDING DEFAULT

INCLUDING CONSTRAINT

INCLUDING INDEXES

INCLUDING STORAGE

INCLUDING COMMENTS

INCLUDING ALL

也可用create table as 来建表

create table baby as select * from child with no data;

临时表:

会话级临时表:会话的生命周期

事务级临时表:事务的生命周期

testdb2=# create temporary table tmp_t1(id int primary key,note text);

CREATE TABLE

testdb2=# \d

List of relations

Schema | Name | Type | Owner

-----------+-----------+-------+----------

pg_temp_7 | tmp_t1 | table | postgres

public | card_test | table | postgres

public | date_test | table | postgres

public | jtest01 | table | postgres

public | jtest02 | table | postgres

public | jtest03 | table | postgres

public | t_number | table | postgres

public | t_user | table | postgres

public | test | table | postgres

public | testtab05 | table | postgres

public | testtab6 | table | postgres

(11 rows)

临时表在schema生成一个特殊的表,这个schema名称pg_tmp_XX","XX"代表一个数字,不同的sseion这个数字是不同的。

testdb2=# insert into tmp_t1 values(1,'111');

INSERT 0 1

testdb2=# insert into tmp_t1 values(2,'122');

INSERT 0 1

testdb2=# select * from tmp_t1;

id | note

----+------

1 | 111

2 | 122

(2 rows)

默认情况下,创建的临时表是会话级别的,如果想创建事务级的临时表,可加上ON COMMIT DELETE ROWS

------------------------------------------------------------------

默认值

字段设置默认值

testdb2=# create table student(no int,name varchar(20),age int default 15);

CREATE TABLE

testdb2=# insert into student (no,name) values(1,'张三');

INSERT 0 1

testdb2=# insert into student (no,name) values(2,'张将');

INSERT 0 1

testdb2=# select * from student;

no | name | age

----+------+-----

1 | 张三 | 15

2 | 张将 | 15

(2 rows)

--可使用DEFAULT来代替默认值。如果没有声明默认值,则为null.

testdb2=# update student set age = 16;

UPDATE 2

testdb2=# select * from student;

no | name | age

----+------+-----

1 | 张三 | 16

2 | 张将 | 16

(2 rows)

testdb2=# update student set age = DEFAULT where no = 2;

UPDATE 1

testdb2=# select * from student;

no | name | age

----+------+-----

1 | 张三 | 16

2 | 张将 | 15

(2 rows)

testdb2=# create table blog(id int,title text,created_date timestamp default now());

CREATE TABLE

testdb2=# insert into blog values(1,'Postgresql创建临时表');

INSERT 0 1

testdb2=# select * from blog;

id | title | created_date

----+----------------------+----------------------------

1 | Postgresql创建临时表 | 2017-10-07 18:20:47.706399

(1 row)

testdb2=#

----------------------------------------------------------------------------------------

约束

1)检查约束

create table persons(

name varchar(40),

age int CHECK(age >=0 and age <=150),

sex boolean

);

create table books(

book_no integer,

name text,

price numeric CHECK (price >0),

discounted_price numeric CHECK(discounted_price > 0),--字段约束

CHECK(price > discounted_price) --表约束

);

2)非空约束

create table books(

book_no integer not null,

price numeric

);

3)唯一约束

create table books(

book_no integer unique,

price numeric

);

4)外键约束

表之间关系的一种约束,参照完整性。

create table class(

class_no int primary key,

class_name varchar(40)

);

create table student(

student_no int primary key,

student_name varchar(40),

age int,

class_no int references class(class_no)

);

----------------------------------------------------------------------------

修改表:

增加字段:

alter table class add column class_teacher varchar(40);

alter table class add column class_teacher varchar(40) CHECK (class_teacher <> '');

删除字段:

alter table class drop column class_teacher;

alter table class drop column class_no CASCADE;--会把引用class_no的外键也删除

增加约束:

alter table student add CHECK(age < 19);

alter table class ADD CONSTRAINT unique_class_teacher UNIQUE (class_teacher);

alter table student alter column student_name set not null; --非空约束

删除约束:

alter table student drop CONSTRAINT constraint_name; --删除前需要知道约束名称,一般用 “\d”把约束名称查出来,再删除

修改默认值:

alter table student alter column set default 13;--不会影响现有的行数据,只将将来的insert命令改变默认值。

删除默认值:

alter table student alter column age drop default;

修改字段类型:

alter table student alter column student_name TYPE text;--只有在字段里现有的每个项都可以隐式地转换成新类型时,才能成功;

重命名字段:

alter table books RENAME COLUMN book_no TO book_id;

重命名表:

alter table class RENAME to classes;

------------------------------------------------------------------------------

表的继承

create table persons(

name text,

sex boolean

);

create table students(

class_no int

)INHERITS(persons);

insert into students values('张三',15,true,1);

insert into students values('张花',16,false,2);

select * from persons;

postgres=# select * from persons;

name | age | sex

------+-----+-----

张三 | 15 | t

张花 | 16 | f

(2 rows)

postgres=# select * from students;

name | age | sex | class_no

------+-----+-----+----------

张三 | 15 | t | 1

张花 | 16 | f | 2

(2 rows)

--更改students表中数据,通过persons表也可看到变化:

update students set age = 13 where name='张三';

postgres=# update students set age = 13 where name='张三';

UPDATE 1

postgres=# select * from persons;

name | age | sex

------+-----+-----

张花 | 16 | f

张三 | 13 | t

(2 rows)

--persons表中插入一条数据,查询student表是看不到这条数据的;

查询父表会把子表的数据显示出来,反过来不行

如果想查询父表的数据,在表名前加上only

所有父表的检查约束和非空约束会自动被子表继承,其它类型的约束不会

一个子表可以从多个父表继承,它将拥有所有父表字段的总和,并且子表中的字段也会加入。

如果一个字段出现在多个父表,或出现在父表和子表中,这些字段将进行融合,只保留一个。

------------------------------------------------------------------------------------

分区表

表分区就是把逻辑上的一个大表分割成物理上的几个小块。分区可提供若干好处:

1.删除历史数据,通过分区 快;

2.查询同一个分区内数据 快;

3.用到较少的历史数据通过分区存放到其它物理介质上。

什么时候使用分区表?表的大小超过了数据库服务器物理内存的大小

使用继承实现分区表时,一般会让父表为空,数据存储在子表中。

建分区表步骤:

1.创建父表,所有分区都从它继承。这个表没有数据,没有任何检查约束,除非想约束所有的分区。

2.创建几个子表,每个都是从主表上继承的,通常不会增加任何字段,我们把这些子表称为分区,实际上它们就是普通的Postgresl表。

3.给分区表增加约束,定义每个分区允许的键值

4.对于每个分区,在关键字字段上创建一个索引,和想创建的其它索引。如果关键字唯一,则创建唯一约束或主键约束。

5.定义一个规则或触发器,把对主表的数据插入重定向到合适的分区表。

6.确保constraint_exclusion里的配置参数postgresql.conf是打开的。打开后,如果查询where子句的过滤条件与分区的约束条件匹配,则这个查询查询这个分区,而不会查询其它分区。

分区表示例:

假设一张销售明细表:

create table sales_detail(

product_id int not null,

price numeric(12,2),

amount int not null,

sale_date date not null,

buyer varchar(40),

buyer_contact text

);

建分区表:

create table sales_detail_y2017m07 (check (sale_date >= DATE '2017-07-01' and sale_date < DATE '2017-08-01')) inherits(sales_detail);

create table sales_detail_y2017m08 (check (sale_date >= DATE '2017-08-01' and sale_date < DATE '2017-09-01')) inherits(sales_detail);

create table sales_detail_y2017m09 (check (sale_date >= DATE '2017-09-01' and sale_date < DATE '2017-10-01')) inherits(sales_detail);

create table sales_detail_y2017m10 (check (sale_date >= DATE '2017-10-01' and sale_date < DATE '2017-11-01')) inherits(sales_detail);

分区表上建的检查约束,只允许插入本月数据;

一般情况下,还可以在分区键sale_date”上建索引:

create index sale_detail_y2017m07_sale_date ON sales_detail_y2017m07 (sale_date);

create index sale_detail_y2017m08_sale_date ON sales_detail_y2017m08 (sale_date);

create index sale_detail_y2017m09_sale_date ON sales_detail_y2017m09 (sale_date);

create index sale_detail_y2017m10_sale_date ON sales_detail_y2017m10 (sale_date);

如果有需要,还可以在其它字段上建索引。

自动且正确的把数据插入到正确的分区:使用触发器

create or replace function sale_detail_insert_trigger()

RETURNS TRIGGER AS $$

begin

if(NEW.sale_date >= DATE'2017-07-01' and NEW.sale_date < DATE '2017-08-01') then

insert into sales_detail_y2017m07 values(NEW.*);

elsif(NEW.sale_date >= DATE'2017-08-01' and NEW.sale_date < DATE '2017-09-01') then

insert into sales_detail_y2017m08 values(NEW.*);

elsif(NEW.sale_date >= DATE'2017-09-01' and NEW.sale_date < DATE '2017-10-01') then

insert into sales_detail_y2017m09 values(NEW.*);

elsif(NEW.sale_date >= DATE'2017-10-01' and NEW.sale_date < DATE '2017-11-01') then

insert into sales_detail_y2017m10 values(NEW.*);

else

raise exception 'Date out of range. Fix the sale_detail_insert_trigger() function!';

END IF;

RETURN NULL;

end;

$$

language plpgsql;

create trigger insert_sale_detail_trigger

before insert on sales_detail

for each row execute procedure sale_detail_insert_trigger();

--------------------------------------------------------------------------

该部分是因为建的触发器有问题

testdb2=# insert into sales_detail values(1,43.12,1,date'20170-09-14','四远方','杭州钱塘江区小碗城');

ERROR: Date out of range. Fix the sale_detail_insert_trigger() function!

CONTEXT: PL/pgsql function sale_detail_insert_trigger() line 12 at RAISE

testdb2=# insert into sales_detail values(1,date'2017-09-14','杭州钱塘江区小 碗城');

ERROR: "sale_detail_y2017m09_sale_date" is an index

LINE 1: insert into sale_detail_y2017m09_sale_date values(NEW.*)

^

QUERY: insert into sale_detail_y2017m09_sale_date values(NEW.*)

CONTEXT: PL/pgsql function sale_detail_insert_trigger() line 8 at sql statement

-----------------------------------------------------------------------------

testdb2=# insert into sales_detail values(1,'杭州钱塘江区小 碗城');

INSERT 0 0

testdb2=#

testdb2=# insert into sales_detail values(13,56.02,31,date'2017-10-14','王思聪','上海浦东新区万达大酒店');

INSERT 0 0

testdb2=#

testdb2=# insert into sales_detail values(13,date'2017-11-14','上海浦东新区万达大酒店');

ERROR: Date out of range. Fix the sale_detail_insert_trigger() function!

CONTEXT: PL/pgsql function sale_detail_insert_trigger() line 12 at RAISE

testdb2=#

testdb2=# select * from sales_detail ;

product_id | price | amount | sale_date | buyer | buyer_contact

------------+-------+--------+------------+--------+------------------------

1 | 43.12 | 1 | 2017-09-14 | 四远方 | 杭州钱塘江区小碗城

13 | 56.02 | 31 | 2017-10-14 | 王思聪 | 上海浦东新区万达大酒店

(2 rows

分区的优化技巧:

打开约束排除(constraint_exclusion)是一种查询优化技巧;

sql查询中将where语句中的过滤条件与表上的check条件进行对比,就可得知不需要扫描的分区,从而跳过相应的分区表,性能也得到提高,如下:

testdb2=# explain select count(*) from sales_detail where sale_date >= Date'2017-09-01';

QUERY PLAN

------------------------------------------------------------------------------------

Aggregate (cost=33.04..33.05 rows=1 width=8)

-> Append (cost=0.00..32.29 rows=300 width=0)

-> Seq Scan on sales_detail (cost=0.00..1.54 rows=14 width=0)

Filter: (sale_date >= '2017-09-01'::date)

-> Seq Scan on sales_detail_y2017m09 (cost=0.00..15.38 rows=143 width=0)

Filter: (sale_date >= '2017-09-01'::date)

-> Seq Scan on sales_detail_y2017m10 (cost=0.00..15.38 rows=143 width=0)

Filter: (sale_date >= '2017-09-01'::date)

(8 rows)

如果把参数 "constraint_exclusion"设置成off,则会扫描每张分区子表,如下:

testdb2=# set constraint_exclusion='off';

SET

testdb2=# explain select count(*) from sales_detail where sale_date >= Date'2017-09-01';

QUERY PLAN

------------------------------------------------------------------------------------

Aggregate (cost=64.50..64.51 rows=1 width=8)

-> Append (cost=0.00..63.04 rows=586 width=0)

-> Seq Scan on sales_detail (cost=0.00..1.54 rows=14 width=0)

Filter: (sale_date >= '2017-09-01'::date)

-> Seq Scan on sales_detail_y2017m07 (cost=0.00..15.38 rows=143 width=0)

Filter: (sale_date >= '2017-09-01'::date)

-> Seq Scan on sales_detail_y2017m08 (cost=0.00..15.38 rows=143 width=0)

Filter: (sale_date >= '2017-09-01'::date)

-> Seq Scan on sales_detail_y2017m09 (cost=0.00..15.38 rows=143 width=0)

Filter: (sale_date >= '2017-09-01'::date)

-> Seq Scan on sales_detail_y2017m10 (cost=0.00..15.38 rows=143 width=0)

Filter: (sale_date >= '2017-09-01'::date)

(12 rows)

testdb2=#

-------------------------------------------------------------------------------------------

触发器

是一种由事件自动触发执行的特殊的存储过程,这些事件可以是insert,update,delete等。

经常用于加强数据的完整性约束和业务规则上的约束。

建触发器步骤

先为触发器建一个执行函数,此函数的返回类型为触发器类型;然后即可创建触发器。

CREATE [CONSTRAINT] TRIGGER name {BEFORE | AFTER | INSTEAD OF} {EVENT [OR ...]} ON table_name

[FROM referenced_table_name]

{NOT DEFERRABLE | [DEFERRABLE] {INITIALLY IMMEDIATE | INITIALLY DEFERRED}}

[FOR [EACH] {ROW | STATEMENT}]

[WHEN (condition)]

EXECUTE PROCEDURE function_name (arguments)

示例:

create table student_info(

student_no int primary key,

age int

);

create table score_info(

student_no int,

chinese_score int,

math_score int,

test_date date

);

如果想删除学生表中一条记录时,把学生在成绩表(score_info)中的成绩记录也删除,就可以使用触发器。先建触发器的执行函数

CREATE OR REPLACE FUNCTION student_delete_trigger()

RETURNS TRIGGER AS $$

begin

delete from score_info where student_no = OLD.student_no;

return OLD;

end;

$$

language plpgsql;

再创建触发器:

create trigger delete_student_trigger

after delete on student_info

for each row execute procedure student_delete_trigger();

插入测试数据:

insert into student_info values(1,'xx1',14);

insert into student_info values(2,'xx2',15);

insert into student_info values(3,'xx3',16);

insert into student_info values(4,'xx4',17);

insert into score_info values(1,84,75,date'2017-05-22');

insert into score_info values(1,81,73,date'2017-06-22');

insert into score_info values(2,87,date'2017-07-22');

insert into score_info values(2,64,85,date'2017-04-22');

insert into score_info values(3,94,25,date'2017-05-22');

insert into score_info values(3,55,88,date'2017-07-22');

insert into score_info values(4,44,53,date'2017-09-22');

insert into score_info values(4,23,83,date'2017-04-22');

把学生好为3的学生删除掉:

testdb2=# delete from student_info where student_no = 3;

DELETE 1

再查下score_info表: ^

testdb2=# select * from score_info ;

student_no | chinese_score | math_score | test_date

------------+---------------+------------+------------

1 | 84 | 75 | 2017-05-22

1 | 81 | 73 | 2017-06-22

2 | 87 | 75 | 2017-07-22

2 | 64 | 85 | 2017-04-22

4 | 44 | 53 | 2017-09-22

4 | 23 | 83 | 2017-04-22

(6 rows)

testdb2=#

语句级触发器指执行每个sql时,只执行一次;

行级触发器指每行就会执行一次;

一个修改0行的操作仍会导致语句级触发器被执行。

create table log_student(

update_time timestamp,--操作时间

db_user varchar(40),--操作的数据库用户名

opr_type varchar(6) --操作类型:insertdeleteupdate

);

创建记录log的触发器函数,如下:

create function log_student_trigger()

returns trigger as

$$

begin

insert into log_studnet values(now(),user,TG_OP);

return null;

end;

$$

language "plpgsql";

student上创建一个语句级触发器:

create trigger log_student_trigger

after insert or delete or update on student

for statement execute procedure log_student_trigger();

testdb2=# insert into student values(1,'张生',14),(2,'水生','25');

INSERT 0 2

testdb2=# select * from log_student;

update_time | db_user | opr_type

----------------------------+----------+----------

2017-10-11 13:18:46.732591 | postgres | INSERT

(1 row)

testdb2=#

从上可看出:虽然插入了2行,但只有一条语句,所以在log_studnet上只记录了一次操作。

testdb2=# update student set age = 18;

UPDATE 4

testdb2=# select * from log_student;

update_time | db_user | opr_type

----------------------------+----------+----------

2017-10-11 13:18:46.732591 | postgres | INSERT

2017-10-11 13:21:22.631776 | postgres | UPDATE

(2 rows)

testdb2=

虽然update更新了4行,但log_student只记录了一条记录。语句级触发器是按语句进行触发的,不管实际操作了多少行。

下面的更新,实际没有更新任何数据,也会被触发:

testdb2=# update student set age = 19 where no = 3333;

UPDATE 0

testdb2=# select * from log_student;

update_time | db_user | opr_type

----------------------------+----------+----------

2017-10-11 13:18:46.732591 | postgres | INSERT

2017-10-11 13:21:22.631776 | postgres | UPDATE

2017-10-11 13:24:13.225804 | postgres | UPDATE

(3 rows)

testdb2=#

行级触发器:

先清掉log_student表;

testdb2=# delete from log_student;

DELETE 3

testdb2=#

create trigger log_student_trigger2

after insert or delete or update on student

for row execute procedure log_student_trigger();

插入数据:

testdb2=# insert into student values(11,(22,'25');

INSERT 0 2

testdb2=# select * from log_student;

update_time | db_user | opr_type

----------------------------+----------+----------

2017-10-11 13:42:03.097678 | postgres | INSERT

2017-10-11 13:42:03.097678 | postgres | INSERT

2017-10-11 13:42:03.097678 | postgres | INSERT

(3 rows)

插入了2条数据,应该是2条日志才对,但实际得到了3条,不知道怎么回事。

更改数据:

testdb2=# update student set age = 19 ;

UPDATE 6

testdb2=# select * from log_student;

update_time | db_user | opr_type

----------------------------+----------+----------

2017-10-11 13:42:03.097678 | postgres | INSERT

2017-10-11 13:42:03.097678 | postgres | INSERT

2017-10-11 13:42:03.097678 | postgres | INSERT

2017-10-11 13:44:36.990037 | postgres | UPDATE

2017-10-11 13:44:36.990037 | postgres | UPDATE

2017-10-11 13:44:36.990037 | postgres | UPDATE

2017-10-11 13:44:36.990037 | postgres | UPDATE

2017-10-11 13:44:36.990037 | postgres | UPDATE

2017-10-11 13:44:36.990037 | postgres | UPDATE

2017-10-11 13:44:36.990037 | postgres | UPDATE

(10 rows)

testdb2=#

更改了6条,却又7条更改记录。

删除触发器:

drop trigger [if exists] name on table [cascade | restrict];

if exists:如果指定的触发器不存在,则发出一个notice而不是抛出一个错误

cascade:级联操作依赖此触发器的对象

restirct:默认值,如果有依赖对象的存在,拒绝删除

drop trigger user_new_name_student_trigger on student;

删除触发器时,触发器的函数不会被删除

当表删除时,表上的触发器也会被删除

触发器函数都有返回值,语句级触发器应该总返回null,即必须显式地在触发器函数中写上“return null,如果没有写,将报错。

触发器函数中的特殊变量:

NEW:该变量为insert/update操作触发的行级触发器中存储的新的数据行,数据类型是record

OLD: 该变量为delete/update操作触发的行级触发器中存储的旧的数据行,数据类型是record

TG_NAME: 数据类型是name,包含实际触发的触发器名。

TG_WHEN: 内容"BEFORE""AFTER"的字符串用于指定是BEFORE触发器还是AFTER触发器

TG_LEVEL: 内容"ROW""STATEMENT"的字符串用于指定是语句触发器还是行级触发器

TG_OP: 内容"INSERT","UPDATE","DELETE","TRUNCATE"之一的字符串,用于指定DML语句类型。

TG_RELLD: 触发器所在的表的OID

TG_RELNAME:

TG_TABLE_NAME: 触发器所在的表的名称

TG_TABLE_SCHEMA: 触发器所在的表的模式

TG_NARGS: create trigger语句里赋予触发器过程的参数个数。

TG_ARGV[]:text类型的一个数组,是create trigger语句里的参数。

表空间:

表空间实际上是为表指定一个存储的目录。

在创建数据库的时候可以为数据库指定默认表空间。

创建表和索引时可以指定表空间,这样表和索引就可以存储到表空间对应的目录下。

创建表空间示例:

CREATE TABLESPACE tbs_data location '/data/pgdata';

创建数据库时指定默认表空间:

create database db01 tablespace tbs_data;

改变一个数据库的默认表空间:

alter database db01 set TABLESPACE tbs_data;

注意:

1.该操作时,必须没有人连接到这个库,否则报错 is being accessed by other users.detail:there is 1 other session using the database.

2.改变默认表空间时,数据库中已有表的表空间不会改变。

创建表时指定表空间:

create table test01(id int,note text) tablespace tbs_data;

创建索引时指定表空间:

create index idx_test01_id on test01(id) tablespace tbs_data;

增加主键时,指定主键索引的表空间,如下:

alter table test01 add constraint pk_test01_id primary key (id) using index tablespace tbs_data;

把表从一个表空间移动到另一个表空间:(会锁表)

alter table test01 set tablespace pg_default;

----------------------------------------------------------

视图:

查询语句定义的虚拟表

1.可使复杂的查询易于理解和使用;

2.安全,隐藏敏感神经;

3.函数的返回结果映射成视图;

-------------------------------------------------------------

索引

索引的好处与代价

索引的分类

B-tree:适合处理等值查询和范围查询

Hash:只能处理简单的等值查询

GiST:不是一种单独的索引类型,而是一种架构,可在这种架构上实现很多不同的索引策略。

SP-GiST:即空间分区GiST索引,提高GiST索引在某些情况下特性。

GIN:反转索引。可以处理包含多个键的值,如数组等。

创建索引

一般在建索引过程中,会把表的数据读一遍,这个过程所用的时间由表的大小决定,对于比较大的表,可能会花很久的时间。

建索引过程中,对表的查询可正常进行,对表的增删改需要等索引建完后才能进行;

create [UNIQUE] index [CONCURRENTLY] on table_name [USING method]

({column_name | (expression)} [COLLATE collation] [opclass] [ASC | DESC] [NULLS {FIRST | LAST})] )

[with (storage_parameter = value [,...])]

示例:

create table contacts(

id int primary key,

name varchar(40),

phone varchar(32)[],

address text

);

--name上建B-tree索引

create index idx_contacts_name on contacts(name);

--phone上建GIN索引

create index idx_contacts_phone on contacts using gin(phone);

select * from contacts where phone @> array['132323443;::varchar(32)];

注意: @> 是数组的操作符,表示“包含”的意思,GIN索引能在 “@>”上起作用。

创建索引时可以指定存储参数WITH (storage_parameter=value),常用的参数为FILLFACTOR.如:

create index idx_contacts_name on contacts(name) with (FILLFACTOR=50);

可按降序建索引:

create index idx_contacts_name on contacts(name desc);

如果name中有空值,可在建索引时,指定空值排在非空值前面:

create index idx_contacts_name on contacts(name desc nulls first);

或空值排在非空值后面:

create index idx_contacts_name on contacts(name desc nulls last);

并发创建索引

鉴于创建索引过程中,不能对表做更新操作,当表数据量大时,耗时很长,Postgresql支持不长时间阻塞更新的情况下创建索引,这是通过在create index中加concurrently(并发创建索引)选项来实现的。当该选项被使用时,postgresql会执行表的两次扫描,因此需要更长一些的时间来建索引。

一个表经过频繁更新后,若要重新建索引:

postgresql支持在同个字段上建两个索引,可使用“CONCURRENTLY”选项建一个新的索引,然后把旧的索引删掉,这样相当于重建。

并发创建索引的时候,如果索引在创建的过程中被强行取消,可能会留下一个无效索引,这个索引仍会导致更新变慢。

如果创建的是一个唯一索引,这个无效的索引还会导致插入重复值失败。此时,手工删除此索引就可以了。

修改索引

--给索引改名

ALTER INDEX name RENAME TO new_name;

--把索引移到表空间下

ALTER INDEX name SET TABLESPACE tablespace_name;

--把索引的填充因子(filfactor)设置为50

ALTER INDEX name SET (storage_parameter = value);

ALTER INDEX name SET (filfactor = 50);

--把填充因子重置为默认值

ALTER INDEX name RESET (storage_parameter);

ALTER INDEX name RESET (filfactor);

删除索引

DROP INDEX [IF EXISTS] name [cascade | restrict];

删除索引时默认使用选项restrict,所以不加关键字“restrict”都是一样,如果有依赖对象依赖这个索引,则会删除失败。而使用“cascade”,表示当有依赖于这个索引的对象时,一并把这些对象删掉,如外键约束。

用户及权限管理

postgresql中,用户与角色是没有区别的,在整个数据库实例中都是全局的,且在同一个实例中的不同数据库中,看到的用户也都是相同的。

安装数据库的时候,预定义的超级用户与初始化该数据库的操作系统用户名相同,如果数据库建立在系统用户postgres”下的,这个数据库超级用户就是“postgres”。用这个用户连接数据库,然后创建更多的用户

创建用户和角色:

create role name [[WITH] option [...]] --默认没有 login 权限

create user name [[WITH] option [...]] --默认有 login 权限

option内容如下:

superuser|nosuperuser:表示创建出的用户是否为超级用户,只有超级用户才能创建超级用户

createdb|nocreatedb:创建的用户是否有 create database权限;

createrole|nocreaterole:

createruser|nocreateruser:

inherit|noinherit: 创建的用户拥有某一个或某几个角色,若指定inherit表示用户自动继承相应角色的权限,否则没有该角色的权限。

login|nologin:是否有login权限

CONNECTION LIMIT connlimit: 用户可以使用并发连接数量,默认为-1,表示没有限制。

[ENCRYPTED|UNENCRYPTED] PASSWORD 'password':用于控制存储在系统表里的口令是否加密。

VALID UNTIL 'timestamp':密码失效时间,如果不指定,口令将永远有效;

权限管理:

删除一个对象及任意修改它的权力都不赋予别人,它是所有者固有的,不能被赋予和撤销。

一个用户的权限分为两类:

一类是在创建用户时就指定的权限,如:

超级用户权限;

创建数据库权限;

是否允许LOGIN的权限;

这些权限可使用alter role命令来修改

还有一类是用grantrevoke来管理的,如下:

创建模式;

创建临时表;

连接某个数据库

创建数据库对象,如:表,视图,函数等;

对表做select,insert,delete操作;

对序列进行查询、使用、更新等;

在声明表上创建触发器;

把表和索引建到指定表空间等;

alter role_name [[WITH] option [...]]

grant some_privileges on database_object_type object_name TO role_name;

postgredsql只允许超级用户使用PL语言写函数

----------------------------------------------------------------------------------------

锁模式

死锁及防范

两个及两个以上事务在执行过程中由于资源竞争造成相互等待。

防范:破坏死锁的条件;

表级锁命令: LOCK TABLE

LOCK TABLE name [IN lockmode MODE] [NOWAIT]

name:表名

lockmode:几种表级锁模式

nowait:如果没有nowait这个关键字,当无法获取锁时,会一直等待;加上nowait后,无法获取锁时,会立即退出并发出一个错误信息。

行级锁命令

select ... for {update|share} [OF table_name [...]] [nowait]

锁的查看

查询系统视图pg_locks

testdb2=# \d pg_locks

locktype | text |

database | oid |

relation | oid |

page | integer |

tuple | smallint |

virtualxid | text |

transactionid | xid |

classid | oid |

objid | oid |

objsubid | smallint |

virtualtransaction | text |

pid | integer |

mode | text |

granted | boolean |

fastpath | boolean |

select

locktype,

relation::regclass as rel,

virtualxid as vxid,

transactionid as xid,

virtualtransaction as vxid2,

pid,

mode,

granted

from pg_locks

where pid = 12373;

locktype | rel | vxid | xid | vxid2 | pid | mode | granted

------------+------+-------+-----+-------+-------+---------------------+---------

virtualxid | | 3/378 | | 3/378 | 12373 | ExclusiveLock | t

relation | test | | | 3/378 | 12373 | AccessExclusiveLock | t

(2 rows)

select

locktype,

granted

from pg_locks ;

locktype | rel | vxid | xid | vxid2 | pid | mode | granted

------------+----------+-------+-----+-------+-------+---------------------+---------

relation | pg_locks | | | 5/118 | 14468 | AccessShareLock | t

virtualxid | | 5/118 | | 5/118 | 14468 | ExclusiveLock | t

virtualxid | | 3/378 | | 3/378 | 12373 | ExclusiveLock | t

relation | test | | | 3/378 | 12373 | AccessExclusiveLock | t

原文链接:https://www.f2er.com/postgresql/193502.html

猜你在找的Postgre SQL相关文章