Postgres Extensions 擴充套件總覽 | Supabase 完整教學

2026/09/25
Postgres Extensions 擴充套件總覽 | Supabase 完整教學

Supabase 底層是一個完整的 Postgres,而 Postgres 真正的威力藏在它龐大的 Extensions(擴充套件) 生態裡。一行 create extension,你的資料庫就能多出向量語意搜尋、地理空間查詢、排程任務、非同步 HTTP、加密雜湊等能力。本篇帶你認識 Supabase 預裝的 50+ 個 extension、如何正確啟用它們,以及 pgvector、pg_cron、postgis 等常用套件各自解決什麼問題。

前言

一句話定義本篇主題:這篇要教你 Postgres Extension 是什麼、如何在 Supabase 啟用它們(Dashboard 或 create extension)、有哪些常用套件與各自用途,以及裝設 extension 的最佳實踐。

上一篇《Schema 設計與關聯》我們把多張表用外鍵串起來、補上索引與約束,替資料模型打好了骨架。但骨架只是基礎——真實專案常常需要「資料庫本身就會的超能力」:想做 AI 語意搜尋、想每天半夜自動清一次過期資料、想在資料變更時打一支 HTTP webhook、想算兩個座標之間的距離……這些在別的資料庫可能要靠外部服務,但在 Postgres,一個 Extension 就搞定。

用現實類比:Postgres 核心像一支功能強大的智慧型手機,而 Extension 就是你安裝的 App。 手機出廠就能打電話、傳訊息(基本 SQL 能力),但你想導航就裝地圖 App(postgis)、想記帳就裝記帳 App(pgvector 做向量搜尋)、想定時提醒就用鬧鐘(pg_cron)。這些 App 不會憑空改變手機的本質,而是把新能力「插」進系統,隨叫隨用。Supabase 貼心地幫你在「應用商店」裡預先審核並上架了 50 多個常用 App,你只要開啟開關就能用。

本篇你會學到:

  • Extension 是什麼:它如何把新功能插進 Postgres,以及 Supabase 預裝生態的樣貌
  • 如何啟用:Dashboard 一鍵啟用 vs create extension SQL,以及該裝在哪個 schema
  • 常用 extension 清單:pgvector、pg_cron、pgmq、pg_net、postgis、pg_graphql、uuid-ossp、pgcrypto、pg_stat_statements 各自的用途與後續預告
  • 實作與最佳實踐:可執行的啟用範例,以及「別亂裝、別裝到 public」等常見坑

核心概念

Extension 是什麼

**Extension(擴充套件)**是 Postgres 官方支援的模組化機制:把一組相關的功能——新的資料型別、函式、運算子、索引方法,甚至背景程序——打包成一個單元,用一行 SQL 就能「掛載」進資料庫。啟用之後,這些新功能就跟內建功能一樣自然可用。

關鍵在於:Extension 不是外部程式,而是真正跑在 Postgres 內部。 例如 pgvector 新增了一個 vector 資料型別和 <=>(餘弦距離)運算子,你就能直接在 SQL 裡 order by embedding <=> query_vec;postgis 新增了 geometry 型別和上百個空間函式,讓你在資料庫裡算距離、判斷範圍。這些都是「原生等級」的能力,不需要把資料撈到應用層再處理,效能與一致性都更好。

Supabase 為每個專案預裝了超過 50 個 extension,涵蓋 AI、地理、排程、加密、監控等各領域。它們預設多半是停用狀態(除少數如 uuid-ossp、pgcrypto 等),你只在需要時啟用對應的那幾個即可。

這裡有個重要觀念要先釐清:「預裝」不等於「已啟用」。預裝指的是這個 extension 的程式碼與二進位檔已經內建在 Supabase 的 Postgres 環境裡、隨時可用;啟用才是你實際下 create extension 把它掛載進你這個資料庫的動作。這也是為什麼一般雲端 Postgres 你可能得自己編譯安裝某個 extension,而 Supabase 幫你把「安裝」這一步預先處理好了——你只剩下輕鬆的「啟用」開關。這正是 Supabase 相較於裸機 Postgres 的一大便利:像 pgvector、pg_cron、postgis 這些在別的環境常常得花半天處理安裝的套件,在這裡都是一行 SQL 的事。

