PostgreSQL使用oracle_fdw与Oracle查询性能对比
在PostgreSQL中使用oracle_fdw 安装oracle_fdw插件
安装前要求:
全部功能要求PostgreSQL9.3及以上
Oracle client要求10.1以上
确保PostgreSQL配置了--without-ldap
确保pg_config
在PATH中(用 pg_config --pgxs
测试)
设置了ORACLE_HOME环境变量
下载oracle_fdw源代码 , 并解压到某个目录下,进入文件目录,执行:
安装完毕后,使用psql连接到PostgreSQL;
使用PostgreSQL的超级用户配置oralce_fdw:
1 2 3 testdb=# create extension oracle_fdw; testdb=# create server oracle_121_56 foreign data wrapper oracle_fdw options (dbserver '//192.168.121.56:1521/orcl'); testdb=# create user mapping for public server oracle_121_56 options (user 'dbuser' password 'test');
简单查询,无索引 生成测试数据,创建一个表,并同时添加1百万条数据
1 create table test_table as select rownum as id ,to_char(sysdate + rownum /24 /3600 , 'yyyy-mm-dd hh24:mi:ss' ) as inc_datetime,trunc(dbms_random.value(0 , 100 )) as random_id,dbms_random.string('x' , 20 ) random_string from dual connect by level <= 1000000 ;
创建完表后,在原来表的基础上追加记录1 2 insert into test_table (ID , INC_DATETIME,RANDOM_ID,RANDOM_STRING) select rownum as id , to_char(sysdate + rownum , 'yyyy-mm-dd hh24:mi:ss' ) as inc_datetime,trunc(dbms_random.value(0 , 100 )) as random_id, dbms_random.string('x' , 20 ) random_string from dual connect by level <= 1000000 ;commit ;
上面SQL是利用了Oracle数据库语法的几个实用小技巧实现的:
利用Oracle特有的“connect by”树形连接语法生成测试记录,“level <= 10”表示要生成10记录;
利用rownum虚拟列生成递增的整数数据;
利用sysdate函数加一些简单运算来生成日期数据,本例中是每条记录的时间加1秒;
利用dbms_random.value函数生成随机的数值型数据,本例中是生成0到100之间的随机整数;
利用dbms_random.string函数生成随机的字符型数据,本例中是生成长度为20的随机字符串,字符串中可以包括字符或数字。
to_char(sysdate + rownum, ‘yyyy-mm-dd hh24:mi:ss’) 这里是转换为字符串,如果该字段的类型为TimeStamp时间戳,那这里可以改写一下方法,转换为时间戳 to_timestamp(sysdate + rownum, ‘yyyy-mm-dd hh24:mi:ss’)
PostgreSQL 创建相应的外部表
1 testdb=# create foreign table test_table(id int, inc_datetime varchar(19), random_id int, random_string varchar(4000)) server oracle_121_56 options (schema 'DBUSER', table 'TEST_TABLE');
查询表的行数
1 $ sqlplus dbuser/test@//192.168.121.56:1521/orcl
1 2 3 4 5 SQL> select count(*) from test_table; COUNT(*) 2000000 Elapsed: 00:00:00.13
1 2 3 4 5 6 testdb=# select count(*) from test_table; count 2000000 (1 row) Time: 5264.299 ms (00:05.264)
查看oracle session中真正执行的sql语句,红框为oracle_fdw执行时,oracle session中执行的sql:
在psql中查看select count(*) from test_table;
的执行计划:
可见oracle处理的sql即是查询计划中的oracle query后面的sql
查看网络流量 oracle_fdw的网络流量明显比sqlplus要高出很多。
查询某条记录
1 2 3 4 5 6 7 SQL> select * from test_table where id= 50; ID INC_DATETIME RANDOM_ID RANDOM_STRING 50 2018-07-25 01:13:38 21 2VMPGE0K6Y293T9WRT7G 50 2018-09-13 01:49:31 51 RGUV1BJJNSTNXDMXMVRL Elapsed: 00:00:00.05
1 2 3 4 5 6 7 8 testdb=# select * from test_table where id= 50; id | inc_datetime | random_id | random_string 50 | 2018-07-25 01:13:38 | 21 | 2VMPGE0K6Y293T9WRT7G 50 | 2018-09-13 01:49:31 | 51 | RGUV1BJJNSTNXDMXMVRL (2 rows) Time: 56.811 ms
使用orderby id获取前5行记录
1 2 3 4 5 6 7 8 9 10 11 SQL> select * from test_table order by id offset 0 rows fetch next 5 rows only; ID INC_DATETIME RANDOM_ID RANDOM_STRING 1 2018-07-25 01:12:49 17 5SPF1INUG6S2L1ZSTU7R 1 2018-07-26 01:49:31 63 BIO3ZOV104VLNKZWGDZN 2 2018-07-25 01:12:50 95 HJFAWH9L7SF85YSPNDHV 2 2018-07-27 01:49:31 86 2PNXP02ZYWYYUZQFWVVN 3 2018-07-25 01:12:51 86 T3UQBBMP3O02LGO6ONPF Elapsed: 00:00:00.32
1 2 3 4 5 6 7 8 9 10 11 testdb=# select * from test_table order by id offset 0 rows fetch next 5 rows only; id | inc_datetime | random_id | random_string 1 | 2018-07-25 01:12:49 | 17 | 5SPF1INUG6S2L1ZSTU7R 1 | 2018-07-26 01:49:31 | 63 | BIO3ZOV104VLNKZWGDZN 2 | 2018-07-27 01:49:31 | 86 | 2PNXP02ZYWYYUZQFWVVN 2 | 2018-07-25 01:12:50 | 95 | HJFAWH9L7SF85YSPNDHV 3 | 2018-07-25 01:12:51 | 86 | T3UQBBMP3O02LGO6ONPF (5 rows) Time: 1169.874 ms (00:01.170)
使用orderby random_string获取前5行记录
1 2 3 4 5 6 7 8 9 10 11 select * from test_table order by random_string offset 0 rows fetch next 5 rows only ; ID INC_DATETIME RANDOM_ID RANDOM_STRING 938145 2018-08-04 21:48:33 86 00008E7XPHROOHEPUYRC 686337 2018-08-01 23:51:45 31 00008JW9S5PXE19F4W4M 19954 2073-03-12 01:49:31 69 0000G3A2KNDLVN61WOSH 382404 3065-07-20 01:49:31 41 0000JDLZP2J8VZFOJ44J 234567 2660-10-14 01:49:31 78 000142EWU0B3GMIPA2AL Elapsed: 00:00:00.33
1 2 3 4 5 6 7 8 9 10 11 testdb=# select * from test_table order by random_string offset 0 rows fetch next 5 rows only; id | inc_datetime | random_id | random_string 938145 | 2018-08-04 21:48:33 | 86 | 00008E7XPHROOHEPUYRC 686337 | 2018-08-01 23:51:45 | 31 | 00008JW9S5PXE19F4W4M 19954 | 2073-03-12 01:49:31 | 69 | 0000G3A2KNDLVN61WOSH 382404 | 3065-07-20 01:49:31 | 41 | 0000JDLZP2J8VZFOJ44J 234567 | 2660-10-14 01:49:31 | 78 | 000142EWU0B3GMIPA2AL (5 rows) Time: 13275.162 ms (00:13.275)
oracle_fdw执行时,oracle session中执行的sql
psql中查看执行计划
网络流量对比
简单查询,带索引 创建id索引
1 create index test_id on test_table(id );
查询某条记录
1 2 3 4 5 6 SQL> select * from test_table where id = 8222; ID INC_DATETIME RANDOM_ID RANDOM_STRING 8222 2018-07-25 03:29:50 68 0VJJSTBAN6RAINSTWQAB 8222 2041-01-27 01:49:31 42 3SAYJV50LNDHURP5FU0K Elapsed: 00:00:00.07
1 2 3 4 5 6 7 testdb=# select * from test_table where id = 8222; id | inc_datetime | random_id | random_string 8222 | 2018-07-25 03:29:50 | 68 | 0VJJSTBAN6RAINSTWQAB 8222 | 2041-01-27 01:49:31 | 42 | 3SAYJV50LNDHURP5FU0K (2 rows) Time: 6.565 ms
使用orderby id获取前5行记录
1 2 3 4 5 6 7 8 9 10 SQL> select * from test_table order by id offset 0 rows fetch next 5 rows only; ID INC_DATETIME RANDOM_ID RANDOM_STRING 1 2018-07-25 01:12:49 17 5SPF1INUG6S2L1ZSTU7R 1 2018-07-26 01:49:31 63 BIO3ZOV104VLNKZWGDZN 2 2018-07-25 01:12:50 95 HJFAWH9L7SF85YSPNDHV 2 2018-07-27 01:49:31 86 2PNXP02ZYWYYUZQFWVVN 3 2018-07-25 01:12:51 86 T3UQBBMP3O02LGO6ONPF Elapsed: 00:00:00.33
1 2 3 4 5 6 7 8 9 10 testdb=# select * from test_table order by id offset 0 rows fetch next 5 rows only; id | inc_datetime | random_id | random_string 1 | 2018-07-25 01:12:49 | 17 | 5SPF1INUG6S2L1ZSTU7R 1 | 2018-07-26 01:49:31 | 63 | BIO3ZOV104VLNKZWGDZN 2 | 2018-07-27 01:49:31 | 86 | 2PNXP02ZYWYYUZQFWVVN 2 | 2018-07-25 01:12:50 | 95 | HJFAWH9L7SF85YSPNDHV 3 | 2018-07-25 01:12:51 | 86 | T3UQBBMP3O02LGO6ONPF (5 rows) Time: 1345.988 ms (00:01.346)
创建random_string索引
1 create index test_string on test_table(random_string);
查询某条记录
1 2 3 4 5 6 SQL> select * from test_table where random_string='GMX0VD9WY4YPN8T4XDML'; ID INC_DATETIME RANDOM_ID RANDOM_STRING 871 2018-07-25 01:27:19 45 GMX0VD9WY4YPN8T4XDML Elapsed: 00:00:00.01
1 2 3 4 5 6 7 testdb=# select * from test_table where random_string='GMX0VD9WY4YPN8T4XDML'; id | inc_datetime | random_id | random_string 871 | 2018-07-25 01:27:19 | 45 | GMX0VD9WY4YPN8T4XDML (1 row) Time: 118.376 ms
使用order by random_string获取前5条记录
1 2 3 4 5 6 7 8 9 10 SQL> select * from test_table order by random_string offset 0 rows fetch next 5 rows only; ID INC_DATETIME RANDOM_ID RANDOM_STRING 938145 2018-08-04 21:48:33 86 00008E7XPHROOHEPUYRC 686337 2018-08-01 23:51:45 31 00008JW9S5PXE19F4W4M 19954 2073-03-12 01:49:31 69 0000G3A2KNDLVN61WOSH 382404 3065-07-20 01:49:31 41 0000JDLZP2J8VZFOJ44J 234567 2660-10-14 01:49:31 78 000142EWU0B3GMIPA2AL Elapsed: 00:00:00.36
1 2 3 4 5 6 7 8 9 10 testdb=# select * from test_table order by random_string offset 0 rows fetch next 5 rows only; id | inc_datetime | random_id | random_string 938145 | 2018-08-04 21:48:33 | 86 | 00008E7XPHROOHEPUYRC 686337 | 2018-08-01 23:51:45 | 31 | 00008JW9S5PXE19F4W4M 19954 | 2073-03-12 01:49:31 | 69 | 0000G3A2KNDLVN61WOSH 382404 | 3065-07-20 01:49:31 | 41 | 0000JDLZP2J8VZFOJ44J 234567 | 2660-10-14 01:49:31 | 78 | 000142EWU0B3GMIPA2AL (5 rows) Time: 12848.595 ms (00:12.849)
创建random_id,random_string复合索引
1 create index test_id_string on test_table(random_id,random_string);
查询某条记录
1 2 3 4 5 6 SQL> select * from test_table where random_id=74 and random_string='6PP2R3M0K4ARK411VFC3'; ID INC_DATETIME RANDOM_ID RANDOM_STRING 4067 2018-07-25 02:20:35 74 6PP2R3M0K4ARK411VFC3 Elapsed: 00:00:00.00
1 2 3 4 5 6 7 testdb=# select * from test_table where random_id=74 and random_string='6PP2R3M0K4ARK411VFC3'; id | inc_datetime | random_id | random_string 4067 | 2018-07-25 02:20:35 | 74 | 6PP2R3M0K4ARK411VFC3 (1 row) Time: 10.488 ms
orderby
1 2 3 4 5 6 7 8 9 SQL> select * from test_table order by random_id,random_string offset 0 rows fetch next 5 rows only; ID INC_DATETIME RANDOM_ID RANDOM_STRING 231792 2018-07-27 17:36:00 0 000LENLB2SJ8M8AZKTOD 691626 2018-08-02 01:19:54 0 003GODBKGMRMZC3LTK8Z 582719 3613-12-29 01:49:31 0 0052V1U6439AGAAAW3QZ 762898 2018-08-02 21:07:46 0 0081R0VHHHJTRTPTL8RG 141007 2404-08-17 01:49:31 0 008PFJM81W6NR83WFNXQ Elapsed: 00:00:00.33
1 2 3 4 5 6 7 8 9 10 11 testdb=# select * from test_table order by random_id,random_string offset 0 rows fetch next 5 rows only; id | inc_datetime | random_id | random_string 231792 | 2018-07-27 17:36:00 | 0 | 000LENLB2SJ8M8AZKTOD 691626 | 2018-08-02 01:19:54 | 0 | 003GODBKGMRMZC3LTK8Z 582719 | 3613-12-29 01:49:31 | 0 | 0052V1U6439AGAAAW3QZ 762898 | 2018-08-02 21:07:46 | 0 | 0081R0VHHHJTRTPTL8RG 141007 | 2404-08-17 01:49:31 | 0 | 008PFJM81W6NR83WFNXQ (5 rows) Time: 12857.763 ms (00:12.858)
关联查询
1 2 3 4 5 6 7 select a.user_name,b.fee from users a,phone_fee b where a.user_id=b.user_id and a.user_id=4999998 ;USER_NAME FEE C58IV8Z0HKYO 297.78 Elapsed: 00:00:00.27
1 2 3 4 5 6 7 testdb=# select a.user_name,b.fee from users a,phone_fee b where a.user_id=b.user_id and a.user_id=4999998; user_name | fee C58IV8Z0HKYO | 297.78 (1 row) Time: 139.633 ms
psql的执行计划1 2 3 4 5 6 7 8 9 10 11 12 13 14 testdb=# explain select a.user_name,b.fee from users a,phone_fee b where a.user_id=b.user_id and a.user_id=4999998; QUERY PLAN Nested Loop (cost=20000.00..52502.50 rows=1000000 width=134) -> Foreign Scan on users a (cost=10000.00..20000.00 rows=1000 width=134) Oracle query: SELECT r1."USER_ID" , r1."USER_NAME" FROM "DBUSER" ."USERS" r1 WHERE (r1."USER_ID" = 4999998 ) -> Materialize (cost =10000.00 ..20005 .00 rows =1000 width=32 ) -> Foreign Scan on phone_fee b (cost =10000.00 ..20000 .00 rows =1000 width=32 ) Oracle query : SELECT r2."USER_ID" , r2."FEE" FROM "DBUSER" ."PHONE_FEE" r2 WHERE (r2."USER_ID" = 4999998 ) (6 rows )
orderby
1 2 3 4 5 6 7 8 9 10 11 SQL> select users.user_id,phone_fee.fee,phone_fee.fee_date from users ,phone_fee where users.user_id=phone_fee.user_id order by users.user_id desc offset 0 rows fetch next 5 rows only; USER_ID FEE FEE_DATE 4999998 297.78 30-APR-15 4999997 243.36 31-MAY-15 4999996 69.79 29-JAN-12 4999992 91.03 07-OCT-17 4999992 268.93 01-FEB-15 Elapsed: 00:00:00.71
1 2 3 4 5 6 7 8 9 10 11 testdb=# select users.user_id,phone_fee.fee,phone_fee.fee_date from users ,phone_fee where users.user_id=phone_fee.user_id order by users.user_id desc offset 0 rows fetch next 5 rows only; user_id | fee | fee_date 4999998 | 297.78 | 2015-04-30 4999997 | 243.36 | 2015-05-31 4999996 | 69.79 | 2012-01-29 4999992 | 91.03 | 2017-10-07 4999992 | 268.93 | 2015-02-01 (5 rows) Time: 27477.661 ms (00:27.478)
psql的执行计划1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 testdb=# explain select users.user_id,phone_fee.fee,phone_fee.fee_date from users ,phone_fee where users.user_id=phone_fee.user_id order by users.user_id desc offset 0 rows fetch next 5 rows only; QUERY PLAN Limit (cost=20016.61..20016.62 rows=5 width=36) -> Sort (cost=20016.61..20019.11 rows=1000 width=36) Sort Key: users.user_id DESC -> Foreign Scan (cost=10000.00..20000.00 rows=1000 width=36) Oracle query: SELECT r1."USER_ID" , r2."FEE" , r2."FEE_DATE" FROM ("DBUSER" ."USERS" r1 INNER JOIN "DBUSER" ."PHONE_FEE" r2 ON (r1."USER_ID" = r2."USER_ID" )) (5 rows )
oracle session中执行的sql
流量情况
可见oracle_fdw实质上发送的是连接sql,拿到oracle返回的结果,再进行排序的。因此中间消耗的时间里,网络传输数据的消耗是占很大部分的。
结论 oracle_fdw的查询效率主要受发送给oracle的sql查询结果集的数据量影响的,结果集越大,网络IO消耗越多,对查询的影响越大。