基于 DATABASE 的多租户

1.、优点

数据库的方式隔离比较彻底,共用的资源较少。可以实现存储的隔离;可以实现 connection 的隔离;可以实现auth的隔离;可以实现权限的隔离。从认证层面就开始隔离了,数据库与数据库之间也无法直接访问,必须要登陆到对方的数据库中才能访问对方的数据(即使使用 fdw,,dblink 也是有登陆的过程的)。陆时可以通过 pg_hba.conf 控制来源 IP,用户是否有权限登陆目标库。同时在数据库中的权限体系中还可以配置是否允许用户访问目标库,或者在目标库创建 SCHEMA。

2. 缺点

因为每个数据库对应了各自的元信息,大概有几百个文件,所以如果租户比较多,数据库也会比较多。

3、实践

--创建用户create role 租户名 login ...;--配置防火墙pg_hba.confhost 数据库 用户 来源IP md5--从模板创建数据库create database db with template templatexxx;--回收权限revoke all on database db from public;--赋权grant all on database db to 租户;

基于 SCHEMA 的多租户

1. 优点

SCHEMA 的方式,共用资源较多,可以同时操作不同的 SCHEMA 之间的对象,事务都是本地事务。单个数据库,多个 SCHEMA 的方式,比较轻巧,如果是企业私有的多租户,可以这样使用。通过数据库的权限体系隔离用户,访问不同 SCHEMA。简单来说是有 SCHEMA更便捷,但是权限隔离没有使用数据库那么彻底,可以从 pg_class 等系统表窥探到没有权限的对象的定义。从生成效率来讲,使用数据库模板的方式会高很多,因为它只需要 COPY DIR,产生的 REDO 很少,也不需要大量的变更元数据。从删除效率来讲,差别也非常大,删除 SCHEMA 与创建 SCHEMA 一样,会产生大量的 REDO,甚至会导致 STANDBY 剧烈的延迟,后面会有分析。而删除数据库很快,只产生少量的 REDO。

2. 缺点

无法通过 pg_hba.conf 控制 schema 的权限,权限隔离可能不够彻底。用户可通过查看元表,观察到其他 schema 的对象,定义等信息,不安全。如果是企业内部私有的,并且这部分缺陷不敏感时可以使用。创建租户和删除租户需要产生大量元数据,或删除大量元数据,可能导致 STANDBY 长时间延迟。

3、实践

--创建用户create role 租户名 login ...;--创建schemacreate schema xx;--回收权限revoke all on schema xx from public;--赋权grant all on schema xx to 租户;

以 schema 为例的多租户路由选择,例如通过客户端 application_name 或者客户端 IP 地址,区分不同的租户。每个租户的模板完全一样,只是使用了不同的 schema。客户使用 search_path 修改路径,完成对路由的选择。一套程序,完成多租户的方法:建立会话后,首先选择路由(即根据客户端 IP 或设置的 application_name,设置对应的路由)。也可以每次设置路由(开销大,较浪费)。后续的操作则会自动匹配对应的 schema.路由函数举例:以 application_name 为 schema 命名

create or replace function public.route() returns void as $$
declare
begin
execute 'set search_path='||current_setting('application_name')||', "$user", public' ;
end;
$$ language plpgsql strict;
postgres=# select public.route();
route
-------
(1 row)
postgres=# show search_path ;
search_path
-----------------------
psql, "$user", public
(1 row)

接下来的SQL都会首先搜索psql中的对象。如果schema很多,而且要经常调用,建议写成C function,使用更高效的匹配算法,例如hash search。在业务函数中封装选择函数的例子。

create or replace function 业务函数(参数) returns xx as $$declarexx;beginperform 路由函数(影响路由选择的参数);业务SQL;end;$$ language plpgsql strict;

实战案例

环境准备

用到两块PCI-E SSD,分别存放主库和备库。主库监听5289,备库监听5290

1. postgresql.conf

