@gordon.gan/specflow 1.4.0-beta → 1.4.2-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/prompts/approval/database-guidance.md +79 -0
- package/prompts/approval/generate.md +600 -290
- package/skills/database/LICENSE +405 -0
- package/skills/database/ORIGIN.md +6 -0
- package/skills/database/README.md +30 -0
- package/skills/database/elasticsearch/LICENSE.txt +202 -0
- package/skills/database/elasticsearch/SKILL.md +199 -0
- package/skills/database/elasticsearch/examples/01-fulltext-search.md +215 -0
- package/skills/database/elasticsearch/examples/02-aggregation-report.md +206 -0
- package/skills/database/elasticsearch/examples/03-reindex-zero-downtime.md +200 -0
- package/skills/database/elasticsearch/examples/04-cluster-monitoring.md +204 -0
- package/skills/database/elasticsearch/references/01-query-dsl-fulltext.md +162 -0
- package/skills/database/elasticsearch/references/02-query-dsl-term.md +210 -0
- package/skills/database/elasticsearch/references/03-aggregations-metric.md +161 -0
- package/skills/database/elasticsearch/references/04-aggregations-bucket.md +236 -0
- package/skills/database/elasticsearch/references/05-mapping-types.md +134 -0
- package/skills/database/elasticsearch/references/06-analyzers.md +187 -0
- package/skills/database/elasticsearch/references/07-cluster-ops.md +225 -0
- package/skills/database/elasticsearch/references/08-elk-integration.md +170 -0
- package/skills/database/mysql/SKILL.md +195 -0
- package/skills/database/mysql/examples/01-connection-pool.md +75 -0
- package/skills/database/mysql/examples/02-slow-query-optimization.md +98 -0
- package/skills/database/mysql/examples/03-master-slave-setup.md +144 -0
- package/skills/database/mysql/examples/04-backup-strategy.md +212 -0
- package/skills/database/mysql/references/01-functions-string.md +103 -0
- package/skills/database/mysql/references/02-functions-date.md +152 -0
- package/skills/database/mysql/references/03-functions-aggregate-window.md +167 -0
- package/skills/database/mysql/references/04-functions-json.md +129 -0
- package/skills/database/mysql/references/05-sql-ddl-types.md +235 -0
- package/skills/database/mysql/references/06-index-optimization.md +232 -0
- package/skills/database/mysql/references/07-replication-ha.md +213 -0
- package/skills/database/mysql/references/08-backup-restore.md +207 -0
- package/skills/database/mysql/references/09-advanced-features.md +345 -0
- package/skills/database/oracle/LICENSE.txt +202 -0
- package/skills/database/oracle/SKILL.md +238 -0
- package/skills/database/oracle/examples/01-plsql-procedure.md +90 -0
- package/skills/database/oracle/examples/02-awr-analysis.md +99 -0
- package/skills/database/oracle/examples/03-rman-backup.md +108 -0
- package/skills/database/oracle/examples/04-dataguard-setup.md +146 -0
- package/skills/database/oracle/references/01-functions-string.md +91 -0
- package/skills/database/oracle/references/02-functions-date.md +71 -0
- package/skills/database/oracle/references/03-analytic-functions.md +103 -0
- package/skills/database/oracle/references/04-plsql-guide.md +303 -0
- package/skills/database/oracle/references/05-performance-tuning.md +164 -0
- package/skills/database/oracle/references/06-backup-recovery.md +115 -0
- package/skills/database/oracle/references/07-dataguard-rac.md +76 -0
- package/skills/database/oracle/references/08-security.md +170 -0
- package/skills/database/oracle/references/09-sql-syntax.md +152 -0
- package/skills/database/oracle/references/10-features.md +174 -0
- package/skills/database/postgresql/LICENSE.txt +202 -0
- package/skills/database/postgresql/SKILL.md +182 -0
- package/skills/database/postgresql/examples/.gitkeep +0 -0
- package/skills/database/postgresql/examples/01-jsonb-query.md +72 -0
- package/skills/database/postgresql/examples/02-cte-recursive.md +110 -0
- package/skills/database/postgresql/examples/03-performance-tuning.md +114 -0
- package/skills/database/postgresql/examples/04-streaming-replication.md +113 -0
- package/skills/database/postgresql/references/.gitkeep +0 -0
- package/skills/database/postgresql/references/01-functions-string.md +174 -0
- package/skills/database/postgresql/references/02-functions-datetime.md +54 -0
- package/skills/database/postgresql/references/03-functions-aggregate-window.md +142 -0
- package/skills/database/postgresql/references/04-functions-jsonb.md +117 -0
- package/skills/database/postgresql/references/05-fulltext-search.md +109 -0
- package/skills/database/postgresql/references/06-index-types.md +95 -0
- package/skills/database/postgresql/references/07-partition-fdw.md +133 -0
- package/skills/database/postgresql/references/08-replication-backup.md +215 -0
- package/skills/database/redis/LICENSE.txt +202 -0
- package/skills/database/redis/SKILL.md +922 -0
- package/skills/database/redis/examples/01-cache-usage.md +104 -0
- package/skills/database/redis/examples/02-session-storage.md +72 -0
- package/skills/database/redis/examples/03-leaderboard.md +63 -0
- package/skills/database/redis/examples/04-redis-cluster-setup.md +70 -0
- package/skills/database/redis/examples/05-stream-queue.md +65 -0
- package/skills/database/redis/references/command-quick-ref.md +180 -0
- package/skills/database/redis/references/commands-admin-key.md +413 -0
- package/skills/database/redis/references/commands-set-sorted-advanced.md +539 -0
- package/skills/database/redis/references/commands-string-hash-list.md +458 -0
- package/skills/database/redis/references/memory-optimization.md +150 -0
- package/skills/database/redis/references/redis-conf-production.md +139 -0
- package/skills/specflow-approval/SKILL.md +102 -181
- package/templates/approval.md +321 -221
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# JSONB 函数与操作详解
|
|
2
|
+
|
|
3
|
+
## 访问操作符
|
|
4
|
+
|
|
5
|
+
```sql
|
|
6
|
+
-- -> 返回 JSONB, ->> 返回 TEXT
|
|
7
|
+
SELECT
|
|
8
|
+
config -> 'theme' AS theme_jsonb, -- "dark"
|
|
9
|
+
config ->> 'theme' AS theme_text, -- dark
|
|
10
|
+
config -> 'notifications' -> 'email' AS email_jsonb,
|
|
11
|
+
config #>> '{preferences, language}' AS lang
|
|
12
|
+
|
|
13
|
+
FROM user_configs WHERE user_id = 1;
|
|
14
|
+
|
|
15
|
+
-- #> / #>> 路径访问
|
|
16
|
+
SELECT config #> '{preferences, timezone}' AS tz,
|
|
17
|
+
config #>> '{notifications, push}' AS push
|
|
18
|
+
FROM user_configs WHERE user_id = 1;
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 包含与存在操作
|
|
22
|
+
|
|
23
|
+
```sql
|
|
24
|
+
-- @> — 包含(业务场景:查询包含特定配置的用户)
|
|
25
|
+
SELECT user_id, config FROM user_configs
|
|
26
|
+
WHERE config @> '{"notifications": {"email": true}}';
|
|
27
|
+
|
|
28
|
+
-- ? — 是否存在键
|
|
29
|
+
SELECT user_id FROM user_configs WHERE config ? 'trust_score';
|
|
30
|
+
|
|
31
|
+
-- ?| — 存在任意键
|
|
32
|
+
SELECT user_id FROM user_configs WHERE config ?| ARRAY['trust_score', 'vip_level'];
|
|
33
|
+
|
|
34
|
+
-- ?& — 包含所有键
|
|
35
|
+
SELECT user_id FROM user_configs WHERE config ?& ARRAY['theme', 'notifications'];
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 修改函数
|
|
39
|
+
|
|
40
|
+
```sql
|
|
41
|
+
-- || — JSONB 合并
|
|
42
|
+
UPDATE user_configs SET config = config || '{"vip_level": 2}' WHERE user_id = 1;
|
|
43
|
+
|
|
44
|
+
-- JSONB_SET — 设置路径值
|
|
45
|
+
UPDATE user_configs SET config = JSONB_SET(config, '{notifications, email}', 'false'::JSONB)
|
|
46
|
+
WHERE user_id = 1;
|
|
47
|
+
|
|
48
|
+
-- JSONB_INSERT — 插入不覆盖 (PG 9.6+)
|
|
49
|
+
SELECT JSONB_INSERT('{"a":1,"b":2}'::JSONB, '{c}', '3'::JSONB);
|
|
50
|
+
|
|
51
|
+
-- JSONB_STRIP_NULLS — 移除 null
|
|
52
|
+
SELECT JSONB_STRIP_NULLS('{"a":1,"b":null}'::JSONB); -- {"a": 1}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 构建函数
|
|
56
|
+
|
|
57
|
+
```sql
|
|
58
|
+
-- JSONB_BUILD_OBJECT / JSONB_BUILD_ARRAY
|
|
59
|
+
SELECT JSONB_BUILD_OBJECT(
|
|
60
|
+
'id', 101, 'name', 'Alice',
|
|
61
|
+
'roles', JSONB_BUILD_ARRAY('admin', 'editor'),
|
|
62
|
+
'meta', JSONB_BUILD_OBJECT('last_login', NOW())
|
|
63
|
+
);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 展开函数
|
|
67
|
+
|
|
68
|
+
```sql
|
|
69
|
+
-- JSONB_EACH — 展开为 (key, value) 行集
|
|
70
|
+
SELECT * FROM JSONB_EACH((SELECT config FROM user_configs WHERE user_id = 1));
|
|
71
|
+
|
|
72
|
+
-- JSONB_EACH_TEXT — 展开为 (key, text_value)
|
|
73
|
+
SELECT * FROM JSONB_EACH_TEXT((SELECT config FROM user_configs WHERE user_id = 1));
|
|
74
|
+
|
|
75
|
+
-- JSONB_OBJECT_KEYS — 仅返回键
|
|
76
|
+
SELECT * FROM JSONB_OBJECT_KEYS((SELECT config FROM user_configs WHERE user_id = 1));
|
|
77
|
+
|
|
78
|
+
-- JSONB_EXTRACT_PATH — 提取路径
|
|
79
|
+
SELECT JSONB_EXTRACT_PATH(config, 'preferences', 'language') FROM user_configs;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 类型检查与格式化
|
|
83
|
+
|
|
84
|
+
```sql
|
|
85
|
+
-- JSONB_TYPEOF (PG 14+)
|
|
86
|
+
SELECT JSONB_TYPEOF(config -> 'theme'), -- string
|
|
87
|
+
JSONB_TYPEOF(config -> 'tags'), -- array
|
|
88
|
+
JSONB_TYPEOF(config -> 'trust_score') -- number
|
|
89
|
+
FROM user_configs WHERE user_id = 1;
|
|
90
|
+
|
|
91
|
+
-- JSONB_PRETTY (PG 14+)
|
|
92
|
+
SELECT JSONB_PRETTY(config) FROM user_configs WHERE user_id = 1;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## GIN 索引
|
|
96
|
+
|
|
97
|
+
```sql
|
|
98
|
+
-- 标准 GIN
|
|
99
|
+
CREATE INDEX idx_config_gin ON user_configs USING GIN (config);
|
|
100
|
+
|
|
101
|
+
-- jsonb_path_ops(更小更快,不支持 ? 操作符)
|
|
102
|
+
CREATE INDEX idx_config_path ON user_configs USING GIN (config jsonb_path_ops);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 完整示例表
|
|
106
|
+
|
|
107
|
+
```sql
|
|
108
|
+
CREATE TABLE user_configs (
|
|
109
|
+
id BIGSERIAL PRIMARY KEY,
|
|
110
|
+
user_id INTEGER NOT NULL,
|
|
111
|
+
config JSONB NOT NULL DEFAULT '{}'
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
INSERT INTO user_configs (user_id, config) VALUES
|
|
115
|
+
(1, '{"theme":"dark","notifications":{"email":true},"preferences":{"language":"zh-CN","timezone":"Asia/Shanghai"},"tags":["developer","premium"],"trust_score":4.5}'),
|
|
116
|
+
(2, '{"theme":"light","notifications":{"email":false},"preferences":{"language":"en","timezone":"America/New_York"},"tags":["basic"]}');
|
|
117
|
+
```
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# 全文搜索详解
|
|
2
|
+
|
|
3
|
+
## 基础概念
|
|
4
|
+
|
|
5
|
+
PostgreSQL 全文搜索基于 **tsvector** (文本搜索向量) 和 **tsquery** (文本搜索查询),配合 GIN 索引实现高效搜索。
|
|
6
|
+
|
|
7
|
+
## 建表与索引
|
|
8
|
+
|
|
9
|
+
```sql
|
|
10
|
+
CREATE TABLE documents (
|
|
11
|
+
id SERIAL PRIMARY KEY,
|
|
12
|
+
title TEXT NOT NULL,
|
|
13
|
+
body TEXT NOT NULL,
|
|
14
|
+
body_tsv TSVECTOR GENERATED ALWAYS AS (to_tsvector('english', body)) STORED
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE INDEX idx_documents_body_tsv ON documents USING GIN (body_tsv);
|
|
18
|
+
|
|
19
|
+
INSERT INTO documents (title, body) VALUES
|
|
20
|
+
('PostgreSQL Full Text Search',
|
|
21
|
+
'PostgreSQL provides full-text search capabilities out of the box.'),
|
|
22
|
+
('Indexing Strategies',
|
|
23
|
+
'Proper indexing is crucial for database performance. GIN indexes are optimized for full-text search.'),
|
|
24
|
+
('Database Performance Tuning',
|
|
25
|
+
'Performance tuning involves many aspects including query optimization, indexing strategy, and hardware configuration.');
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 核心函数
|
|
29
|
+
|
|
30
|
+
```sql
|
|
31
|
+
-- to_tsvector — 文本转搜索向量(停用词被移除, 动词被词根化)
|
|
32
|
+
SELECT to_tsvector('english', 'The quick brown fox jumps over the lazy dog');
|
|
33
|
+
-- 'brown':3 'dog':9 'fox':4 'jump':5 'lazi':8 'quick':2
|
|
34
|
+
|
|
35
|
+
-- to_tsquery — 文本转搜索查询
|
|
36
|
+
SELECT to_tsquery('english', 'search & indexing');
|
|
37
|
+
-- 'search' & 'index'
|
|
38
|
+
|
|
39
|
+
-- plainto_tsquery — 简单转换(空格分隔的单词自动加 &)
|
|
40
|
+
SELECT plainto_tsquery('english', 'full text search');
|
|
41
|
+
-- 'full' & 'text' & 'search'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 匹配查询
|
|
45
|
+
|
|
46
|
+
```sql
|
|
47
|
+
-- @@ — 全文搜索匹配操作符
|
|
48
|
+
SELECT id, title FROM documents
|
|
49
|
+
WHERE body_tsv @@ to_tsquery('english', 'search & index');
|
|
50
|
+
|
|
51
|
+
-- plainto_tsquery 简化写法
|
|
52
|
+
SELECT id, title FROM documents
|
|
53
|
+
WHERE body_tsv @@ plainto_tsquery('english', 'full text search');
|
|
54
|
+
|
|
55
|
+
-- 直接对原始列搜索(不依赖 tsvector 列)
|
|
56
|
+
SELECT id, title FROM documents
|
|
57
|
+
WHERE to_tsvector('english', body) @@ to_tsquery('english', 'search');
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 排序与高亮
|
|
61
|
+
|
|
62
|
+
```sql
|
|
63
|
+
-- ts_rank / ts_rank_cd — 相关性排序
|
|
64
|
+
SELECT id, title, ts_rank(body_tsv, query) AS rank
|
|
65
|
+
FROM documents, to_tsquery('english', 'search & indexing') AS query
|
|
66
|
+
WHERE body_tsv @@ query ORDER BY rank DESC;
|
|
67
|
+
|
|
68
|
+
-- ts_headline — 高亮摘要
|
|
69
|
+
SELECT id, ts_headline('english', body, query,
|
|
70
|
+
'StartSel=<mark>, StopSel=</mark>, MaxWords=30, MinWords=10') AS highlighted
|
|
71
|
+
FROM documents, plainto_tsquery('english', 'full text search') AS query
|
|
72
|
+
WHERE body_tsv @@ query;
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 短语搜索
|
|
76
|
+
|
|
77
|
+
```sql
|
|
78
|
+
-- <-> : 相邻单词
|
|
79
|
+
SELECT * FROM documents
|
|
80
|
+
WHERE body_tsv @@ to_tsquery('english', 'full <-> text <-> search');
|
|
81
|
+
|
|
82
|
+
-- <N> : 相隔最多 N 个词
|
|
83
|
+
SELECT * FROM documents
|
|
84
|
+
WHERE body_tsv @@ to_tsquery('english', 'performance <2> tuning');
|
|
85
|
+
-- 匹配 "performance tuning" 或 "performance and tuning"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 中文全文搜索
|
|
89
|
+
|
|
90
|
+
```sql
|
|
91
|
+
-- 需要 zhparser 或 jieba 扩展
|
|
92
|
+
-- CREATE EXTENSION zhparser;
|
|
93
|
+
-- CREATE TEXT SEARCH CONFIGURATION chinese (PARSER = zhparser);
|
|
94
|
+
-- ALTER TEXT SEARCH CONFIGURATION chinese ADD MAPPING FOR n,v,a,i,e,l WITH simple;
|
|
95
|
+
-- SELECT to_tsvector('chinese', '数据库性能优化技巧');
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 多语言与自定义配置
|
|
99
|
+
|
|
100
|
+
```sql
|
|
101
|
+
-- simple: 不做词干分析
|
|
102
|
+
SELECT to_tsvector('simple', 'running runs ran'); -- 'running':1 'runs':2 'ran':3
|
|
103
|
+
|
|
104
|
+
-- english: 词干分析
|
|
105
|
+
SELECT to_tsvector('english', 'running runs ran'); -- 'run':1,2,3
|
|
106
|
+
|
|
107
|
+
-- 创建自定义字典
|
|
108
|
+
CREATE TEXT SEARCH DICTIONARY my_dict (TEMPLATE = pg_catalog.simple, ...);
|
|
109
|
+
```
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# 索引类型与视图详解
|
|
2
|
+
|
|
3
|
+
## 6种索引类型
|
|
4
|
+
|
|
5
|
+
| 索引类型 | 适用场景 | 操作符 | 典型用途 |
|
|
6
|
+
|---------|---------|--------|---------|
|
|
7
|
+
| **B-Tree** (默认) | 等值/范围查询 | =, <, <=, >, >=, BETWEEN, IN, IS NULL, LIKE ('abc%') | 主键、外键、排序字段 |
|
|
8
|
+
| **Hash** | 等值查询 | = | 长随机值的等值比较 (有限用途) |
|
|
9
|
+
| **GiST** | 几何/全文/范围 | &&, <@, @>, <<, >>, ~= | PostGIS、范围排除约束 |
|
|
10
|
+
| **GIN** | 复合值索引 | @>, <@, ?, ?|, ?&, @@ | JSONB、数组、全文搜索 |
|
|
11
|
+
| **BRIN** | 大表顺序相关数据 | =, <, <=, >, >=, BETWEEN | 时间序列、日志表 (节省 95%+ 空间) |
|
|
12
|
+
| **SP-GiST** | 空间分区/聚类 | 同 GiST | 四叉树、k-d 树、前缀树 |
|
|
13
|
+
|
|
14
|
+
## 索引创建
|
|
15
|
+
|
|
16
|
+
```sql
|
|
17
|
+
-- B-Tree
|
|
18
|
+
CREATE INDEX idx_users_email ON users (email);
|
|
19
|
+
CREATE INDEX idx_orders_created_at ON orders (created_at DESC);
|
|
20
|
+
CREATE INDEX idx_orders_user_status ON orders (user_id, status);
|
|
21
|
+
|
|
22
|
+
-- 复合索引列顺序: 等值在前,范围在后,选择性高的在前
|
|
23
|
+
-- ✅ WHERE user_id = 1 AND status = 'paid' → 索引 (user_id, status) 最优
|
|
24
|
+
-- ❌ WHERE status = 'paid' AND created_at > '2024-01-01' → 索引 (created_at, status) 更好
|
|
25
|
+
|
|
26
|
+
-- 部分索引(仅索引活跃用户,更小更快)
|
|
27
|
+
CREATE INDEX idx_users_active ON users (email) WHERE is_active = TRUE;
|
|
28
|
+
|
|
29
|
+
-- 覆盖索引 / INCLUDE (PG 11+, 避免回表)
|
|
30
|
+
CREATE INDEX idx_orders_covering ON orders (user_id, status) INCLUDE (total_amount, created_at);
|
|
31
|
+
|
|
32
|
+
-- Hash 索引
|
|
33
|
+
CREATE INDEX idx_users_email_hash ON users USING HASH (email);
|
|
34
|
+
|
|
35
|
+
-- GIN 索引
|
|
36
|
+
CREATE INDEX idx_articles_body_tsv ON articles USING GIN (body_tsv);
|
|
37
|
+
CREATE INDEX idx_config_gin ON user_configs USING GIN (config);
|
|
38
|
+
CREATE INDEX idx_articles_tags_gin ON articles USING GIN (tags);
|
|
39
|
+
CREATE INDEX idx_config_path ON user_configs USING GIN (config jsonb_path_ops);
|
|
40
|
+
|
|
41
|
+
-- GiST 索引
|
|
42
|
+
CREATE INDEX idx_room_bookings_period ON room_bookings USING GIST (period);
|
|
43
|
+
|
|
44
|
+
-- BRIN 索引(大表时序数据,极大节省空间)
|
|
45
|
+
CREATE INDEX idx_orders_brin ON orders USING BRIN (created_at) WITH (pages_per_range = 32);
|
|
46
|
+
|
|
47
|
+
-- CONCURRENTLY — 在线建索引(不阻塞写)
|
|
48
|
+
CREATE INDEX CONCURRENTLY idx_orders_user_id ON orders (user_id);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 索引维护
|
|
52
|
+
|
|
53
|
+
```sql
|
|
54
|
+
-- DROP INDEX CONCURRENTLY — 在线删除
|
|
55
|
+
DROP INDEX CONCURRENTLY IF EXISTS idx_orders_old;
|
|
56
|
+
|
|
57
|
+
-- REINDEX — 重建索引(索引膨胀时)
|
|
58
|
+
REINDEX INDEX idx_orders_user_id;
|
|
59
|
+
REINDEX TABLE orders;
|
|
60
|
+
REINDEX DATABASE mydb;
|
|
61
|
+
|
|
62
|
+
-- REINDEX CONCURRENTLY — 在线重建 (PG 12+)
|
|
63
|
+
REINDEX INDEX CONCURRENTLY idx_orders_user_id;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 视图 (View)
|
|
67
|
+
|
|
68
|
+
```sql
|
|
69
|
+
-- 普通视图 — 虚拟表
|
|
70
|
+
CREATE VIEW user_order_summary AS
|
|
71
|
+
SELECT u.id, u.username, COUNT(o.id) AS total_orders,
|
|
72
|
+
COALESCE(SUM(o.total_amount), 0) AS total_spent,
|
|
73
|
+
MAX(o.created_at) AS last_order_date
|
|
74
|
+
FROM users u LEFT JOIN orders o ON o.user_id = u.id
|
|
75
|
+
GROUP BY u.id, u.username;
|
|
76
|
+
|
|
77
|
+
-- WITH CHECK OPTION — 确保更新满足视图条件
|
|
78
|
+
CREATE VIEW paid_orders AS SELECT * FROM orders WHERE status = 'paid'
|
|
79
|
+
WITH CHECK OPTION;
|
|
80
|
+
|
|
81
|
+
-- 物化视图 — 物理存储的快照
|
|
82
|
+
CREATE MATERIALIZED VIEW mv_monthly_sales AS
|
|
83
|
+
SELECT DATE_TRUNC('month', o.created_at) AS month, p.category_id,
|
|
84
|
+
COUNT(DISTINCT o.id) AS order_count, SUM(oi.quantity * oi.price) AS revenue
|
|
85
|
+
FROM orders o JOIN order_items oi ON oi.order_id = o.id
|
|
86
|
+
JOIN products p ON p.id = oi.product_id
|
|
87
|
+
GROUP BY month, p.category_id WITH DATA;
|
|
88
|
+
|
|
89
|
+
-- 刷新物化视图
|
|
90
|
+
REFRESH MATERIALIZED VIEW mv_monthly_sales;
|
|
91
|
+
|
|
92
|
+
-- 并发刷新(需唯一索引, PG 9.4+)
|
|
93
|
+
CREATE UNIQUE INDEX idx_mv_monthly_sales_unique ON mv_monthly_sales (month, category_id);
|
|
94
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_monthly_sales;
|
|
95
|
+
```
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# 分区表与 FDW 详解
|
|
2
|
+
|
|
3
|
+
## 分区表 (PG 10+)
|
|
4
|
+
|
|
5
|
+
### RANGE 分区
|
|
6
|
+
|
|
7
|
+
```sql
|
|
8
|
+
CREATE TABLE orders_partitioned (
|
|
9
|
+
id BIGSERIAL, user_id INTEGER NOT NULL, total_amount NUMERIC(12,2),
|
|
10
|
+
status TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
11
|
+
) PARTITION BY RANGE (created_at);
|
|
12
|
+
|
|
13
|
+
CREATE TABLE orders_2024_01 PARTITION OF orders_partitioned
|
|
14
|
+
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
|
|
15
|
+
CREATE TABLE orders_2024_02 PARTITION OF orders_partitioned
|
|
16
|
+
FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
|
|
17
|
+
|
|
18
|
+
-- 默认分区
|
|
19
|
+
CREATE TABLE orders_default PARTITION OF orders_partitioned DEFAULT;
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### LIST 分区
|
|
23
|
+
|
|
24
|
+
```sql
|
|
25
|
+
CREATE TABLE customers_partitioned (
|
|
26
|
+
id BIGSERIAL, name TEXT NOT NULL, region TEXT NOT NULL
|
|
27
|
+
) PARTITION BY LIST (region);
|
|
28
|
+
|
|
29
|
+
CREATE TABLE customers_asia PARTITION OF customers_partitioned
|
|
30
|
+
FOR VALUES IN ('CN', 'JP', 'KR', 'SG');
|
|
31
|
+
CREATE TABLE customers_americas PARTITION OF customers_partitioned
|
|
32
|
+
FOR VALUES IN ('US', 'CA', 'BR', 'MX');
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### HASH 分区
|
|
36
|
+
|
|
37
|
+
```sql
|
|
38
|
+
CREATE TABLE logs_partitioned (
|
|
39
|
+
id BIGSERIAL, level TEXT, message TEXT, logged_at TIMESTAMPTZ DEFAULT NOW()
|
|
40
|
+
) PARTITION BY HASH (id);
|
|
41
|
+
|
|
42
|
+
CREATE TABLE logs_p0 PARTITION OF logs_partitioned FOR VALUES WITH (MODULUS 4, REMAINDER 0);
|
|
43
|
+
CREATE TABLE logs_p1 PARTITION OF logs_partitioned FOR VALUES WITH (MODULUS 4, REMAINDER 1);
|
|
44
|
+
CREATE TABLE logs_p2 PARTITION OF logs_partitioned FOR VALUES WITH (MODULUS 4, REMAINDER 2);
|
|
45
|
+
CREATE TABLE logs_p3 PARTITION OF logs_partitioned FOR VALUES WITH (MODULUS 4, REMAINDER 3);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 子分区 (PG 11+)
|
|
49
|
+
|
|
50
|
+
```sql
|
|
51
|
+
CREATE TABLE sales (id BIGSERIAL, sale_date DATE NOT NULL, region TEXT NOT NULL, amount NUMERIC(12,2))
|
|
52
|
+
PARTITION BY RANGE (sale_date);
|
|
53
|
+
|
|
54
|
+
CREATE TABLE sales_2024_q1 PARTITION OF sales
|
|
55
|
+
FOR VALUES FROM ('2024-01-01') TO ('2024-04-01')
|
|
56
|
+
PARTITION BY LIST (region);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 分区维护
|
|
60
|
+
|
|
61
|
+
```sql
|
|
62
|
+
-- 添加新分区
|
|
63
|
+
CREATE TABLE orders_2024_04 PARTITION OF orders_partitioned
|
|
64
|
+
FOR VALUES FROM ('2024-04-01') TO ('2024-05-01');
|
|
65
|
+
|
|
66
|
+
-- 分离分区(变成独立表)
|
|
67
|
+
ALTER TABLE orders_partitioned DETACH PARTITION orders_2024_01;
|
|
68
|
+
|
|
69
|
+
-- 附加分区
|
|
70
|
+
ALTER TABLE orders_partitioned ATTACH PARTITION orders_2024_01
|
|
71
|
+
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
|
|
72
|
+
|
|
73
|
+
-- 分区裁剪自动生效
|
|
74
|
+
EXPLAIN SELECT * FROM orders_partitioned
|
|
75
|
+
WHERE created_at >= '2024-02-15' AND created_at < '2024-03-01';
|
|
76
|
+
-- 只在 orders_2024_02 分区上扫描
|
|
77
|
+
|
|
78
|
+
-- 分区表索引自动应用到所有分区
|
|
79
|
+
CREATE INDEX ON orders_partitioned (user_id);
|
|
80
|
+
CREATE INDEX ON orders_partitioned (created_at DESC);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 分区最佳实践
|
|
84
|
+
|
|
85
|
+
- 每个分区 1-10GB 为宜
|
|
86
|
+
- 时间分区常用:日、周、月、季
|
|
87
|
+
- 定期分离旧分区用于归档
|
|
88
|
+
- 分区数不宜超过 1000
|
|
89
|
+
- 分区键直接影响分区裁剪能力
|
|
90
|
+
|
|
91
|
+
## FDW (Foreign Data Wrapper)
|
|
92
|
+
|
|
93
|
+
### postgres_fdw — 跨 PG 数据库
|
|
94
|
+
|
|
95
|
+
```sql
|
|
96
|
+
CREATE EXTENSION postgres_fdw;
|
|
97
|
+
|
|
98
|
+
CREATE SERVER remote_prod FOREIGN DATA WRAPPER postgres_fdw
|
|
99
|
+
OPTIONS (host '192.168.1.100', port '5432', dbname 'prod_db');
|
|
100
|
+
|
|
101
|
+
CREATE USER MAPPING FOR current_user SERVER remote_prod
|
|
102
|
+
OPTIONS (user 'readonly_user', password 'secret');
|
|
103
|
+
|
|
104
|
+
CREATE FOREIGN TABLE remote_orders (
|
|
105
|
+
id BIGINT, user_id INTEGER, total_amount NUMERIC(12,2), status TEXT, created_at TIMESTAMPTZ
|
|
106
|
+
) SERVER remote_prod OPTIONS (schema_name 'public', table_name 'orders');
|
|
107
|
+
|
|
108
|
+
-- 查询远程表
|
|
109
|
+
SELECT * FROM remote_orders WHERE created_at > NOW() - INTERVAL '1 hour';
|
|
110
|
+
|
|
111
|
+
-- 批量导入外部表结构
|
|
112
|
+
IMPORT FOREIGN SCHEMA public FROM SERVER remote_prod INTO local_schema
|
|
113
|
+
LIMIT TO (users, orders, products);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### file_fdw — 读取 CSV
|
|
117
|
+
|
|
118
|
+
```sql
|
|
119
|
+
CREATE EXTENSION file_fdw;
|
|
120
|
+
CREATE SERVER file_server FOREIGN DATA WRAPPER file_fdw;
|
|
121
|
+
|
|
122
|
+
CREATE FOREIGN TABLE csv_orders (
|
|
123
|
+
id BIGINT, user_id INTEGER, amount NUMERIC(10,2), order_date DATE
|
|
124
|
+
) SERVER file_server OPTIONS (filename '/data/orders.csv', format 'csv', header 'true');
|
|
125
|
+
|
|
126
|
+
SELECT SUM(amount) FROM csv_orders WHERE order_date >= '2024-01-01';
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### FDW 性能考量
|
|
130
|
+
|
|
131
|
+
- 适合小数据量或低频跨库查询
|
|
132
|
+
- 大数据量传输建议用逻辑复制或 ETL
|
|
133
|
+
- WHERE 条件尽量 push down 到远程
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# 复制/备份/权限详解
|
|
2
|
+
|
|
3
|
+
## 流复制 (Streaming Replication)
|
|
4
|
+
|
|
5
|
+
### 主库配置
|
|
6
|
+
|
|
7
|
+
```conf
|
|
8
|
+
# postgresql.conf
|
|
9
|
+
wal_level = replica
|
|
10
|
+
max_wal_senders = 10
|
|
11
|
+
wal_keep_size = 1GB
|
|
12
|
+
hot_standby = on
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```sql
|
|
16
|
+
-- pg_hba.conf
|
|
17
|
+
-- host replication replicator 192.168.1.0/24 md5
|
|
18
|
+
|
|
19
|
+
CREATE USER replicator WITH REPLICATION LOGIN PASSWORD 'strong_password';
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 从库搭建
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# 清空从库数据目录
|
|
26
|
+
rm -rf /var/lib/postgresql/data/*
|
|
27
|
+
|
|
28
|
+
# 从主库拉取基础备份
|
|
29
|
+
pg_basebackup -h 192.168.1.100 -U replicator \
|
|
30
|
+
-D /var/lib/postgresql/data -P -v --wal-method=stream
|
|
31
|
+
|
|
32
|
+
# PG 12+: 创建 standby.signal
|
|
33
|
+
touch /var/lib/postgresql/data/standby.signal
|
|
34
|
+
|
|
35
|
+
# 配置主库连接
|
|
36
|
+
echo "primary_conninfo = 'host=192.168.1.100 port=5432 user=replicator password=strong_password'" \
|
|
37
|
+
>> /var/lib/postgresql/data/postgresql.auto.conf
|
|
38
|
+
|
|
39
|
+
# 启动从库
|
|
40
|
+
systemctl start postgresql
|
|
41
|
+
|
|
42
|
+
# 检查复制状态(主库)
|
|
43
|
+
SELECT * FROM pg_stat_replication;
|
|
44
|
+
# 从库
|
|
45
|
+
SELECT * FROM pg_stat_wal_receiver;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 同步 vs 异步
|
|
49
|
+
|
|
50
|
+
```sql
|
|
51
|
+
-- 同步复制:主库等待从库确认
|
|
52
|
+
-- 配置: synchronous_standby_names = 'FIRST 1 (slave1, slave2)'
|
|
53
|
+
-- 数据零丢失,但写入延迟增加
|
|
54
|
+
|
|
55
|
+
-- 检查同步状态
|
|
56
|
+
SELECT application_name, state, sync_state, write_lag, flush_lag, replay_lag
|
|
57
|
+
FROM pg_stat_replication;
|
|
58
|
+
-- sync: 同步, async: 异步, potential: 候选同步
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 逻辑复制 (PG 10+)
|
|
62
|
+
|
|
63
|
+
```sql
|
|
64
|
+
-- 发布端
|
|
65
|
+
CREATE PUBLICATION my_pub FOR ALL TABLES;
|
|
66
|
+
CREATE PUBLICATION orders_pub FOR TABLE orders, order_items;
|
|
67
|
+
CREATE PUBLICATION paid_orders_pub FOR TABLE orders WHERE (status = 'paid'); -- PG 15+
|
|
68
|
+
|
|
69
|
+
-- 订阅端
|
|
70
|
+
CREATE SUBSCRIPTION my_sub
|
|
71
|
+
CONNECTION 'host=192.168.1.100 port=5432 dbname=mydb user=replicator password=strong_password'
|
|
72
|
+
PUBLICATION my_pub;
|
|
73
|
+
|
|
74
|
+
-- 管理
|
|
75
|
+
ALTER SUBSCRIPTION my_sub ENABLE;
|
|
76
|
+
ALTER SUBSCRIPTION my_sub DISABLE;
|
|
77
|
+
ALTER SUBSCRIPTION my_sub REFRESH PUBLICATION;
|
|
78
|
+
DROP SUBSCRIPTION my_sub;
|
|
79
|
+
|
|
80
|
+
-- 监控
|
|
81
|
+
SELECT * FROM pg_stat_subscription;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 备份与恢复
|
|
85
|
+
|
|
86
|
+
### pg_dump — 逻辑备份
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# SQL 格式
|
|
90
|
+
pg_dump -h localhost -U postgres -d mydb > mydb.sql
|
|
91
|
+
|
|
92
|
+
# 自定义格式(推荐)
|
|
93
|
+
pg_dump -h localhost -U postgres -d mydb -Fc -f mydb.dump
|
|
94
|
+
|
|
95
|
+
# 并行导出目录格式
|
|
96
|
+
pg_dump -h localhost -U postgres -d mydb -Fd -j 4 -f /backup/mydb/
|
|
97
|
+
|
|
98
|
+
# 只导出结构
|
|
99
|
+
pg_dump -h localhost -U postgres -d mydb -s -f mydb_schema.sql
|
|
100
|
+
|
|
101
|
+
# 指定表
|
|
102
|
+
pg_dump -h localhost -U postgres -d mydb -t orders -t users -f mydb_tables.sql
|
|
103
|
+
|
|
104
|
+
# 全局对象(角色、表空间)
|
|
105
|
+
pg_dumpall -h localhost -U postgres -g -f global_objects.sql
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### pg_restore — 恢复
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pg_restore -h localhost -U postgres -d mydb /backup/mydb.dump
|
|
112
|
+
pg_restore -h localhost -U postgres -d mydb -j 4 /backup/mydb.dump # 并行
|
|
113
|
+
pg_restore -h localhost -U postgres -d mydb -t users /backup/mydb.dump # 指定表
|
|
114
|
+
|
|
115
|
+
# SQL 文件恢复
|
|
116
|
+
psql -h localhost -U postgres -d mydb < mydb.sql
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### WAL 归档与 PITR
|
|
120
|
+
|
|
121
|
+
```conf
|
|
122
|
+
# postgresql.conf
|
|
123
|
+
archive_mode = on
|
|
124
|
+
archive_command = 'cp %p /archive/%f'
|
|
125
|
+
wal_keep_size = 1GB
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# 创建基础备份
|
|
130
|
+
pg_basebackup -h localhost -U postgres -D /backup/base -P -v --wal-method=stream
|
|
131
|
+
|
|
132
|
+
# PITR 恢复步骤:
|
|
133
|
+
# 1. 停止 PG
|
|
134
|
+
# 2. 用基础备份恢复数据目录
|
|
135
|
+
# 3. 创建 recovery.signal (PG 12+)
|
|
136
|
+
# 4. 配置 restore_command 和 recovery_target_time
|
|
137
|
+
# 5. 启动 PG
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### pg_basebackup — 物理备份
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# 基础用法
|
|
144
|
+
pg_basebackup -h localhost -U replicator -D /backup/pg_base -P -v --wal-method=stream
|
|
145
|
+
|
|
146
|
+
# 压缩 tar 格式
|
|
147
|
+
pg_basebackup -h localhost -U replicator -D /backup/pg_base -Ft -z -P -v
|
|
148
|
+
|
|
149
|
+
# 验证备份 (PG 13+)
|
|
150
|
+
pg_verifybackup /backup/pg_base
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## 高可用工具
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Patroni (基于 etcd/consul/ZK)
|
|
157
|
+
# 自动故障转移 + 自动恢复
|
|
158
|
+
patroni /etc/patroni/patroni.yml
|
|
159
|
+
|
|
160
|
+
# repmgr
|
|
161
|
+
repmgr -f /etc/repmgr.conf primary register
|
|
162
|
+
repmgr -f /etc/repmgr.conf standby clone
|
|
163
|
+
repmgr -f /etc/repmgr.conf standby register
|
|
164
|
+
repmgr -f /etc/repmgr.conf standby switchover
|
|
165
|
+
|
|
166
|
+
# PgBouncer — 连接池
|
|
167
|
+
# Pgpool-II — 连接池 + 读写分离 + 负载均衡
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 权限管理
|
|
171
|
+
|
|
172
|
+
```sql
|
|
173
|
+
-- ROLE 管理
|
|
174
|
+
CREATE ROLE app_user WITH LOGIN PASSWORD 'password';
|
|
175
|
+
CREATE ROLE readonly_role;
|
|
176
|
+
CREATE ROLE readwrite_role;
|
|
177
|
+
|
|
178
|
+
-- 角色层级
|
|
179
|
+
GRANT readonly_role TO app_user;
|
|
180
|
+
|
|
181
|
+
-- Schema 权限
|
|
182
|
+
GRANT USAGE ON SCHEMA public TO readonly_role;
|
|
183
|
+
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_role;
|
|
184
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO readwrite_role;
|
|
185
|
+
|
|
186
|
+
-- 默认权限(未来新建表自动授权)
|
|
187
|
+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_role;
|
|
188
|
+
|
|
189
|
+
-- 序列、函数
|
|
190
|
+
GRANT USAGE, SELECT ON ALL SEQUENCES TO readwrite_role;
|
|
191
|
+
GRANT EXECUTE ON ALL FUNCTIONS TO readwrite_role;
|
|
192
|
+
|
|
193
|
+
-- RLS 行级安全(多租户隔离)
|
|
194
|
+
CREATE TABLE tenant_orders (id BIGSERIAL PRIMARY KEY, tenant_id INTEGER NOT NULL, ...);
|
|
195
|
+
ALTER TABLE tenant_orders ENABLE ROW LEVEL SECURITY;
|
|
196
|
+
|
|
197
|
+
CREATE POLICY tenant_isolation ON tenant_orders
|
|
198
|
+
USING (tenant_id = current_setting('app.tenant_id')::INTEGER);
|
|
199
|
+
|
|
200
|
+
ALTER TABLE tenant_orders FORCE ROW LEVEL SECURITY;
|
|
201
|
+
SET app.tenant_id = '1001'; -- 应用层设置
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## 扩展
|
|
205
|
+
|
|
206
|
+
```sql
|
|
207
|
+
-- PostGIS: CREATE EXTENSION postgis;
|
|
208
|
+
-- pgvector: CREATE EXTENSION vector;
|
|
209
|
+
-- pg_stat_statements: CREATE EXTENSION pg_stat_statements;
|
|
210
|
+
-- uuid-ossp: CREATE EXTENSION "uuid-ossp";
|
|
211
|
+
-- pgcrypto: CREATE EXTENSION pgcrypto;
|
|
212
|
+
-- citext: CREATE EXTENSION citext;
|
|
213
|
+
-- pg_trgm: CREATE EXTENSION pg_trgm;
|
|
214
|
+
-- unaccent: CREATE EXTENSION unaccent;
|
|
215
|
+
```
|