强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

AgensGraph 完全指南 / 第 15 章:最佳实践与规范

第 15 章:最佳实践与规范

15.1 图建模规范

15.1.1 命名规范

元素规范正确示例错误示例
顶点标签PascalCase,单数Person, OrderItempersons, order_items
边标签UPPER_SNAKE_CASEKNOWS, WORKS_ATknows, worksAt
属性名snake_casefirst_name, created_atfirstName, createdAt
图名snake_casesocial_networkSocialNetwork
约束名{table}_{col}_{type}person_email_uniqueconstraint1
索引名{table}_{col}_idxperson_name_idxidx1

15.1.2 标签设计原则

标签设计四原则:

  1. 业务语义: 标签应反映业务实体
     ✅ :Customer, :Product, :Order
     ❌ :Table1, :Data, :Record

  2. 适度粒度: 2-3 个标签为宜
     ✅ :Person:Employee
     ❌ :Person:Employee:Manager:FullTime:BeijingOffice:TechDept

  3. 不可变性: 标签不应频繁变化
     ✅ :Person (status 属性区分 active/inactive)
     ❌ :ActivePerson, :InactivePerson

  4. 查询驱动: 标签服务于高频查询
     ✅ :VIP_Customer (VIP 客户查询频繁)
     ❌ 将所有分类信息都做成标签

15.1.3 边设计原则

边设计五原则:

  1. 有向性: 边必须有方向
     (User)-[:PLACED]->(Order)
     (Order)-[:CONTAINS]->(Product)

  2. 语义化: 边标签应表达关系含义
     ✅ :REPORTS_TO, :PURCHASED, :REVIEWED
     ❌ :HAS, :RELATES_TO, :LINKED

  3. 适度属性: 边上存储关系属性
     (User)-[:PURCHASED {date, quantity, price}]->(Product)

  4. 避免超级节点: 大量边的节点需特殊处理
     ❌ (PopularProduct)<-[:VIEWED]-(百万用户)
     ✅ 按时间分区或使用聚合

  5. Reification: 复杂关系提升为顶点
     ❌ (Buyer)-[:BOUGHT {items, total, address}]->(Seller)
     ✅ (Buyer)-[:PLACED]->(Order)-[:CONTAINS]->(Product)

15.1.4 属性设计原则

-- ✅ 良好的属性设计
CREATE (:Person {
  id: 'P001',                      -- 业务主键
  name: '张三',                     -- 必填属性
  email: 'zhangsan@example.com',   -- 唯一标识
  age: 30,                         -- 基本属性
  skills: ['Java', 'Python'],      -- 数组属性
  address: {                       -- 嵌套结构
    city: '北京',
    district: '海淀区',
    street: '中关村大街1号'
  },
  created_at: datetime(),          -- 时间戳
  updated_at: datetime(),          -- 更新时间
  version: 1                       -- 乐观锁版本号
});
原则说明示例
原子性属性值不可再分first_name + last_name 而非 full_name
类型一致同名属性保持类型统一age 始终为 Integer
避免大对象不存储二进制/长文本使用 URL 引用外部存储
索引友好高频查询字段作为属性status 而非 备注 做索引
时间标记记录创建和修改时间created_at, updated_at

15.2 查询编写规范

15.2.1 Cypher 编码规范

-- ✅ 推荐: 格式化良好的查询
MATCH (u:User {status: 'active'})-[:PLACED]->(o:Order)-[:CONTAINS]->(p:Product)
WHERE o.created_at > datetime('2024-01-01')
  AND p.category = 'electronics'
WITH u, count(o) AS order_count, sum(o.total) AS total_spent
WHERE order_count > 5
RETURN
  u.name AS customer,
  order_count,
  total_spent
ORDER BY total_spent DESC
LIMIT 20;

-- ❌ 不推荐: 所有内容挤在一行
-- MATCH (u:User{status:'active'})-[:PLACED]->(o:Order)-[:CONTAINS]->(p:Product) WHERE o.created_at>datetime('2024-01-01') AND p.category='electronics' WITH u,count(o) AS order_count,sum(o.total) AS total_spent WHERE order_count>5 RETURN u.name AS customer,order_count,total_spent ORDER BY total_spent DESC LIMIT 20;

15.2.2 查询编写 Checklist