listen_addresses = '0.0.0.0'
port = 5289
max_connections = 100
unix_socket_directories = '.'
shared_buffers = 8GB
maintenance_work_mem = 512MB
dynamic_shared_memory_type = posix
bgwriter_delay = 10ms
bgwriter_lru_maxpages = 1000
bgwriter_lru_multiplier = 10.0
wal_level = hot_standby
synchronous_commit = off
wal_buffers = 128MB
wal_writer_delay = 10ms
checkpoint_segments = 256
checkpoint_timeout = 30min
checkpoint_completion_target = 0.0001
max_wal_senders = 10
wal_keep_segments = 512
hot_standby = on
max_standby_archive_delay = 300s
max_standby_streaming_delay = 300s
wal_receiver_status_interval = 1s
hot_standby_feedback = on
random_page_cost = 1.0
log_destination = 'csvlog'
logging_collector = on
log_truncate_on_rotation = on
log_checkpoints = on
log_connections = on
log_disconnections = on
log_error_verbosity = verbose
log_timezone = 'PRC'
autovacuum = on
log_autovacuum_min_duration = 0
autovacuum_naptime = 10s
datestyle = 'iso, mdy'
timezone = 'PRC'
lc_messages = 'C'
lc_monetary = 'C'
lc_numeric = 'C'
lc_time = 'C'
default_text_search_config = 'pg_catalog.english'
max_locks_per_transaction = 1000000

2. pg_hba.conf

local   all             all                                     trust
host    all             all             127.0.0.1/32            trust
host    all             all             ::1/128                 trust
host    replication     postgres        127.0.0.1/32            trust

3. recovery.done

recovery_target_timeline = 'latest'
standby_mode = on
primary_conninfo = 'host=localhost port=5289 user=postgres'

创建备库

pg_basebackup -D /data01/digoal/pg_root5290 -F p -x -h 127.0.0.1 -p 5289 -U postgrescd /data01/digoal/pg_root5290
mv recovery.done recovery.confvi postgresql.conf
port = 5290pg_ctl start

准备 schema

进入 template1 数据库,准备 schema。

\c template1 postgres

主表建表语句如下,为了让 schema 尽量大一些,使用这种方法来建立。

