用途
这套实践面向前后端使用 Npgsql 与 Entity Framework Core 的 .NET 应用,用于指导 PostgreSQL 数据库设计、命名约定、索引策略与性能优化,并以速查表与正误示例的形式给出可执行的建议。
命名约定
- 所有标识符使用 snake_case(表、列)。
- 表名使用复数 snake_case,如 user_profiles、order_items。
- 主键用 pk_{table},外键用 fk_{table}{ref_table},索引用 ix{table}{column(s)},唯一索引用 uix{table}{column(s)},检查约束用 ck{table}{column},序列用 seq{table}_{column}。
- EF Core 可通过 EFCore.NamingConventions 包配合 UseSnakeCaseNamingConvention() 将 C# 的 PascalCase 自动转换为 snake_case。安装命令:dotnet add package EFCore.NamingConventions。
数据类型
- Guid 映射 uuid,主键优先使用;string 优先用 text,仅在需要长度限制时用 varchar(n);int→integer、long→bigint、decimal→numeric(p,s)、double→double precision、bool→boolean、DateTime→timestamptz、byte[]→bytea、Dictionary<string,object>→jsonb、string[]→text[]。
- 时间戳使用 timestamptz 并默认 UTC,如 DEFAULT (CURRENT_TIMESTAMP AT TIME ZONE 'UTC');避免不带时区的 timestamp。
- 结构化数据使用 jsonb(可索引、更快),不要用 json。EF Core 中可设置 HasColumnType("jsonb"),或对 owned type 使用 ToJson()(EF Core 7+)。
主键
- 推荐 uuid 主键,可由应用侧生成(ValueGeneratedNever)或数据库默认 gen_random_uuid();优点是全局唯一、客户端可生成、适合分布式系统、无顺序枚举安全风险。
- 替代方案是 bigserial 自增,EF Core 中可用 UseIdentityColumn()。
索引策略
- 外键始终建索引(EF Core 通常自动创建,需核实)。
- 唯一索引用例:uix_users_email、uix_users_username。
- 复合索引注意列顺序,如 (user_id, status) 能服务 WHERE user_id = ? AND status = ? 与 WHERE user_id = ?,但不能服务 WHERE status = ?。
- 部分索引仅索引相关行,如 WHERE status = 'Pending' 或 WHERE is_deleted = false。
- 覆盖索引用 INCLUDE 包含常访问列。
- 全文检索使用 tsvector 生成列 + GIN 索引;jsonb 查询使用 GIN 索引(整体或指定路径)。
- 不建议建索引的场景:极小表(少于约 1000 行)、很少出现在 WHERE/JOIN 的列、低基数列、频繁变更的列。
约束
- 主键、外键、检查约束、唯一约束均建议命名。
- 外键删除行为需明确:ON DELETE RESTRICT 防孤儿,ON DELETE CASCADE 随主记录删除。EF Core 通过 OnDelete(DeleteBehavior.Restrict/Cascade) 配置,检查约束用 HasCheckConstraint,复合唯一约束用 HasIndex(...).IsUnique()。
性能优化
- 连接池默认启用,可在连接字符串设置 Pooling、MinPoolSize、MaxPoolSize、Timeout。
- Npgsql 对重复查询自动使用预编译语句。
- 批量插入用 AddRange + 一次 SaveChangesAsync,避免逐条保存。
- 只读查询使用 AsNoTracking。
- 高频查询可使用 EF.CompileAsyncQuery 编译查询。
- 分页使用 ORDER BY + LIMIT/OFFSET(EF Core 的 Skip/Take)。
- 避免 N+1:用 Include 预加载;多个集合使用 AsSplitQuery 避免笛卡尔积膨胀。
维护与监控
- 使用 ANALYZE 更新统计信息,VACUUM 回收空间,VACUUM ANALYZE 同时执行。
- autovacuum 自动运行,可对高流量表调整 autovacuum_vacuum_scale_factor、autovacuum_analyze_scale_factor。
- 通过 pg_stat_user_indexes 查找未使用索引,通过 pg_stat_user_tables 查找大表顺序扫描以发现缺失索引。
- 可通过 pg_tables 与 pg_total_relation_size 检查表膨胀与大小。
安全实践
- 连接使用 SSL/TLS(SSL Mode=Require),并设置连接池上限与超时。
- 遵循最小权限:为应用创建专用用户,仅授予 CONNECT、USAGE、必要的 SELECT/INSERT/UPDATE/DELETE 与序列权限,避免使用超级用户或授予 ALL PRIVILEGES。
- 参数化查询:EF Core 默认参数化,Dapper 使用参数对象;禁止拼接 SQL 字符串。
扩展
推荐扩展包括 uuid-ossp、pgcrypto(gen_random_uuid())、pg_trgm(三元组相似匹配)、citext(大小写不敏感文本)、hstore、ltree,并给出对应使用示例(uuid 默认值、citext 唯一列、GIN + gin_trgm_ops 相似搜索)。
高并发模式
- 使用 PostgreSQL 隐藏系统列 xmin 作为乐观并发令牌:在实体中定义 uint RowVersion,配置 IsRowVersion(),Npgsql 自动映射到 xmin。
- 捕获 DbUpdateConcurrencyException 后可通过 GetDatabaseValuesAsync 获取数据库当前值,选择覆盖数据库值(客户端胜出)或抛出让调用方重试(数据库胜出)。
- 使用 Polly 配置重试策略,可处理 DbUpdateConcurrencyException 与瞬态 NpgsqlException(资料在此处截断,指数退避的具体配置暂未提供完整内容)。
限制与说明
以上为资料中明确给出的实践与示例。适用场景、版本兼容性、性能收益与具体边界需结合实际环境验证;资料未提供的内容不在此展开。