Stats 采集当前数据库大小、Ping 延迟及各表行数。 调用方负责在后台 goroutine 中调用,不要在 HTTP handler 中直接调用。
(_ string)
| 253 | // Stats 采集当前数据库大小、Ping 延迟及各表行数。 |
| 254 | // 调用方负责在后台 goroutine 中调用,不要在 HTTP handler 中直接调用。 |
| 255 | func (db *DB) Stats(_ string) DBStats { |
| 256 | var s DBStats |
| 257 | ctx := context.Background() |
| 258 | |
| 259 | // 查询数据库大小 |
| 260 | db.conn.QueryRow(ctx, "SELECT pg_database_size(current_database())").Scan(&s.FileSizeBytes) |
| 261 | // WALSizeBytes、PageCount、PageSize、FreePages 字段设为 0(PostgreSQL 无对应概念) |
| 262 | |
| 263 | start := time.Now() |
| 264 | db.conn.QueryRow(ctx, "SELECT 1").Scan(new(int)) |
| 265 | s.PingLatencyMs = float64(time.Since(start).Microseconds()) / 1000.0 |
| 266 | |
| 267 | // 枚举 public schema 下的用户表并统计行数 |
| 268 | // 表名来自 pg_tables.tablename(系统表,非用户输入),安全。 |
| 269 | rows, err := db.conn.Query(ctx, "SELECT tablename FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename") |
| 270 | if err == nil { |
| 271 | defer rows.Close() |
| 272 | s.Tables = make(map[string]int64) |
| 273 | for rows.Next() { |
| 274 | var tbl string |
| 275 | if rows.Scan(&tbl) == nil { |
| 276 | var count int64 |
| 277 | // tbl 来自 pg_tables,只含小写字母、数字和下划线,无注入风险。 |
| 278 | db.conn.QueryRow(ctx, "SELECT COUNT(*) FROM "+tbl).Scan(&count) //nolint:gosec |
| 279 | s.Tables[tbl] = count |
| 280 | } |
| 281 | } |
| 282 | if err := rows.Err(); err != nil { |
| 283 | // 统计失败不致命,直接忽略 |
| 284 | _ = err |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | return s |
| 289 | } |