create table test(
c0 serial  unique  check(c0>0),
c1 serial  unique  check(c1>0),
c2 serial  unique  check(c2>0),
c3 serial  unique  check(c3>0),
c4 serial  unique  check(c4>0),
c5 serial  unique  check(c5>0),
c6 serial  unique  check(c6>0),
c7 serial  unique  check(c7>0),
c8 serial  unique  check(c8>0),
c9 serial  unique  check(c9>0),
c10 serial unique   check(c10>0),
c11 serial unique   check(c11>0),
c12 serial unique   check(c12>0),
c13 serial unique   check(c13>0),
c14 serial unique   check(c14>0),
c15 serial unique   check(c15>0),
c16 serial unique   check(c16>0),
c17 serial unique   check(c17>0),
c18 serial unique   check(c18>0),
c19 serial unique   check(c19>0),
c20 serial unique   check(c20>0),
c21 serial unique   check(c21>0),
c22 serial unique   check(c22>0),
c23 serial unique   check(c23>0),
c24 serial unique   check(c24>0),
c25 serial unique   check(c25>0),
c26 serial unique   check(c26>0),
c27 serial unique   check(c27>0),
c28 serial unique   check(c28>0),
c29 serial unique   check(c29>0),
c30 serial unique   check(c30>0),
c31 serial unique   check(c31>0),
c32 serial unique   check(c32>0),
c33 serial unique   check(c33>0),
c34 serial unique   check(c34>0),
c35 serial unique   check(c35>0),
c36 serial unique   check(c36>0),
c37 serial unique   check(c37>0),
c38 serial unique   check(c38>0),
c39 serial unique   check(c39>0),
c40 serial unique   check(c40>0),
c41 serial unique   check(c41>0),
c42 serial unique   check(c42>0),
c43 serial unique   check(c43>0),
c44 serial unique   check(c44>0),
c45 serial unique   check(c45>0),
c46 serial unique   check(c46>0),
c47 serial unique   check(c47>0),
c48 serial unique   check(c48>0),
c49 serial unique   check(c49>0),
c50 serial unique   check(c50>0),
c51 serial unique   check(c51>0),
c52 serial unique   check(c52>0),
c53 serial unique   check(c53>0),
c54 serial unique   check(c54>0),
c55 serial unique   check(c55>0),
c56 serial unique   check(c56>0),
c57 serial unique   check(c57>0),
c58 serial unique   check(c58>0),
c59 serial unique   check(c59>0),
c60 serial unique   check(c60>0),
c61 serial unique   check(c61>0),
c62 serial unique   check(c62>0),
c63 serial unique   check(c63>0),
c64 serial unique   check(c64>0),
c65 serial unique   check(c65>0),
c66 serial unique   check(c66>0),
c67 serial unique   check(c67>0),
c68 serial unique   check(c68>0),
c69 serial unique   check(c69>0),
c70 serial unique   check(c70>0),
c71 serial unique   check(c71>0),
c72 serial unique   check(c72>0),
c73 serial unique   check(c73>0),
c74 serial unique   check(c74>0),
c75 serial unique   check(c75>0),
c76 serial unique   check(c76>0),
c77 serial unique   check(c77>0),
c78 serial unique   check(c78>0),
c79 serial unique   check(c79>0),
c80 serial unique   check(c80>0),
c81 serial unique   check(c81>0),
c82 serial unique   check(c82>0),
c83 serial unique   check(c83>0),
c84 serial unique   check(c84>0),
c85 serial unique   check(c85>0),
c86 serial unique   check(c86>0),
c87 serial unique   check(c87>0),
c88 serial unique   check(c88>0),
c89 serial unique   check(c89>0),
c90 serial unique   check(c90>0),
c91 serial unique   check(c91>0),
c92 serial unique   check(c92>0),
c93 serial unique   check(c93>0),
c94 serial unique   check(c94>0),
c95 serial unique   check(c95>0),
c96 serial unique   check(c96>0),
c97 serial unique   check(c97>0),
c98 serial unique   check(c98>0),
c99 serial unique   check(c99>0));

100个字段,每个字段都有一个约束。在数据库元数据中,也会产生一大批系统记录,例如:每个表至少会新增的元数据(没算序列的,算序列还更多)。

pg_class ,      101条 (表+索引) pg_attribute ,  106条 (tableoid, cmax, cmin, xmax, xmin, ctid, 字段)  pg_constraint , 200条 (唯一, check各100个)  pg_depend ,     401条 (表, 索引+唯一约束+check约束)(索引,唯一约束)  pg_index ,      100条 

同时还会产生很多数据文件,每个索引,表都会有一个数据文件,如果算上 fork(vm, fsm, init)的话,就更多了。使用 test 新建 500 张一样的表,会产生较多的元数据变动,同时会产生一堆数据文件。

do language plpgsql $$
declarei int ;
beginfor i in 1..500 loopexecute 'create table test'||i||' (like test including all)';end loop;
end;
$$;

建完表后,template1 就变 500 多 MB 了。

template1=# \l+List of databasesName    |  Owner   | Encoding | Collate | Ctype |   Access privileges   |  Size   | Tablespace |                Description
-----------+----------+----------+---------+-------+-----------------------+---------+------------+--------------------------------------------postgres  | postgres | UTF8     | C       | C     |                       | 1044 MB | pg_default | default administrative connection databasetemplate0 | postgres | UTF8     | C       | C     | =c/postgres          +| 6681 kB | pg_default | unmodifiable empty database|          |          |         |       | postgres=CTc/postgres |         |            | template1 | postgres | UTF8     | C       | C     | =c/postgres          +| 624 MB  | pg_default | default template for new databases|          |          |         |       | postgres=CTc/postgres |         |            | 

测试 drop schema

以 template1 为模板创建新数据库

postgres=# create database db0 with template template1;

记录当前XLOG位点