检查项说明严重程度
✅ 设置 graph_path执行前确保图路径已设置🔴 必须
✅ 使用索引属性定位MATCH 中使用已索引属性🟠 重要
✅ 限制遍历深度变长路径设置合理的 *N..M🟠 重要
✅ 使用 LIMIT防止返回过多结果🟡 建议
✅ 参数化查询防止 Cypher 注入🔴 必须
✅ 只返回必要字段避免 RETURN *🟡 建议
✅ 使用 MERGE 去重防止重复数据🟠 重要
✅ 事务粒度适当避免长事务🟠 重要

15.2.3 参数化查询

# ✅ 正确: 参数化查询
query = """
    MATCH (p:Person {name: $name})
    RETURN p.age, p.city
"""
params = {'name': 'Alice'}
result = execute_cypher(query, params)

# ❌ 错误: 字符串拼接(有注入风险)
query = f"""
    MATCH (p:Person {{name: '{user_input}'}})
    RETURN p.age, p.city
"""

15.3 索引管理规范

15.3.1 索引创建策略

-- 必须创建索引的场景:
-- 1. 主键/唯一标识
CREATE CONSTRAINT person_id_unique
  ON (p:Person) ASSERT p.id IS UNIQUE;

-- 2. 高频查询属性
CREATE INDEX ON :Person(name);
CREATE INDEX ON :Person(email);

-- 3. 外键/关联属性
CREATE INDEX ON :Order(user_id);
CREATE INDEX ON :KNOWS(since);

-- 4. 复合查询
CREATE INDEX ON :Person(city, age);

15.3.2 索引维护计划

频率操作说明
每日检查索引使用率删除未使用索引
每周ANALYZE 更新统计保持优化器准确
每月REINDEX 重建索引消除索引碎片
每季索引策略评审根据查询变化调整
-- 查看索引使用情况
SELECT
    indexrelname AS index_name,
    idx_scan AS scans,
    idx_tup_read AS tuples_read,
    pg_size_pretty(pg_relation_size(indexrelid)) AS size
FROM pg_stat_user_indexes
ORDER BY idx_scan ASC;

-- 查找未使用的索引(可能需要删除)
SELECT
    indexrelname,
    idx_scan,
    pg_size_pretty(pg_relation_size(indexrelid)) AS wasted_size
FROM pg_stat_user_indexes
WHERE idx_scan = 0
  AND indexrelname NOT LIKE '%pkey%'
ORDER BY pg_relation_size(indexrelid) DESC;

15.4 安全规范

15.4.1 访问控制

-- 创建只读用户
CREATE USER readonly_user WITH PASSWORD 'secure_password';
GRANT CONNECT ON DATABASE agens TO readonly_user;
GRANT USAGE ON SCHEMA social_network TO readonly_user;
GRANT SELECT ON ALL TABLES IN SCHEMA social_network TO readonly_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA social_network
  GRANT SELECT ON TABLES TO readonly_user;

-- 创建应用用户(最小权限原则)
CREATE USER app_user WITH PASSWORD 'app_secure_password';
GRANT CONNECT ON DATABASE agens TO app_user;
GRANT USAGE ON SCHEMA social_network TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA social_network TO app_user;

-- 创建管理员用户
CREATE USER admin_user WITH PASSWORD 'admin_secure_password' SUPERUSER;

15.4.2 安全配置清单

配置项推荐值说明
password_encryptionscram-sha-256使用强密码加密
sslon启用 SSL 连接
ssl_min_protocol_versionTLSv1.2最低 TLS 版本
pg_hba.conf限制 IP 范围不使用 0.0.0.0/0
log_connectionson记录连接事件
log_disconnectionson记录断开事件
log_statementddl记录 DDL 语句

15.4.3 SSL 配置

# agens.conf
ssl = on
ssl_cert_file = '/etc/ssl/server.crt'
ssl_key_file = '/etc/ssl/server.key'
ssl_ca_file = '/etc/ssl/ca.crt'
ssl_crl_file = '/etc/ssl/root.crl'
ssl_min_protocol_version = 'TLSv1.2'
ssl_ciphers = 'HIGH:!aNULL:!MD5'
# 生成自签名证书(测试环境)
openssl req -new -x509 -days 365 -nodes \
  -text -out server.crt \
  -keyout server.key \
  -subj "/CN=agensgraph.local"

# 设置权限
chmod 600 server.key
chown agens:agens server.*

15.5 备份与恢复规范

15.5.1 备份策略矩阵

备份类型频率保留周期存储位置适用场景
完整备份每周日4 周异地存储全量恢复
增量备份每天7 天本地+异地快速恢复
WAL 归档持续7 天异地存储PITR 恢复
逻辑备份每天30 天对象存储跨版本迁移

15.5.2 备份验证

#!/bin/bash
# verify_backup.sh - 备份验证脚本

