客户端 → FastAPI 业务层 → psycopg3 连接池 → PostgreSQL 内核 & 扩展
每个模块对应前 18 章的一组知识点。鼠标悬浮卡片看高亮。
INSERT INTOusers(..., password)VALUES(...,crypt(pwd,gen_salt('bf', 10)));-- 校验SELECTidFROMusersWHEREpassword =crypt(pwd, password);
INSERT INTOposts(..., tags)VALUES(...,'["postgres","pgvector"]'::jsonb);-- BEFORE INSERT 触发器自动算出:search_vector :=to_tsvector('simple', title || body);
SELECTid, title,ts_rank(search_vector, q)ASrankFROMposts,websearch_to_tsquery('simple', $1) qWHEREsearch_vector @@ qORDER BYrankDESCLIMIT10;
SELECTid, title,similarity(title, $1)ASsimFROMpostsWHEREtitle % $1-- 相似度 > 0.3ORDER BYtitle <-> $1-- 距离升序LIMIT10;
-- 384 维 MiniLM-L6 向量SELECTp.id, p.title, e.embedding <=> $1::vectorASdistFROMpost_embeddings eJOINposts pONp.id = e.post_idORDER BYe.embedding <=> $1::vectorLIMIT5;
WITH RECURSIVEtreeAS(SELECT*, 1ASdepth,ARRAY[id]ASpathFROMcommentsWHEREpost_id = $1ANDparent_idIS NULLUNION ALLSELECTc.*, t.depth+1, t.path || c.idFROMcomments cJOINtree tONc.parent_id = t.id)SELECT*FROMtreeORDER BYpath;
SELECTid, titleFROMpostsWHEREtenant_id = 1ANDtags @>'["postgres"]'::jsonbORDER BYcreated_atDESC;-- Bitmap Index Scan on idx_posts_tags
CREATE MATERIALIZED VIEWmv_hot_postsASSELECTp.id, p.title,count(l.*)FILTER(WHEREl.created_at >now() -INTERVAL'7 days')ASrecent_likesFROMposts pLEFT JOINpost_likes l ...;-- 每小时:REFRESH MATERIALIZED VIEW CONCURRENTLYmv_hot_posts;
CREATE TABLEposts (...)PARTITION BY RANGE(created_at);CREATE TABLEposts_2025_01PARTITION OFpostsFOR VALUES FROM('2025-01-01')TO('2025-02-01');-- 冷数据归档:ALTER TABLEpostsDETACH PARTITIONposts_2023_01;
ALTER TABLEpostsENABLE ROW LEVEL SECURITY;CREATE POLICYsel_tenantONpostsUSING(tenant_id =current_setting('app.tenant_id')::bigint);-- 业务连接启动时:SELECTset_config('app.tenant_id','1',false);
SELECTsubstring(query, 1, 60)ASq, calls,round(total_exec_time::numeric, 2)FROMpg_stat_statementsORDER BYtotal_exec_timeDESCLIMIT10;
CREATE INDEXON postsUSINGGIN(search_vector);CREATE INDEXON postsUSINGGIN(tags jsonb_path_ops);CREATE INDEXON postsUSINGGIN(title gin_trgm_ops);CREATE INDEXON posts(author_id);CREATE INDEXON posts(tenant_id, status);CREATE INDEXON post_embeddingsUSINGhnsw(embedding vector_cosine_ops);
输入一个关键词,直观感受 全文检索 / 模糊检索 / 语义检索 的差异。
演示用前端的 mock 数据库,不连后端,重点是概念区别。
SELECT*FROMpostsWHEREsearch_vector @@to_tsquery($1)ORDER BYts_rank(search_vector, ...)
SELECT*FROMpostsWHEREtitle % $1ORDER BYtitle <-> $1
SELECT*FROMpost_embeddingsORDER BYembedding <=> $1::vectorLIMIT5