postgres=# select pg_current_xlog_location();
-[ RECORD 1 ]------------+-----------
pg_current_xlog_location | 1/7394D08

删除 schema

\c db0drop schema public cascade;

记录当前XLOG位点,等待drop schema结束,并记录当前XLOG位点(很长一段时间后稳定(autovacuum)结束)

db0=# select pg_current_xlog_location();
-[ RECORD 1 ]------------+-----------
pg_current_xlog_location | 1/168E6EA8

监控延迟

在主库执行

\xselect
pg_size_pretty(pg_xlog_location_diff(pg_current_xlog_location(),sent_location)),
pg_size_pretty(pg_xlog_location_diff(pg_current_xlog_location(),write_location)),
pg_size_pretty(pg_xlog_location_diff(pg_current_xlog_location(),flush_location)),
pg_size_pretty(pg_xlog_location_diff(pg_current_xlog_location(),replay_location)),
* from pg_stat_replication ;\watch 1

发现备库apply卡在一个REDO REC上很久,如果接下来主库又产生了大量的REDO,那么备库的apply就会延迟严重。主机REDO发送是没有延迟的,也就是说REDO已经在备机那里了,但是还没有被apply。

-[ RECORD 1 ]----+------------------------------
pg_size_pretty   | 0 bytes
pg_size_pretty   | 0 bytes
pg_size_pretty   | 0 bytes
pg_size_pretty   | 56 MB  -- 出现apply延迟
pid              | 27375
usesysid         | 10
usename          | postgres
application_name | walreceiver
client_addr      | 127.0.0.1
client_hostname  |
client_port      | 53164
backend_start    | 2016-10-12 10:17:16.414473+08
backend_xmin     | 2030
state            | streaming
sent_location    | 1/168E6EA8
write_location   | 1/168E6EA8
flush_location   | 1/168E6EA8
replay_location  | 1/13151E28  -- 卡住
sync_priority    | 0
sync_state       | async

备机apply延迟严重的话,另外一个问题就是备机的xlog会占用较大的空间。

延迟分析

使用pg_xlogdump分析 "堵塞" apply的redo rec

pg_xlogdump -b 000000010000000100000013 000000010000000100000014 2>&1 |less

搜索 1/13151E28

rmgr: Transaction len (rec/tot): 17680828/17680860, tx:       2029, lsn: 1/13151E28, prev 1/13151930, bkp: 0000, desc: commit: 2016-10-12 17:04:39.615288 CST; rels:
大量的文件位置
base/400932/199021 base/400932/199422 base/400932/199019 base/400932/199420 base/400932/199017 base/400932/199418 base/400932/199015 base/400932/199416 base/400932/199013
base/400932/199414 base/400932/199011 base/400932/199412 base/400932/199009 base/400932/199410
base/400932/199007 base/400932/199408 base/400932/199005 base/400932/199406 base/400932/199003 base/400932/199404 base/400932/199001 base/400932/199402 base/400932/198999
........
........
lcache 400523 snapshot 2608 relcache 400523 snapshot 2608 snapshot 2608 relcache 400730 relcache 400523 snapshot 2608 relcache 400523 snapshot 2608 relcache 400523 snapshot 2608 snapshot 2608 relcache 400728 relcache 400523 snapshot 2608relcache 400523 snapshot 2608 relcache 400523 snapshot 2608 snapshot 2608 relcache 400726 relcache 400523 snapshot 2608 snapshot 2608 snapshot 2608rmgr: Standby     len (rec/tot):     24/    56, tx:          0, lsn: 1/1423B310, prev 1/13151E28, bkp: 0000, desc: running xacts: nextXid 2030 latestCompletedXid 2029 oldestRunningXid 2030

这笔 redo 很大,十几 MB

db0=# select pg_xlog_location_diff('1/1423B310', '1/13151E28');
-[ RECORD 1 ]---------+---------
pg_xlog_location_diff | 17732840

备库 apply 卡住的地方,跟踪备库 startup 进程(用于 recovery 的进程)在干什么

