The oss_fdw extension is a foreign data wrapper (FDW) for PolarDB for PostgreSQL that maps Object Storage Service (OSS) data to foreign tables in your PolarDB cluster. With oss_fdw, you read and write OSS-stored data through standard SQL statements, making it ideal for archiving historical data, read-only data, and cold data to reduce storage costs.
OSS provides secure, cost-effective, and highly reliable cloud storage with 99.995% data availability.
Prerequisites
OSS is activated and a bucket is created. For more information, see What is OSS?
Your PolarDB for PostgreSQL cluster runs one of the following engine versions:
PostgreSQL 16 (revision version 2.0.16.6.2.0 or later)
PostgreSQL 14 (revision version 2.0.14.5.3.0 or later)
PostgreSQL 11 (revision version 2.0.11.2.1.0 or later)
View the revision version in the console or run SHOW polardb_version; to query it. To upgrade, see Version management.
Limitations
oss_fdw foreign tables support only SELECT, INSERT, and TRUNCATE. The UPDATE and DELETE statements are not supported. Once data is written to OSS, it can be read but not modified in place.
Foreign table options reference
When you create an OSS foreign table, use the following options to control how data is stored and organized in OSS:
| Option | Description | Example value |
|---|---|---|
dir | Maps the foreign table to an OSS directory. Each INSERT creates a new file in the directory. | 'archive/' |
prefix | Maps the foreign table to a filename prefix. Each INSERT creates a new file with the prefix. | 'prefix/file_' |
format | Data format. Default: csv. | 'csv' |
compressiontype | Compression algorithm. Default: none. Valid values: gzip, zstd. | 'gzip' |
compressionlevel | Compression level. Higher levels produce smaller files but consume more CPU. | '9' |
Specify either dir or prefix to define the OSS path for the foreign table.
Install the extension
CREATE EXTENSION oss_fdw;Create a foreign data server
Define the OSS connection and map your PolarDB cluster to an OSS bucket.
CREATE SERVER ossserver
FOREIGN DATA WRAPPER oss_fdw
OPTIONS (
host 'oss-cn-xxx.aliyuncs.com',
bucket 'mybucket',
id 'xxx',
key 'xxx'
);The server options are:
| Parameter | Description |
|---|---|
host | OSS endpoint |
bucket | OSS bucket name |
id | AccessKey ID of your Alibaba Cloud account |
key | AccessKey secret of your Alibaba Cloud account |
Map a foreign table to an OSS directory
Create an OSS foreign table mapped to a directory.
CREATE FOREIGN TABLE t1_oss ( id INT, f FLOAT, txt TEXT ) SERVER ossserver OPTIONS (dir 'archive/');Insert data into the foreign table. The data is written to a file in the
archive/directory. Query the foreign table to verify:INSERT INTO t1_oss VALUES (generate_series(1,100), 0.1, 'hello');EXPLAIN SELECT COUNT(*) FROM t1_oss; QUERY PLAN ----------------------------------------------------------------- Aggregate (cost=6.54..6.54 rows=1 width=8) -> Foreign Scan on t1_oss (cost=0.00..6.40 rows=54 width=0) Directory on OSS: archive/ Number Of OSS file: 1 Total size of OSS file: 1292 bytes (5 rows) SELECT COUNT(*) FROM t1_oss; count ------- 100 (1 row)Each subsequent
INSERTcreates a new file in the same OSS directory.INSERT INTO t1_oss VALUES (generate_series(1,100), 0.1, 'hello'); EXPLAIN SELECT COUNT(*) FROM t1_oss; QUERY PLAN ------------------------------------------------------------------- Aggregate (cost=12.07..12.08 rows=1 width=8) -> Foreign Scan on t1_oss (cost=0.00..11.80 rows=108 width=0) Directory on OSS: archive/ Number Of OSS file: 2 Total size of OSS file: 2584 bytes (5 rows) SELECT COUNT(*) FROM t1_oss; count ------- 200 (1 row)Run
TRUNCATEto remove all OSS files mapped to the foreign table.TRUNCATE t1_oss; SELECT COUNT(*) FROM t1_oss; WARNING: does not match any file in oss count ------- 0 (1 row)
Map a foreign table to a directory prefix
Create a foreign table with the
prefixoption.CREATE FOREIGN TABLE t2_oss ( id INT, f FLOAT, txt TEXT ) SERVER ossserver OPTIONS (prefix 'prefix/file_');Each
INSERTcreates a new file with the specified prefix.INSERT INTO t2_oss VALUES (generate_series(1,100), 0.1, 'hello'); INSERT INTO t2_oss VALUES (generate_series(1,100), 0.1, 'hello'); EXPLAIN SELECT COUNT(*) FROM t2_oss; QUERY PLAN ------------------------------------------------------------------- Aggregate (cost=12.07..12.08 rows=1 width=8) -> Foreign Scan on t2_oss (cost=0.00..11.80 rows=108 width=0) Directory on OSS: prefix/file_ Number Of OSS file: 2 Total size of OSS file: 2584 bytes (5 rows) SELECT COUNT(*) FROM t2_oss; count ------- 200 (1 row)
Specify the storage format
oss_fdw stores data in CSV format by default. Specify the format explicitly with the format option. When you run INSERT on an OSS foreign table, data is written in the specified format to an OSS file.
CREATE FOREIGN TABLE t3_oss (
id INT,
f FLOAT,
txt TEXT
)
SERVER ossserver
OPTIONS (dir 'archive_csv/', format 'csv');List files for an OSS foreign table
Create a foreign table and run three
INSERTstatements to write data to three OSS files.CREATE FOREIGN TABLE t4_oss ( id INT, f FLOAT, txt TEXT ) SERVER ossserver OPTIONS (dir 'archive_file_list/'); INSERT INTO t4_oss VALUES (generate_series(1,10000), 0.1, 'hello'); INSERT INTO t4_oss VALUES (generate_series(1,10000), 0.1, 'hello'); INSERT INTO t4_oss VALUES (generate_series(1,10000), 0.1, 'hello');Call
oss_fdw_list_file()with the table name and, optionally, the schema name (defaults topublic) to list the associated files.SELECT * FROM oss_fdw_list_file('t4_oss'); name | size -------------------------------------------+-------- archive_file_list/_t4_oss_783053364762580 | 148894 archive_file_list/_t4_oss_783053364849053 | 148894 archive_file_list/_t4_oss_783053366496328 | 148894 (3 rows) SELECT * FROM oss_fdw_list_file('t4_oss', 'public'); name | size -------------------------------------------+-------- archive_file_list/_t4_oss_783053364762580 | 148894 archive_file_list/_t4_oss_783053364849053 | 148894 archive_file_list/_t4_oss_783053366496328 | 148894 (3 rows)
Compress data with gzip or Zstandard
The compressiontype option specifies the compression algorithm for data written to OSS. By default, no compression is applied. Valid values: gzip and zstd.
The compressionlevel option sets the compression level. Higher levels produce smaller files and reduce network transfer volume, but consume more CPU during compression and decompression.
| Algorithm | Compression level range | Default level | Version requirement |
|---|---|---|---|
| gzip | 1 to 9 | 6 | All supported engine versions |
| Zstandard (zstd) | -7 to 22 | 6 | PostgreSQL 14 (revision version 14.9.13.0 or later) |
gzip compression
gzip compression levels range from 1 to 9, with a default of 6.
CREATE FOREIGN TABLE t5_oss (
id INT,
f FLOAT,
txt TEXT
)
SERVER ossserver
OPTIONS (
dir 'archive_file_compression/',
compressiontype 'gzip',
compressionlevel '9'
);
INSERT INTO t5_oss VALUES (generate_series(1,10000), 0.1, 'hello');
INSERT INTO t5_oss VALUES (generate_series(1,10000), 0.1, 'hello');
INSERT INTO t5_oss VALUES (generate_series(1,10000), 0.1, 'hello');Compare the gzip-compressed file sizes with the uncompressed files:
SELECT * FROM oss_fdw_list_file('t4_oss');
name | size
-------------------------------------------+--------
archive_file_list/_t4_oss_741147680906121 | 148894
archive_file_list/_t4_oss_741147680965631 | 148894
archive_file_list/_t4_oss_741147681201236 | 148894
(3 rows)
SELECT * FROM oss_fdw_list_file('t5_oss');
name | size
-----------------------------------------------------+-------
archive_file_compression/_t5_oss_741147752563794.gz | 23654
archive_file_compression/_t5_oss_741147752633713.gz | 23654
archive_file_compression/_t5_oss_741147752828680.gz | 23654
(3 rows)Zstandard compression
Zstandard (zstd) compression is supported only on clusters running PostgreSQL 14 (revision version 14.9.13.0 or later).
Zstandard compression levels range from -7 to 22, with a default of 6.
CREATE FOREIGN TABLE t6_oss (
id INT,
f FLOAT,
txt TEXT
)
SERVER ossserver
OPTIONS (
dir 'archive_file_zstd/',
compressiontype 'zstd',
compressionlevel '9'
);
INSERT INTO t6_oss VALUES (generate_series(1,10000), 0.1, 'hello');
INSERT INTO t6_oss VALUES (generate_series(1,10000), 0.1, 'hello');
INSERT INTO t6_oss VALUES (generate_series(1,10000), 0.1, 'hello');Compare the Zstandard-compressed file sizes with the uncompressed files:
SELECT * FROM oss_fdw_list_file('t4_oss');
name | size
-------------------------------------------+--------
archive_file_list/_t4_oss_741147680906121 | 148894
archive_file_list/_t4_oss_741147680965631 | 148894
archive_file_list/_t4_oss_741147681201236 | 148894
(3 rows)
SELECT * FROM oss_fdw_list_file('t6_oss');
name | size
-----------------------------------------------+------
archive_file_zstd/_t6_oss_748106174612293.zst | 6710
archive_file_zstd/_t6_oss_748106174700206.zst | 6710
archive_file_zstd/_t6_oss_748106174866829.zst | 6710
(3 rows)Compression size comparison
The following table compares file sizes for 10,000 rows (3 columns) across compression methods at level 9:
| Compression | File size per file | File extension | Reduction |
|---|---|---|---|
| None | 148,894 bytes | (none) | -- |
| gzip (level 9) | 23,654 bytes | .gz | ~84% |
| Zstandard (level 9) | 6,710 bytes | .zst | ~95% |
Remove the extension
DROP EXTENSION oss_fdw;