常用 Extension 分類對照表

先建立一張全景圖。下表把 Supabase 最常用的 extension 按用途分類,讓你知道遇到什麼需求該找哪一個:

分類Extension主要用途系列後續
AI/向量pgvector(型別名 vector)儲存 Embedding 向量、做語意相似度搜尋第 035 篇深入
排程pg_cron用 cron 表達式在資料庫內排程 SQL 任務排程專篇
佇列pgmq資料庫原生的訊息佇列(Message Queue)佇列專篇
網路pg_net從資料庫非同步發出 HTTP 請求(webhook 基礎)Webhooks 專篇
地理postgis(含 geometry 型別)地理空間資料、距離計算、鄰近搜尋地理專篇
APIpg_graphql自動把資料庫 schema 暴露成 GraphQL APIGraphQL 專篇
工具uuid-ossp產生各版本 UUID(現多改用內建 gen_random_uuid())本篇
加密pgcryptobcrypt 密碼雜湊、AES 加密、SHA-256、亂數本篇
監控pg_stat_statements統計每條 SQL 的執行次數與耗時,找出慢查詢效能專篇

其他你日後可能會遇到的:pgtap(資料庫單元測試)、index_advisor(索引建議)、pgaudit(審計日誌)、btree_gin/btree_gist(讓 GIN/GiST 索引支援一般型別)、hypopg(假設索引,不實際建立就能評估效益)。這篇聚焦「概觀」,讓你對整個工具箱有印象;每一格工具的深入用法留給對應的系列專篇。

運作原理:extension 裝在哪、怎麼被找到

啟用 extension 時,它會在某個 schema 裡建立自己的函式與型別。在 Supabase,官方強烈建議把 extension 統一裝進一個專屬的 extensions schema,而不是預設的 public:

  • 避免污染:postgis 一裝就是上百個函式,全塞進 public 會跟你自己的資料表、函式擠在一起,命名容易撞、也讓 Supabase 自動產生的 API 介面變雜亂。
  • 安全考量:Supabase 的 REST API 預設暴露 public schema,把 extension 函式放這裡等於多開一扇門。放在 extensions 則更乾淨。

你可能會問:裝在 extensions schema,那我呼叫函式時要不要每次都加 extensions. 前綴?不用——Supabase 已經把 extensions 放進資料庫的 search_path(Postgres 尋找物件的路徑清單)裡,所以 gen_random_uuid()、crypt() 這些函式你直接呼叫就能找到,跟裝在 public 一樣方便,但乾淨許多。

順帶一提,有些 extension 並不會乖乖地只裝在你指定的 schema,而是會建立自己專屬的命名空間。例如 pg_cron 會建立一個 cron schema,把 cron.schedule()、cron.job 這些函式與資料表放進去;pg_net 則用 net schema 收納 net.http_post()。這是設計使然,你呼叫時就照著 cron.、net. 前綴用即可。理解這點能幫你在 Dashboard 或 SQL 裡快速找到某個 extension「把東西藏在哪」,除錯時特別有用。

實作範例

打開 Supabase 的 SQL Editor,跟著逐段執行。我們先看啟用與查詢,再用 pgcrypto 和 pg_stat_statements 做兩個最小可跑的示範。

步驟一:啟用與查詢 extension

啟用 extension 的標準寫法是 create extension,加上 if not exists 避免重複啟用時報錯,並用 with schema extensions 指定安裝位置:

-- 啟用 pgcrypto(加密/雜湊工具),裝進 extensions schema
create extension if not exists pgcrypto with schema extensions;

-- 啟用 pgvector:注意 extension 名稱是 vector,型別也叫 vector
create extension if not exists vector with schema extensions;

-- 啟用效能監控
create extension if not exists pg_stat_statements with schema extensions;

命名小陷阱:pgvector 的啟用名稱是 vector(create extension vector),不是 pgvector;它提供的資料型別也叫 vector。這是很多人第一次會卡住的地方。

查詢目前裝了哪些 extension、以及全部可用清單:

-- 查看「已啟用」的 extension 及其版本
select extname, extversion
from pg_extension
order by extname;