strace -p $pid  一堆的unlink
unlink("base/400932/307422")            = 0
unlink("base/400932/307422.1")          = -1 ENOENT (No such file or directory)
unlink("base/400932/307422_fsm")        = -1 ENOENT (No such file or directory)
unlink("base/400932/307422_vm")         = -1 ENOENT (No such file or directory)
unlink("base/400932/307422_init")       = -1 ENOENT (No such file or directory)
unlink("base/400932/307420")            = 0
unlink("base/400932/307420.1")          = -1 ENOENT (No such file or directory)
unlink("base/400932/307420_fsm")        = -1 ENOENT (No such file or directory)
unlink("base/400932/307420_vm")         = -1 ENOENT (No such file or directory)
unlink("base/400932/307420_init")       = -1 ENOENT (No such file or directory)
unlink("base/400932/307418")            = 0
unlink("base/400932/307418.1")          = -1 ENOENT (No such file or directory)
unlink("base/400932/307418_fsm")        = -1 ENOENT (No such file or directory)
unlink("base/400932/307418_vm")         = -1 ENOENT (No such file or directory)
unlink("base/400932/307418_init")       = -1 ENOENT (No such file or directory)
unlink("base/400932/307416")            = 0
unlink("base/400932/307416.1")          = -1 ENOENT (No such file or directory)
unlink("base/400932/307416_fsm")        = -1 ENOENT (No such file or directory)
unlink("base/400932/307416_vm")         = -1 ENOENT (No such file or directory)
unlink("base/400932/307416_init")       = -1 ENOENT (No such file or directory)
....

查看一下template1下面有多少个文件,(200多个是系统自带的一些元表的数据文件)有50954多个文件。unlink这些文件至少也要耗费10几分钟。综上可以得出:

1. drop schema 产生了多少 redo,本例的测试用例,约 17MB 的 REDO。

2. 为什么 drop schema 会导致 standby apply 的延迟严重,大量的文件操作,导致了apply 的延迟。

测试基于 database 的 DaaS

记录当前XLOG位点

postgres=# select pg_current_xlog_location();pg_current_xlog_location
--------------------------1/168EE5F8
(1 row)

以template1为模板创建新数据库

postgres=# create database db0 with template template1;

记录当前XLOG位点

postgres=# select pg_current_xlog_location();pg_current_xlog_location
--------------------------1/168F0640
(1 row)

创建数据库产生了多少 REDO

postgres=# select pg_xlog_location_diff('1/168F0640', '1/168EE5F8');
-[ RECORD 1 ]---------+-----
pg_xlog_location_diff | 8264

删除 database

postgres=# drop database db0;
DROP DATABASE

记录当前 XLOG位点

postgres=# select pg_current_xlog_location();pg_current_xlog_location
--------------------------1/168F20E0
(1 row)

drop 数据库产生了多少REDO

postgres=# select pg_xlog_location_diff('1/168F20E0','1/168F0640');
-[ RECORD 1 ]---------+-----
pg_xlog_location_diff | 6816

监控延迟

在主库执行

select
pg_size_pretty(pg_xlog_location_diff(pg_current_xlog_location(),sent_location)),
pg_size_pretty(pg_xlog_location_diff(pg_current_xlog_location(),write_location)),
pg_size_pretty(pg_xlog_location_diff(pg_current_xlog_location(),flush_location)),
pg_size_pretty(pg_xlog_location_diff(pg_current_xlog_location(),replay_location)),
* from pg_stat_replication ;\watch 1

未发现延迟

-[ RECORD 1 ]----+------------------------------
pg_size_pretty   | 0 bytes
pg_size_pretty   | 0 bytes
pg_size_pretty   | 0 bytes
pg_size_pretty   | 0 bytes
pid              | 27375
usesysid         | 10
usename          | postgres
application_name | walreceiver
client_addr      | 127.0.0.1
client_hostname  |
client_port      | 53164
backend_start    | 2016-10-12 10:17:16.414473+08
backend_xmin     | 2046
state            | streaming
sent_location    | 1/168F20E0
write_location   | 1/168F20E0
flush_location   | 1/168F20E0
replay_location  | 1/168F20E0
sync_priority    | 0
sync_state       | async

