FDW Foreign Data Wrapper
用于通过PG访问外部表
1. 通过cretae server 关联 ip port dbname
2. 通过cretae user mapping 关联 user password
3. 通过 create foreign table 关联外部表在本地的映射,只保存元信息在本地,数据保存在远程表中
4. 本地数据库到远程数据库的链接,就是通过server 和 user mapping 建立的,必要的信息包括:ip,端口,用户,密码,数据库名
查询一个 foreign table 的流程如下;
1. 通过本地的元信息构造表的结构,列的数据类型,属性等
2. 构造优化器节点 create foreign scan 时,根据用户输入内容,构造 sql 语句,如 select a,b from t
最终的优化器节点内保存了获取远程数据库数据的sql语句。
优化器估算外部表的大小时,可以选择使用远程的数据库的信息,通过create server 时指定参数 use_remote_estimate 来设定
当选择了使用远程数据库统计信息时,优化器会连接远程数据库执行 explain ,获取返回的统计信息,包括
cost [startup..total], rows, width 一共4个值;
explain 结果类似下面这样,结果就是 startup=0.00, total=13.10 rows=310, width=230
Seq Scan on t1 (cost=0.00..13.10 rows=310 width=230)
3. 执行器初始化阶段,建立与远程数据库的链接,设置属性的输出函数,构造结构体
4. 执行器执行阶段,调用 ExecForeignScan -> ForeignNext 向远程数据库取数据,通游标的方式获取。
执行器每次获取100条数据,缓存起来,这100用完,继续 fetch;直到取完全部数据或遇到 limit 提前结束。
贴一段代码:
通过cursor每次fetch 100 条的操作就在
fetch_more_data 中做的
-
static TupleTableSlot *
-
postgresIterateForeignScan(ForeignScanState *node)
-
{
-
PgFdwScanState *fsstate = (PgFdwScanState *) node->fdw_state;
-
TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
-
-
/*
-
* If this is the first call after Begin or ReScan, we need to create the
-
* cursor on the remote side.
-
*/
-
if (!fsstate->cursor_exists)
-
create_cursor(node);
-
-
/*
-
* Get some more tuples, if we've run out.
-
*/
-
if (fsstate->next_tuple >= fsstate->num_tuples)
-
{
-
/* No point in another fetch if we already detected EOF, though. */
-
if (!fsstate->eof_reached)
-
fetch_more_data(node);
-
/* If we didn't get any tuples, must be end of data. */
-
if (fsstate->next_tuple >= fsstate->num_tuples)
-
return ExecClearTuple(slot);
-
}
-
-
/*
-
* Return the next tuple.
-
*/
-
ExecStoreTuple(fsstate->tuples[fsstate->next_tuple++],
-
slot,
-
InvalidBuffer,
-
false);
-
-
return slot;
-
}
增删改则是通过 prepare 一个查询,然后通过传递参数的方式一条条执行
在原有的增删改接口中判断,如果是 foreign table, 则进入增删改远程表流程
以delete 为例:
如:delete from t_foreign
1. 先通过 ForeignScan 接口,获取远程数据库的一条元组 的 ctid
2. 将该ctid 传递到 ExecDelete 接口中,该函数调用 postgresExecForeignDelete 进入删除外部表操作
3. 为 delete 语句
DELETE FROM public.t2 WHERE ctid = $1 生成执行计划
4. 在远程数据库执行 3 生成的计划,删除一条元组
5. 重复 1。由于计划只需生成1次,所以后面的删除不需要重新生成计划。
Insert 和 Update 同理。
阅读(3683) | 评论(0) | 转发(0) |