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 extensionSQL,以及該裝在哪個 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 型別) | 地理空間資料、距離計算、鄰近搜尋 | 地理專篇 |
| API | pg_graphql | 自動把資料庫 schema 暴露成 GraphQL API | GraphQL 專篇 |
| 工具 | uuid-ossp | 產生各版本 UUID(現多改用內建 gen_random_uuid()) | 本篇 |
| 加密 | pgcrypto | bcrypt 密碼雜湊、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 預設暴露
publicschema,把 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 狀態一致。
最佳實踐總結:
- 一律裝進
extensionsschema(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(慢查詢監控) - 最佳實踐:裝進
extensionsschema、用到才裝、記對啟用名稱、關注版本相依
你現在手上有了一張完整的「工具箱地圖」,知道遇到什麼需求該打開哪一格。而其中一個最能改變資料庫玩法的能力,是讓資料庫自己會思考、會反應——用函式封裝邏輯、用觸發器在資料變動時自動行動。
下一篇《Database Functions 與 Triggers》,我們會教你在資料庫層寫 **Functions(可從客戶端 rpc() 呼叫的伺服器端函式)**與 Triggers(資料變更時自動執行的觸發器),包含 security definer 的注意事項、自動更新 updated_at 的經典模式,以及如何避免無限遞迴等常見坑。裝好了工具箱,接下來讓資料庫動起來。下一篇見。