xlogdump 分析

分析一下 create 和 drop database 产生的 redo 内容

pg_xlogdump -b 000000010000000100000016 000000010000000100000016 2>&1 |less

分析从 1/168EE5F8 到 1/168F20E0 的内容全部如下

rmgr: Standby     len (rec/tot):     24/    56, tx:          0, lsn: 1/168EE5F8, prev 1/168EE5A8, bkp: 0000, desc: running xacts: nextXid 2044 latestCompletedXid 2043 oldestRunningXid 2044
rmgr: Heap        len (rec/tot):     21/  6437, tx:       2044, lsn: 1/168EE630, prev 1/168EE5F8, bkp: 1000, desc: insert: rel 1664/0/12999; tid 0/24backup bkp #0; rel 1664/0/12999; fork: main; block: 0; hole: offset: 120, length: 1832
rmgr: Btree       len (rec/tot):     18/   618, tx:       2044, lsn: 1/168EFF58, prev 1/168EE630, bkp: 1000, desc: insert: rel 1664/0/13001; tid 1/1backup bkp #0; rel 1664/0/13001; fork: main; block: 1; hole: offset: 120, length: 7648
rmgr: Btree       len (rec/tot):     18/   594, tx:       2044, lsn: 1/168F01E0, prev 1/168EFF58, bkp: 1000, desc: insert: rel 1664/0/13002; tid 1/24backup bkp #0; rel 1664/0/13002; fork: main; block: 1; hole: offset: 120, length: 7672
rmgr: Standby     len (rec/tot):     28/    60, tx:          0, lsn: 1/168F0438, prev 1/168F01E0, bkp: 0000, desc: running xacts: nextXid 2045 latestCompletedXid 2043 oldestRunningXid 2044; 1 xacts: 2044
rmgr: XLOG        len (rec/tot):     72/   104, tx:          0, lsn: 1/168F0478, prev 1/168F0438, bkp: 0000, desc: checkpoint: redo 1/168F0438; tli 1; prev tli 1; fpw true; xid 0/2045; oid 401408; multi 1; offset 0; oldest xid 1798 in DB 1; oldest multi 1 in DB 1; oldest running xid 2044; online
rmgr: Database    len (rec/tot):     16/    48, tx:       2044, lsn: 1/168F04E0, prev 1/168F0478, bkp: 0000, desc: create db: copy dir 1/1663 to 400934/1663
rmgr: Standby     len (rec/tot):     28/    60, tx:          0, lsn: 1/168F0510, prev 1/168F04E0, bkp: 0000, desc: running xacts: nextXid 2045 latestCompletedXid 2043 oldestRunningXid 2044; 1 xacts: 2044
rmgr: XLOG        len (rec/tot):     72/   104, tx:          0, lsn: 1/168F0550, prev 1/168F0510, bkp: 0000, desc: checkpoint: redo 1/168F0510; tli 1; prev tli 1; fpw true; xid 0/2045; oid 401408; multi 1; offset 0; oldest xid 1798 in DB 1; oldest multi 1 in DB 1; oldest running xid 2044; online
rmgr: Transaction len (rec/tot):     48/    80, tx:       2044, lsn: 1/168F05B8, prev 1/168F0550, bkp: 0000, desc: commit: 2016-10-12 19:17:16.791771 CST; inval msgs: catcache 21
rmgr: Standby     len (rec/tot):     24/    56, tx:          0, lsn: 1/168F0608, prev 1/168F05B8, bkp: 0000, desc: running xacts: nextXid 2045 latestCompletedXid 2044 oldestRunningXid 2045
rmgr: Heap        len (rec/tot):     26/  6442, tx:       2045, lsn: 1/168F0640, prev 1/168F0608, bkp: 1000, desc: delete: rel 1664/0/12999; tid 0/24 KEYS_UPDATED backup bkp #0; rel 1664/0/12999; fork: main; block: 0; hole: offset: 120, length: 1832
rmgr: Standby     len (rec/tot):     28/    60, tx:          0, lsn: 1/168F1F70, prev 1/168F0640, bkp: 0000, desc: running xacts: nextXid 2046 latestCompletedXid 2044 oldestRunningXid 2045; 1 xacts: 2045
rmgr: XLOG        len (rec/tot):     72/   104, tx:          0, lsn: 1/168F1FB0, prev 1/168F1F70, bkp: 0000, desc: checkpoint: redo 1/168F1F70; tli 1; prev tli 1; fpw true; xid 0/2046; oid 401408; multi 1; offset 0; oldest xid 1798 in DB 1; oldest multi 1 in DB 1; oldest running xid 2045; online
rmgr: Database    len (rec/tot):      8/    40, tx:       2045, lsn: 1/168F2030, prev 1/168F1FB0, bkp: 0000, desc: drop db: dir 400934/1663
rmgr: Transaction len (rec/tot):     48/    80, tx:       2045, lsn: 1/168F2058, prev 1/168F2030, bkp: 0000, desc: commit: 2016-10-12 19:17:30.981401 CST; inval msgs: catcache 21
rmgr: Standby     len (rec/tot):     24/    56, tx:          0, lsn: 1/168F20A8, prev 1/168F2058, bkp: 0000, desc: running xacts: nextXid 2046 latestCompletedXid 2045 oldestRunningXid 2046