-- 查看「所有可安裝」的 extension(含尚未啟用的、可用版本)
select name, default_version, installed_version, comment
from pg_available_extensions
order by name;

停用某個 extension 用 drop extension:

-- 停用(若有其他物件依賴它,需加 cascade,請小心)
drop extension if exists vector;

步驟二:用 pgcrypto 做密碼雜湊與雜湊值

pgcrypto 是最實用的加密工具箱之一。下面示範 bcrypt 密碼雜湊(登入系統常用)與 SHA-256:

-- 產生 bcrypt 雜湊:gen_salt('bf', 12) 產生工作因子 12 的 bcrypt 鹽
select crypt('my_secret_password', gen_salt('bf', 12));
-- 輸出類似:$2a$12$Xy...(每次執行都不同,因為鹽是隨機的)

-- 驗證密碼:用「儲存的雜湊」當鹽重新加密,比對結果是否相同
select crypt('my_secret_password', stored_hash) = stored_hash as is_valid;
-- 輸出:true(密碼正確時)

-- SHA-256 雜湊(例如替資料算指紋)
select encode(digest('data to hash', 'sha256'), 'hex');
-- 輸出:一長串 64 字元的十六進位字串

-- 產生密碼學等級的隨機 bytes(例如做 token)
select encode(gen_random_bytes(16), 'hex');
-- 輸出:32 字元的隨機十六進位字串

注意我們裝在 extensions schema,卻能直接呼叫 crypt()、digest()——這正是前面說的 search_path 已包含 extensions 的好處。

步驟三:用 pg_stat_statements 找出慢查詢

pg_stat_statements 會累積記錄每一條 SQL 的執行統計,是效能調校的第一站。啟用後隨便跑幾個查詢,再讀取統計表:

-- 找出「總耗時最高」的前 10 條查詢
select
  calls,                          -- 被呼叫幾次
  round(total_exec_time::numeric, 2) as total_ms,   -- 累計執行時間(毫秒)
  round(mean_exec_time::numeric, 2) as mean_ms,     -- 平均每次耗時
  query
from extensions.pg_stat_statements
order by total_exec_time desc
limit 10;

total_ms 高代表這條查詢「整體」拖累了資料庫(可能是跑很多次、也可能是單次很慢),是優化的優先目標。之後的效能專篇會搭配 EXPLAIN ANALYZE 深入拆解。

步驟四:其他 extension 的「一鍵預覽」

下面不是要你現在全跑,而是讓你先看到各 extension 啟用後長什麼樣,建立印象:

-- pgvector:新增 vector 型別,可存 Embedding、用 <=> 算餘弦距離(細節見第 035 篇)
create extension if not exists vector with schema extensions;
-- 之後就能:create table docs (id bigint, embedding vector(1536));

-- pg_cron:用 cron 表達式排程 SQL,每天凌晨 3 點清一次過期資料
create extension if not exists pg_cron;
-- 之後就能:select cron.schedule('cleanup', '0 3 * * *', $$delete from sessions where expires_at < now()$$);

-- pg_net:從資料庫非同步發 HTTP,是 Database Webhooks 的底層
create extension if not exists pg_net with schema extensions;
-- 之後就能:select net.http_post(url := 'https://api.example.com/hook', body := '{}'::jsonb);

-- postgis:地理空間,算最近的餐廳(細節見地理專篇)
create extension if not exists postgis with schema extensions;
-- 之後就能:order by location <-> st_point(121.5, 25.0)::geometry

看到規律了嗎?每個 extension 啟用後,都帶來一組專屬的型別(vector、geometry)或函式命名空間(cron.*、net.*),這就是它們把新能力「插」進 Postgres 的方式。

常見錯誤與最佳實踐

坑一:把 extension 裝到 public schema。 圖方便直接 create extension postgis(省略 with schema),它就會裝進 public,混進你自己的資料表與函式,命名容易撞、也讓自動產生的 API 變亂,甚至多開一層安全面。正確做法:一律 create extension <name> with schema extensions,把 extension 集中在專屬 schema。Supabase 的 search_path 已含 extensions,呼叫函式不必加前綴,方便又乾淨。(少數如 pg_cron 因權限機制固定裝在特定位置,跟 Dashboard 預設走即可。)

