1

我正在运行两个不同的 postgres 9.3 实例(一个用于生产,一个用于开发/测试)。我想将生产中的表的一个子集复制到开发中。

假设我要复制的表定义为

CREATE TABLE users (user_id varchar PRIMARY KEY, other_stuff varchar);

我要复制的子集是所有在缓存表中具有 user_id 的用户(在生产中),这是一个比用户表小得多的表

CREATE TABLE user_id_subset (user_id varchar PRIMARY KEY);

我已经在我的开发数据库上设置了一些外部表来访问这两个表(分别命名为 foreign_users 和 foreign_user_id_subset),我想做如下查询:

INSERT INTO development_users (user_id, other_stuff) 
    SELECT user_id, other_stuff FROM foreign_users f
    WHERE EXISTS (
        SELECT 1 FROM foreign_user_id_subset ss 
        WHERE ss.user_id=f.user_id)

此查询有效,但我担心性能。解释的结果给了我这样的东西:

'Insert on development_users (cost=262.01..284.09 rows=138 width=272)'
'  ->  Hash Join  (cost=262.01..284.09 rows=138 width=272)'
'        Hash Cond: ((f.user_id)::text = (cache.user_id)::text)'
'        ->  Foreign Scan on foreign_users f  (cost=100.00..118.28 rows=276 width=272)'
'        ->  Hash  (cost=159.52..159.52 rows=200 width=32)'
'              ->  HashAggregate  (cost=157.52..159.52 rows=200 width=32)'
'                    ->  Foreign Scan on foreign_user_id_subset  (cost=100.00..153.86 rows=1462 width=32)'

认为正在发生的事情是我的开发数据库将请求发送到我的生产数据库,它创建了 foreign_user_id_subset 的临时哈希(生产上的 user_id_subset)并在生产上进行哈希检查。这样,唯一通过网络(在数据库之间)发送的是初始请求,然后是选择查询的结果。这是真的?

另一种想法是在我的生产数据库上创建此请求结果的“临时”(不能是真正的 TEMP 表 b/c 我需要一个外部表),然后构建一个外部表并执行SELECT * from development 在外表上。

(应该注意的是,我的生产数据库是比我的开发数据库更昂贵/性能更高的 RDS 实例)

4

1 回答 1

0

回答我自己的问题:

我实现了上述替代想法:在生产中生成仅包含 EXISTS 查询结果的表,然后在开发中创建一个外部表来引用该表。然后为了创建子集表,我只是做了一个'INSERT INTO ...SELECT * FROM ...'。

使用此方法的时间比发布的原始方法快得多。

创建生产表的时间: Total runtime: 204.838 ms

插入开发数据库的时间:Total runtime: 1564.444 ms

并做原来的方法:它慢得让人无法接受,需要> 10分钟才能达到与上述相同的结果(我什至没有等待解释分析完成)

我不知道有更好的方法来确定规划器提供的低级指令,但我相信原始方法执行顺序扫描(通过重复扫描外部表的块)并执行散列开发数据库的比较。

于 2015-07-28T21:15:31.163 回答