create 和 drop database并没有产生很多的日志,也没有那么多的文件操作。只有copy dir和drop dir。文件操作少了,比drop schema快多了。

总结

1. schema 和 database 在物理结构上的差别:database是以目录的形式组织在表空间的目录下的,而schema是以文件的形式在数据库的目录下的,没有再细分独立的目录。所以在drop database时系统调用变得更简单,而drop schema需要挨个文件来。

2. schema和database在元数据上的差别:简单来说就是比擦屁股的动作, drop database擦屁股很快,因为元数据很少只影响pg_databases。drop schema擦屁股就很烦了,要挨个清理pg_class, pg_attribute, 等等元表。  元表清理完还需要vacuum。

3. create 和 drop schema的文件操作很多,是一个个文件进行的,而且都会记录在REDO中,如果schema中有很对对象并且有很多文件的话,会非常慢。

4. create 和 drop database产生的日志少,系统调用也更少。schema不建议作为daas的模板环境频繁(新增和删除时)使用,如果要频繁的创建和删除模板,建议使用database作为模板。

database作为模板的一个缺点是连接复用的问题,因为连接复用需要基于user+database,如果有很多DB的话,连接可能会消耗很多。

5、可以优化改进的地方是把 schema 放到 database 下,新增一个目录存放。删除的时候可以 drop dir,但是清理元数据还是少不了的。schema 与其他 schema 之间的一些依赖关系也需要清理(可能涉及元数据的清理)。