坑二:一次把 50 個 extension 全裝起來。 「看起來都很有用」不代表要現在全開。每個啟用的 extension 都佔資源、增加版本相依與升級相容的維護負擔,亂裝一堆用不到的只是徒增複雜度與攻擊面。正確做法:用到才裝——需要向量搜尋才 pgvector、需要排程才 pg_cron。把 extensions 當工具箱,遇到需求再取出對應那一格。

坑三:搞錯 extension 的啟用名稱。 最常見是 pgvector——它的啟用名稱是 vector 不是 pgvector(create extension vector)。名稱不對會直接報「extension does not exist」。正確做法:不確定時先查 select * from pg_available_extensions where name ilike '%vector%';,用查到的正確 name 來啟用。

坑四:忽略版本相依與升級。 Extension 有版本,且可能與 Postgres 大版本相依(例如 plv8 在 Postgres 17 已棄用)。升級 Postgres 或 extension 時若沒留意,可能踩到相容性問題。正確做法:用 select extname, extversion from pg_extension; 掌握現況,升級前查閱該 extension 的相容性說明;需要時用 alter extension <name> update; 升級 extension 版本。

坑五:Dashboard 點一點,卻沒納入 migration。 探索期在 Dashboard 手動啟用很方便,但團隊協作或多環境部署時,別人的環境或 production 可能漏掉,導致「本地能跑、線上炸掉」。正確做法:正式專案把啟用寫成 create extension if not exists <name> with schema extensions; 放進 migration 檔,讓每個環境的 extension 狀態一致。

最佳實踐總結:

  • 一律裝進 extensions schema(with schema extensions),別污染 public
  • 用到才啟用,把 extensions 當按需取用的工具箱,別全開
  • 記住正確啟用名稱(尤其 pgvector 是 vector),不確定先查 pg_available_extensions
  • 關注版本與相依,升級前查相容性,用 alter extension ... update 管理版本
  • 正式專案用 migration SQL 管理,Dashboard 適合探索,兩者可並用
  • 善用 pg_extension(已啟用)與 pg_available_extensions(全清單)兩張系統視圖掌握現況

小結

這篇是 Supabase 系列教學的第 006 篇。承接上一篇《Schema 設計與關聯》——我們替資料模型打好了外鍵、索引、約束的骨架,這篇則帶你認識 Postgres 真正的擴充威力:

  • Extension 是什麼:把新型別、函式、能力「插」進 Postgres 的模組化機制,跑在資料庫內部、原生等級;Supabase 預裝 50+ 個
  • 如何啟用:create extension if not exists <name> with schema extensions,或 Dashboard 一鍵;正式專案用 migration SQL 管理才能多環境一致
  • 常用清單:pgvector(向量語意搜尋)、pg_cron(排程)、pgmq(佇列)、pg_net(HTTP/webhook 底層)、postgis(地理)、pg_graphql(GraphQL API)、uuid-ossp/pgcrypto(UUID/加密)、pg_stat_statements(慢查詢監控)
  • 最佳實踐:裝進 extensions schema、用到才裝、記對啟用名稱、關注版本相依

你現在手上有了一張完整的「工具箱地圖」,知道遇到什麼需求該打開哪一格。而其中一個最能改變資料庫玩法的能力,是讓資料庫自己會思考、會反應——用函式封裝邏輯、用觸發器在資料變動時自動行動。

下一篇《Database Functions 與 Triggers》,我們會教你在資料庫層寫 **Functions(可從客戶端 rpc() 呼叫的伺服器端函式)**與 Triggers(資料變更時自動執行的觸發器),包含 security definer 的注意事項、自動更新 updated_at 的經典模式,以及如何避免無限遞迴等常見坑。裝好了工具箱,接下來讓資料庫動起來。下一篇見。

BenZ Software Developer

熱愛技術的軟體開發者,在這裡分享程式開發經驗與學習筆記。

本週主打

AI 自動化入門包

你每天手動在做的那些煩事,其實 AI 可以自己跑。這份給你 10 個照著做就會的自動化工作流 + 50 個複製即用的提示詞,不用會寫程式。

看看這個產品 →