Skip to content
Back to skills

1338 Data Analysis 3128b307

ASecurity

> **项目**: Data Analysis Automation (DAA) > **技术栈**: TypeScript, PostgreSQL, Vercel Serverless, MCP, Drizzle ORM > **最后更新**: 2026-01-14 ---

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
databasestypescriptbashsqlapidatabaseci/cd

Works with

  • api
  • mcp

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 1338-data-analysis_3128b307 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1338 Data Analysis 3128b307?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 1338 Data Analysis 3128b307
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1338-data-analysis-3128b307/badge)](https://www.skillsdirectory.com/skills/tools-only-1338-data-analysis-3128b307)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Data Analysis Automation 错误案例

> **项目**: Data Analysis Automation (DAA)
> **技术栈**: TypeScript, PostgreSQL, Vercel Serverless, MCP, Drizzle ORM
> **最后更新**: 2026-01-14

---

## 错误 1: SQL 查询未使用 CTE 预过滤

### 📋 错误描述

**常见表现**:
- Bot 归因查询耗时 60-180 秒
- 数据库负载过高
- JOIN 操作性能极差

**根本原因**:
- 直接在 JOIN 中使用全表扫描
- 没有在 CTE 中预先过滤数据
- 在 GROUP BY 中重复计算表达式

**影响**:
- 性能差 3-10 倍
- 资源浪费
- 用户体验差

### ❌ 错误示例

```sql
-- ❌ 错误:没有 CTE,直接 JOIN 全表
SELECT
  bot.bot_id,
  bot.bot_name,
  COUNT(DISTINCT task.id) as task_count,
  SUM(task.actual_energy_cost) / 100 as total_cost_usd
FROM bot
LEFT JOIN task ON task.bot_id = bot.bot_id
  AND task.status IN ('done', 'cancel')
  AND task.created_at >= '2024-01-01'  -- 每次 JOIN 都过滤
GROUP BY bot.bot_id, bot.bot_name;
-- 性能:60-180 秒,全表扫描
```

### ✅ 正确做法

```sql
-- ✅ 正确:使用 CTE 预过滤数据
WITH filtered_tasks AS (
  -- ✅ 先过滤,只保留需要的数据
  SELECT
    bot_id,
    id,
    actual_energy_cost,
    created_at
  FROM task
  WHERE status IN ('done', 'cancel')
    AND created_at >= '2024-01-01'
    AND created_at < '2024-02-01'
),
bot_costs AS (
  -- ✅ 在小数据集上 JOIN 和聚合
  SELECT
    bot.bot_id,
    bot.bot_name,
    COUNT(DISTINCT t.id) as task_count,
    SUM(t.actual_energy_cost) / 100 as total_cost_usd
  FROM bot
  LEFT JOIN filtered_tasks t ON t.bot_id = bot.bot_id
  GROUP BY bot.bot_id, bot.bot_name
)
SELECT * FROM bot_costs;
-- 性能:15-45 秒,性能提升 3-10 倍
```

### 🔍 关键改进

1. ✅ 使用 CTE 在 JOIN 前预过滤数据
2. ✅ 减少 JOIN 操作的数据量
3. ✅ 在 CTE 中明确选择需要的列
4. ✅ 避免在 JOIN 条件中重复过滤

**相关系统级错误**: [E004 - SQL 未使用 CTE](../system-errors/sql-optimization.md)

---

## 错误 2: Vercel Cron 环境变量未正确配置

### 📋 错误描述

**常见表现**:
- Cron job 在 Vercel 上执行失败
- 本地开发正常,部署后报错 "DATABASE_URL is undefined"
- 定时任务静默失败,没有通知

**根本原因**:
- 环境变量只在本地 `.env` 文件中配置
- 没有在 Vercel 项目设置中添加环境变量
- 使用了 Vercel 不支持的环境变量名

### ❌ 错误示例

```typescript
// ❌ 错误:直接使用 process.env,没有 fallback
export default async function handler(req, res) {
  const dbUrl = process.env.DATABASE_URL; // ❌ Vercel 上可能未定义
  const db = await connectDB(dbUrl);
  // 如果 dbUrl 为 undefined,会静默失败或崩溃
}
```

```bash
# ❌ 错误:只在本地 .env 配置
# .env.local (不会部署到 Vercel)
DATABASE_URL=postgresql://localhost:5432/mydb
```

### ✅ 正确做法

```typescript
// ✅ 正确:验证环境变量并提供清晰错误
export default async function handler(req, res) {
  const requiredEnvVars = ['DATABASE_URL', 'CRON_SECRET'];

  for (const varName of requiredEnvVars) {
    if (!process.env[varName]) {
      console.error(`Missing required environment variable: ${varName}`);
      return res.status(500).json({
        error: 'Configuration error',
        message: `${varName} is not configured`
      });
    }
  }

  const dbUrl = process.env.DATABASE_URL!;
  const db = await connectDB(dbUrl);
  // ... rest of logic
}
```

**Vercel 项目设置**:
```bash
# ✅ 在 Vercel Dashboard → Settings → Environment Variables 中配置
DATABASE_URL=postgresql://user:password@host:5432/database
CRON_SECRET=your-random-secret
SLACK_BOT_TOKEN=xoxb-...
SLACK_CHANNEL_ID=C...
```

**验证脚本**:
```typescript
// ✅ 在 CI/CD 或本地验证环境变量
import { config } from 'dotenv';
config();

const requiredEnvVars = [
  'DATABASE_URL',
  'CRON_SECRET',
  'SLACK_BOT_TOKEN',
  'SLACK_CHANNEL_ID'
];

const missing = requiredEnvVars.filter(v => !process.env[v]);

if (missing.length > 0) {
  console.error('❌ Missing environment variables:');
  missing.forEach(v => console.error(`  - ${v}`));
  process.exit(1);
}

console.log('✅ All required environment variables are configured');
```

### 🔍 关键改进

1. ✅ 在代码中验证所有必需的环境变量
2. ✅ 在 Vercel Dashboard 中配置环境变量
3. ✅ 提供清晰的错误信息
4. ✅ 使用验证脚本在部署前检查

---

## 错误 3: Drizzle ORM Schema 与数据库不同步

### 📋 错误描述

**常见表现**:
- 查询时报错 "column does not exist"
- 新增字段在代码中可用但数据库中不存在
- 数据类型不匹配导致插入失败

**根本原因**:
- 修改了 schema.ts 但没有运行 `npm run db:push`
- 没有使用 migration 系统
- 开发和生产数据库 schema 不一致

### ❌ 错误示例

```typescript
// ❌ 错误:修改了 schema 但未同步数据库
// lib/db/schema.ts
export const daaf_bot_revenue_snapshots = pgTable('daaf_bot_revenue_snapshots', {
  id: serial('id').primaryKey(),
  bot_id: integer('bot_id').notNull(),
  bot_name: text('bot_name').notNull(),
  // ❌ 新增字段但未 db:push
  proportional_margin_pct: numeric('proportional_margin_pct', { precision: 10, scale: 2 }),
});

// api/cron/sync-bot-revenue.ts
const result = await db.insert(daaf_bot_revenue_snapshots).values({
  bot_id: 1,
  bot_name: 'Bot A',
  proportional_margin_pct: 0.75 // ❌ 数据库中不存在这个列
});
// 报错:column "proportional_margin_pct" does not exist
```

### ✅ 正确做法

```bash
# ✅ 工作流:修改 schema → 推送到数据库 → 验证
# 1. 修改 schema.ts
# 2. 推送变更到数据库
npm run db:push

# ✅ 或使用 migration(推荐生产环境)
npm run db:generate  # 生成 migration
npm run db:migrate   # 应用 migration

# 3. 验证 schema 同步
npm run db:studio    # 打开 Drizzle Studio 检查
```

```typescript
// ✅ 在代码中检测 schema 不一致
import { sql } from 'drizzle-orm';

async function validateSchema(db: DB) {
  try {
    // ✅ 尝试查询新字段
    await db.select().from(daaf_bot_revenue_snapshots).limit(1);
    console.log('✅ Schema is in sync');
  } catch (error) {
    if (error.message.includes('column') && error.message.includes('does not exist')) {
      console.error('❌ Schema is out of sync. Run `npm run db:push`');
      throw new Error('Database schema is not in sync with code');
    }
    throw error;
  }
}
```

### 🔍 关键改进

1. ✅ 修改 schema 后立即运行 `db:push`
2. ✅ 生产环境使用 migration 而非 push
3. ✅ 在 CI/CD 中验证 schema 同步
4. ✅ 使用 Drizzle Studio 可视化验证

---

## 错误 4: 时区处理不一致

### 📋 错误描述

**常见表现**:
- 每日快照时间偏差 8 小时
- 日期范围查询结果不准确
- 同一天的数据被分到不同日期

**根本原因**:
- 数据库使用 UTC,代码使用本地时间
- 没有统一时区处理
- 日期格式化时未指定时区

### ❌ 错误示例

```typescript
// ❌ 错误:使用本地时间,不指定时区
const today = new Date().toISOString().split('T')[0];
// 如果在北京时间 2024-01-15 01:00 执行
// toISOString() 返回 2024-01-14T17:00:00.000Z
// split 后得到 '2024-01-14',比实际日期早了一天

const snapshot = await db.insert(daaf_daily_summary_snapshots).values({
  snapshot_date: today, // ❌ 时区错误
  total_cost: 1000
});
```

```sql
-- ❌ 错误:查询时不考虑时区
SELECT * FROM daaf_daily_summary_snapshots
WHERE snapshot_date = '2024-01-15'; -- ❌ 可能查不到北京时间的数据
```

### ✅ 正确做法

```typescript
// ✅ 正确:统一使用北京时间(Asia/Shanghai)
import { format, toZonedTime } from 'date-fns-tz';

function getBeijingDate(): string {
  const now = new Date();
  const beijingTime = toZonedTime(now, 'Asia/Shanghai');
  return format(beijingTime, 'yyyy-MM-dd', { timeZone: 'Asia/Shanghai' });
}

const today = getBeijingDate(); // ✅ 北京时间日期
const snapshot = await db.insert(daaf_daily_summary_snapshots).values({
  snapshot_date: today, // ✅ 正确的北京时间日期
  total_cost: 1000
});
```

```typescript
// ✅ 或在数据库查询中转换时区
import { sql } from 'drizzle-orm';

const snapshots = await db
  .select()
  .from(daaf_daily_summary_snapshots)
  .where(
    sql`DATE(snapshot_date AT TIME ZONE 'Asia/Shanghai') = ${today}`
  );
```

### 🔍 关键改进

1. ✅ 使用 `date-fns-tz` 处理时区
2. ✅ 统一使用北京时间(Asia/Shanghai)
3. ✅ 在数据库层面转换时区
4. ✅ 文档中明确说明时区约定

---

## 错误 5: Vercel Serverless 函数超时未处理

### 📋 错误描述

**常见表现**:
- Cron job 执行到一半被强制终止
- 日志显示 "Function execution timed out"
- 数据部分更新,状态不一致

**根本原因**:
- Vercel Hobby 计划函数超时 10 秒
- 长时间运行的查询没有优化
- 没有实现超时保护机制

### ❌ 错误示例

```typescript
// ❌ 错误:可能超过 10 秒的操作,没有超时保护
export default async function handler(req, res) {
  // ❌ 没有超时限制
  const bots = await db.select().from(bot); // 可能很慢

  for (const bot of bots) {
    // ❌ 顺序执行,总时间 = n × 单次时间
    const revenue = await calculateRevenue(bot.id);
    await db.insert(daaf_bot_revenue_snapshots).values({
      bot_id: bot.id,
      revenue
    });
  }

  return res.json({ success: true });
  // 如果超时,数据只部分更新
}
```

### ✅ 正确做法

```typescript
// ✅ 正确:使用超时保护和批处理
export default async function handler(req, res) {
  const startTime = Date.now();
  const maxDuration = 8000; // ✅ 留 2 秒缓冲

  try {
    const bots = await db
      .select()
      .from(bot)
      .limit(100); // ✅ 限制批次大小

    // ✅ 并行处理,设置超时
    const revenuePromises = bots.map(bot =>
      Promise.race([
        calculateRevenue(bot.id),
        new Promise((_, reject) =>
          setTimeout(() => reject(new Error('Timeout')), 5000)
        )
      ]).catch(error => {
        console.error(`Failed for bot ${bot.id}:`, error.message);
        return null; // 单个失败不影响其他
      })
    );

    const revenues = await Promise.all(revenuePromises);

    // ✅ 检查剩余时间
    const elapsed = Date.now() - startTime;
    if (elapsed > maxDuration) {
      console.warn('Approaching timeout, stopping early');
      return res.status(202).json({
        success: 'partial',
        processed: revenues.filter(r => r !== null).length
      });
    }

    // ✅ 批量插入
    const validRevenues = revenues
      .map((revenue, i) => revenue ? { bot_id: bots[i].id, revenue } : null)
      .filter(Boolean);

    if (validRevenues.length > 0) {
      await db.insert(daaf_bot_revenue_snapshots).values(validRevenues);
    }

    return res.json({
      success: true,
      processed: validRevenues.length,
      duration: Date.now() - startTime
    });
  } catch (error) {
    console.error('Handler failed:', error);
    return res.status(500).json({ error: error.message });
  }
}
```

**Vercel 配置**:
```json
// vercel.json - 升级到 Pro 计划可增加超时
{
  "functions": {
    "api/cron/*.ts": {
      "maxDuration": 60 // Pro 计划:最多 60 秒
    }
  }
}
```

### 🔍 关键改进

1. ✅ 设置安全的超时限制(留缓冲)
2. ✅ 使用 `Promise.race()` 为单个操作设置超时
3. ✅ 并行处理提高效率
4. ✅ 批量操作减少数据库往返
5. ✅ 监控执行时间,提前停止
6. ✅ 考虑升级 Vercel 计划延长超时

---

## 📌 总结

### 高频错误排名

1. 🔴 **SQL 未使用 CTE**(错误 1)- 性能差 3-10 倍
2. 🔴 **环境变量未配置**(错误 2)- 部署后崩溃
3. 🟡 **Schema 不同步**(错误 3)- 运行时错误
4. 🟡 **时区处理不一致**(错误 4)- 数据错误
5. 🟡 **Serverless 超时**(错误 5)- 数据不一致

### 关键预防措施

- ✅ 使用 CTE 在 JOIN 前预过滤数据
- ✅ 在 Vercel Dashboard 配置所有环境变量
- ✅ 修改 schema 后立即运行 `db:push`
- ✅ 统一使用北京时间(date-fns-tz)
- ✅ 为 Serverless 函数设置超时保护
- ✅ 使用并行处理和批量操作
- ✅ 监控函数执行时间

### 性能优化清单

- [ ] SQL 查询使用 CTE 预过滤(3-10x 提升)
- [ ] 并行执行独立操作(Promise.all)
- [ ] 批量插入减少数据库往返
- [ ] 设置合理的 LIMIT 和超时
- [ ] 使用索引优化查询
- [ ] 监控 Serverless 函数执行时间

---

**返回**: [project-errors/README.md](./README.md) | [ERROR_CATALOG.md](../ERROR_CATALOG.md)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.