PostgreSQL学习总结(8)—— PostgreSQL 基于数据库和基于模式(schema)的多租户分析相关推荐

  1. 数据库指向默认模式(Schema)

    数据库指向默认模式Schema 应用 1.场景 2.语句 应用 1.场景 在开发中,遇到过新建了一个新的数据库模式,但是你的程序又仅仅依赖这个模式下的表,而且也不想因为 不填模式名而报错,这样的话我们 ...

  2. postgresql学习_在PostgreSQL中学习这些快速技巧

    postgresql学习 PostgreSQL is one of the most popular open source SQL dialects. One of its main advanta ...

  3. 汽车租赁系统java基于数据库_基于数据库和JAVA的网上汽车租赁管理系统的设计(MySQL)...

    基于数据库和JAVA的网上汽车租赁管理系统的设计(MySQL)(论文11000字,程序代码,MySQL数据库) 摘要:本文用JAVA编程语言为主体,用JDBC连接MySQL数据库来设计和实现这个系统. ...

  4. PostgreSQL学习笔记(一)数据库字段类型及含义

    注意:字段类型以navicat顺序为主,即英文字母顺序. 名字 长度 描述 范围 bigserial 8 字节 自增的大范围整数 1 ~ 9223372036854775807 bit - 位串,一串 ...

  5. 一个迷你的 Node.js 基于 Express 的 MVR 模式的 API工程 的分析

    1. 工程说明 该工程是基于 Express 库,编写的一个 API 查询返回的一个微型应用. API Resource 就是把 API 的内容当做网络资源去处理.工程中的路由访问也是返回 API 内 ...

  6. postgresql 学习笔记

    SQL 入门语言 3.1 SQL(Structured Query Lanuage) 特点:它是结构化查询语句,重要的关系型数据库操作语言.PgSQql 的基础语法也同样适用于其他的关系型数据库如:m ...

  7. PostgreSQL中的数据库实例、模式、用户(角色)、表空间

    2019独角兽企业重金招聘Python工程师标准>>> 本文参考:http://blog.csdn.net/kanon_lgt/article/details/5931522 htt ...

  8. 知识分享之PostgreSQL——数据库中的模式(Schema)

    知识分享之PostgreSQL--数据库中的模式(Schema) 背景 日常我们开发时,我们会遇到各种各样的奇奇怪怪的问题(踩坑o(╯□╰)o),这个常见问题系列就是我日常遇到的一些问题的记录文章系列 ...

  9. 基于数据库的事务消息解决分布式事务方案

    转载请注明出处:http://www.cnblogs.com/lizo/p/8516502.html 概述 当单库已不能支撑当前业务的时候,我们往往都考虑进行分库(横向拆分或者纵向拆分).但分库有个无 ...

最新文章

  1. go 类型 value 不支持索引_10分钟掌握PostgreSQL 5种索引的应用场景
  2. centos7 更新firefox版本
  3. matlab程序求一个正交的相似变换矩阵,图像的等距变换,相似变换,仿射变换,射影变换及其matlab实现...
  4. 块级元素(导航,图片,层)的水平和垂直居中
  5. JavaParser入门:以编程方式分析Java代码
  6. 如何提高网页中图片显示的用户体验(附源码下载)
  7. NYOJ 99单词拼接(有向图的欧拉(回)路)
  8. java两个数最大公约数和最小公倍数,java求两个数的最大公约数和最小公倍数
  9. 【华为云实战开发】15.Maven依赖的JAR包下载慢?赶紧看过来
  10. 最好用的虚拟机软件----VMware详细图文教程
  11. MD5之C#密码加密-备忘录
  12. python自学行吗-零基础可以学会python吗?python好学吗?
  13. 百度谷歌2013年母亲节 赏析中文搜索引擎庆祝涂鸦
  14. 将运算放大器(运放)用作比较器
  15. GooFlow获取节点/线信息和自定义节点属性
  16. 质量值体系 Phred33 和 Phred 64 的由来 及其在质量控制中的实际影响
  17. 全网通工业无线路由器多网口工业路由器
  18. 使用Java程序发送邮件|发送有附件的邮件|进行邮件群发
  19. 【第五届集创赛备赛】三、紫光同创李星钢赛题解读直播要点总结
  20. 2021年化工自动化控制仪表新版试题及化工自动化控制仪表找解析

热门文章

  1. 人生苦短我用python壁纸_人生苦短,我用 Python——我如何用 Python 助力工作和生活?...
  2. N5105 构建 Esxi 镜像
  3. Mac母带制作软件:Steinberg WaveLab 11 Pro
  4. FONT face=Verdana再测文字/FONT 的问题
  5. word2016表格文字左右居中
  6. 法切蒂:真正的球迷是不会中途退场
  7. python计算平均绩点_ACM计算平均绩点
  8. Mysql GEOHASH function 实现
  9. Python求解T形矩阵(toeplitz矩阵)
  10. [SSD综述1.6] 固态硬盘物理接口SATA、M.2、U.2、PCIe和BGA图文详解_SSD接口形态(Form Factor)