BACKUP_FILE=$1
VERIFY_PORT=5433

echo "=== Backup Verification ==="

# 1. 恢复到临时实例
docker run -d --name ag_verify \
  -p ${VERIFY_PORT}:5432 \
  -e AG_PASSWORD=verify123 \
  bitnine/agensgraph:v2.13

sleep 10

# 2. 恢复备份
pg_restore -h localhost -p ${VERIFY_PORT} -U agens -d agens ${BACKUP_FILE}

# 3. 数据完整性检查
TABLE_COUNT=$(psql -h localhost -p ${VERIFY_PORT} -U agens -t -c "
  SELECT count(*) FROM information_schema.tables
  WHERE table_schema = 'public';
")

TOTAL_ROWS=$(psql -h localhost -p ${VERIFY_PORT} -U agens -t -c "
  SELECT sum(n_live_tup) FROM pg_stat_user_tables;
")

echo "Tables: ${TABLE_COUNT}"
echo "Total rows: ${TOTAL_ROWS}"

# 4. 基本查询测试
psql -h localhost -p ${VERIFY_PORT} -U agens -c "
  SET graph_path = social_network;
  MATCH (p:Person) RETURN count(p);
"

# 5. 清理
docker stop ag_verify && docker rm ag_verify

echo "=== Verification Complete ==="

15.5.3 恢复演练

演练项目频率验证内容
完整恢复每季全量备份恢复到新环境
PITR 恢复每季恢复到指定时间点
主从切换每季主库故障,备库提升
跨区域恢复每半年异地备份恢复测试

15.6 监控规范

15.6.1 监控指标分级

级别指标阈值告警方式
P0 (紧急)服务不可用无法连接短信 + 电话
P0 (紧急)磁盘使用率> 90%短信 + 电话
P1 (严重)复制延迟> 30s短信
P1 (严重)缓冲区命中率< 95%短信
P2 (警告)连接数> 80% max邮件
P2 (警告)慢查询数量> 10/min邮件
P3 (信息)表膨胀率> 30%工单

15.6.2 Prometheus 告警规则

# prometheus/alert_rules.yml
groups:
  - name: agensgraph_alerts
    rules:
      - alert: AgensGraphDown
        expr: pg_up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "AgensGraph instance is down"

      - alert: HighDiskUsage
        expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) < 0.1
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Disk usage above 90%"

      - alert: LowBufferHitRatio
        expr: pg_stat_database_blks_hit_ratio < 0.95
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Buffer hit ratio below 95%"

      - alert: HighReplicationLag
        expr: pg_stat_replication_lag > 30
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Replication lag above 30 seconds"

      - alert: TooManyConnections
        expr: pg_stat_activity_count > (pg_settings_max_connections * 0.8)
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Connection count above 80% of max"

15.7 团队协作规范

15.7.1 版本控制

图 Schema 变更流程:

  1. 开发环境测试变更
      │
  2. 编写迁移脚本 (migration script)
      │
  3. Code Review
      │
  4. 测试环境验证
      │
  5. 生产环境执行
      │
  6. 验证结果

15.7.2 迁移脚本管理

migrations/
├── V001__create_graph_social_network.cypher
├── V002__add_person_constraints.cypher
├── V003__create_indexes.cypher
├── V004__add_company_label.cypher
└── V005__migrate_person_data.cypher
-- V001__create_graph_social_network.cypher
-- 创建图数据库
CREATE GRAPH IF NOT EXISTS social_network;
SET graph_path = social_network;

-- 创建标签约束
CREATE CONSTRAINT person_id_unique
  ON (p:Person) ASSERT p.id IS UNIQUE;

CREATE CONSTRAINT company_id_unique
  ON (c:Company) ASSERT c.id IS UNIQUE;

15.7.3 开发环境管理

# docker-compose.dev.yml
version: '3.8'

services:
  agensgraph:
    image: bitnine/agensgraph:v2.13
    ports:
      - "5432:5432"
    environment:
      AG_PASSWORD: dev123
    volumes:
      - ./data:/home/agens/AgensGraph/data
      - ./migrations:/docker-entrypoint-initdb.d
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U agens"]
      interval: 5s
      timeout: 3s
      retries: 5

  # 每个开发者使用独立端口
  # developer1: 5432
  # developer2: 5433
  # developer3: 5434

15.7.4 文档规范

# 图模型文档模板

## 1. 概述
- 图名称: social_network
- 用途: 社交网络关系管理
- 负责人: 张三
- 创建时间: 2024-01-01

## 2. 顶点定义
| 标签 | 属性 | 约束 | 说明 |
|------|------|------|------|
| Person | id, name, email, age | id UNIQUE | 用户 |
| Company | id, name, industry | id UNIQUE | 公司 |

## 3. 边定义
| 类型 | 起点 | 终点 | 属性 | 说明 |
|------|------|------|------|------|
| KNOWS | Person | Person | since, context | 好友关系 |
| WORKS_AT | Person | Company | position, since | 工作关系 |

## 4. 索引
| 名称 | 类型 | 说明 |
|------|------|------|
| person_name_idx | B-Tree | Person.name 查询 |
| person_email_idx | B-Tree | Person.email 查询 |

## 5. 变更记录
| 日期 | 版本 | 变更内容 | 操作人 |
|------|------|---------|--------|
| 2024-01-01 | v1.0 | 初始版本 | 张三 |
| 2024-02-15 | v1.1 | 添加 Company 标签 | 李四 |

15.8 生产部署清单

15.8.1 上线前检查清单

分类检查项状态备注
基础配置
PostgreSQL 版本确认
内存参数调优
连接池配置
SSL 启用
日志配置
数据模型
图 Schema 设计评审
约束创建(唯一性/存在性)
索引创建
初始数据导入验证
安全
用户权限最小化
密码策略合规
网络访问限制
审计日志开启
备份恢复
完整备份策略配置
WAL 归档配置
备份恢复测试
PITR 恢复测试
监控告警
监控指标采集
告警规则配置
告警渠道测试
仪表板创建
高可用
主从复制配置
复制延迟监控
故障切换演练
自动故障转移
性能
基准测试完成
慢查询阈值设定
查询优化评审
容量规划

15.8.2 灾难恢复预案

场景RTORPO恢复步骤
主库硬件故障30min0备库提升为主库
数据损坏2h< 5minPITR 恢复
机房级故障4h< 1h异地恢复
误删数据30min0闪回查询/PITR

15.8.3 运维值班手册

# 故障处理流程

## P0 故障(服务不可用)
1. 确认故障范围和影响
2. 启动应急预案
3. 通知相关方
4. 执行故障恢复
5. 验证服务恢复
6. 故障复盘

## P1 故障(性能下降)
1. 检查监控指标
2. 定位瓶颈(CPU/内存/IO/锁)
3. 应急优化(杀慢查询/扩连接)
4. 根因分析
5. 制定长期优化方案

## P2 故障(功能异常)
1. 收集错误信息
2. 定位问题代码/配置
3. 修复并测试
4. 部署上线
5. 验证恢复

15.9 性能优化速查卡

┌─────────────────────────────────────────────────────┐
│           AgensGraph 性能优化速查卡                    │
├─────────────────────────────────────────────────────┤
│                                                     │
│  [查询层]                                            │
│  ✅ 使用索引属性定位起始节点                            │
│  ✅ 限制变长路径深度 *1..N                             │
│  ✅ 尽早过滤 (WHERE 在 MATCH 中)                      │
│  ✅ 返回必要字段,使用 LIMIT                          │
│  ✅ 避免笛卡尔积(多个独立 MATCH)                     │
│                                                     │
│  [索引层]                                            │
│  ✅ 高频查询属性创建索引                               │
│  ✅ 复合索引:等值列在前,范围列在后                    │
│  ✅ 定期 ANALYZE 更新统计                             │
│  ✅ 清理未使用的索引                                  │
│                                                     │
│  [配置层]                                            │
│  ✅ shared_buffers = RAM × 25%                       │
│  ✅ work_mem = 16-64MB (按需调整)                     │
│  ✅ effective_cache_size = RAM × 75%                 │
│  ✅ random_page_cost = 1.1 (SSD)                     │
│                                                     │
│  [运维层]                                            │
│  ✅ 使用连接池(PgBouncer)                           │
│  ✅ 监控慢查询和锁等待                                │
│  ✅ 定期 VACUUM 和 REINDEX                           │
│  ✅ 容量规划和趋势分析                                │
│                                                     │
└─────────────────────────────────────────────────────┘

15.10 本章小结

规范领域核心要点
图建模命名规范、标签适度、属性原子、避免超级节点
查询编写参数化、索引利用、深度限制、返回精简
索引管理策略性创建、定期维护、清理未使用索引
安全最小权限、SSL 加密、审计日志
备份多级策略、定期演练、异地存储
监控分级告警、关键指标、自动化工单
团队协作版本控制、迁移脚本、文档模板
生产部署检查清单、灾备预案、值班手册

15.11 扩展阅读