💻

資料庫種子資料生成

👤 ҉Breeze🌔 📦 v1.1.0 ⭐ 4.2 ⬇️ 279 下載
💻 開發程式設計 免費

📖 技能介紹


name: 資料庫初始化 slug: "database-seeding" version: "1.1.0" displayName: "資料庫種子資料生成" summary: "為開發和測試填充逼真、可復現的測試資料到資料庫中,支援多種資料庫系統和資料模式。" description: 為開發、測試和預釋出環境填充真實、可重現的測試資料。 license: MIT metadata: author: AI Agent Skills Community version: 1.0.0


Database Seeding

此技能使AI代理能夠生成並插入真實測試資料到資料庫中,用於開發、測試和預釋出環境。該代理使用確定性生成器或faker庫建立冪等種子指令碼,處理具有正確外部索引鍵順序的關聯資料,支援特定環境的種子配置檔案(最小開發資料與大規模負載測試),並確保種子可以重複執行而不會導致資料重複。

Workflow

  1. 分析目標模式:檢查資料庫模式以識別所有表、其列、資料型別、約束(NOT NULL, UNIQUE, CHECK, 外部索引鍵)和關係。確定正確的插入順序以滿足外部索引鍵依賴——父表必須在子表之前被填充。

  2. 設計種子資料策略:根據使用場景選擇適當的方法。使用固定種子的確定性資料來生成可重現的測試套件。使用基於faker的資料生成器建立看起來真實的開發資料。使用匿名化生產快照為需要真實資料分佈的預釋出環境生成資料。定義每個表的資料量。

    7w4.net小蔥技能站,你的AI助手技能庫。

  3. 生成種子指令碼:用專案語言(Python、JavaScript、SQL等)編寫匹配所有模式約束的種子指令碼。使用Faker庫或類似工具生成真實的姓名、郵箱、地址和日期。通過生成唯一值或使用基於序列的模式處理唯一性約束。將插入操作包裝在事務中以保證原子性。

  4. 確保冪等性:設計可安全重複執行的指令碼。使用INSERT ON CONFLICT DO NOTHING、UPSER模式或截斷後插入策略。在插入前檢查現有資料以避免重複或違反約束。

  5. 支援特定環境配置檔案:建立不同的種子配置檔案——本地開發使用小資料集(每表10-50條記錄),整合測試使用中等資料集(每表1,000-10,000條記錄),效能測試使用大數據集(每表10萬+條記錄)。通過環境變數或命令列引數控制配置檔案。

  6. 執行與驗證:在目標資料庫上執行種子指令碼,驗證行數是否符合預期,並確認通過檢查所有外部索引鍵引用現有行來保持關係完整性。記錄每個表的填充結果。

支援的技術

  • Python: Faker, Factory Boy, SQLAlchemy, psycopg2
  • JavaScript/TypeScript: @faker-js/faker, Prisma seed, Knex seed files, TypeORM
  • SQL: 原始INSERT語句,COPY FROM CSV
  • Ruby: FactoryBot, Faker gem, Rails db:seed
  • 框架: Django fixtures, Laravel seeders, Rails seeds.rb

Usage

提供資料庫模式(或指向遷移檔案)並指定目標環境和所需資料量。代理將生成一個完整的種子指令碼,尊重所有約束和關係。您可以請求特定的資料特徵(例如,“包含來自多個時區的使用者”或“建立跨越過去12個月的訂單”)。

Examples

示例 1:使用Faker的Python種子指令碼

請求:為開發環境填充PostgreSQL資料庫中的使用者、產品和訂單資料。

"""seed.py — Seed development database with realistic test data."""
import random
from datetime import datetime, timedelta
from faker import Faker
import psycopg2

fake = Faker()
Faker.seed(42)  # Deterministic output for reproducibility
random.seed(42)

DB_CONFIG = {
    "host": "localhost",
    "port": 5432,
    "dbname": "dev_db",
    "user": "dev_user",
    "password": "dev_password",
}

NUM_USERS = 50
NUM_PRODUCTS = 30
NUM_ORDERS = 100


def seed():
    conn = psycopg2.connect(**DB_CONFIG)
    cur = conn.cursor()

    # Seed users
    user_ids = []
    for _ in range(NUM_USERS):
        cur.execute(
            """INSERT INTO users (email, password_hash, full_name, created_at)
               VALUES (%s, %s, %s, %s)
               ON CONFLICT (email) DO NOTHING
               RETURNING id""",
            (
                fake.unique.email(),
                fake.sha256(),
                fake.name(),
                fake.date_time_between(start_date="-2y", end_date="now"),
            ),
        )
        row = cur.fetchone()
        if row:
            user_ids.append(row[0])

    # Seed products
    product_ids = []
    for i in range(NUM_PRODUCTS):
        cur.execute(
            """INSERT INTO products (name, description, price, stock_quantity, sku)
               VALUES (%s, %s, %s, %s, %s)
               ON CONFLICT (sku) DO NOTHING
               RETURNING id""",
            (
                fake.catch_phrase(),
                fake.paragraph(nb_sentences=3),
                round(random.uniform(9.99, 499.99), 2),
                random.randint(0, 500),
                f"SKU-{i+1:05d}",
            ),
        )
        row = cur.fetchone()
        if row:
            product_ids.append(row[0])

    # Seed orders with order items
    statuses = ["pending", "confirmed", "shipped", "delivered"]
    for _ in range(NUM_ORDERS):
        user_id = random.choice(user_ids)
        status = random.choice(statuses)
        items = random.sample(product_ids, k=random.randint(1, 5))
        total = 0.0

        cur.execute(
            """INSERT INTO orders (user_id, status, total_amount, shipping_address, ordered_at)
               VALUES (%s, %s, 0, %s, %s) RETURNING id""",
            (user_id, status, fake.address(), fake.date_time_between("-1y", "now")),
        )
        order_id = cur.fetchone()[0]

        for pid in items:
            qty = random.randint(1, 4)
            price = round(random.uniform(9.99, 499.99), 2)
            total += qty * price
            cur.execute(
                """INSERT INTO order_items (order_id, product_id, quantity, unit_price)
                   VALUES (%s, %s, %s, %s)""",
                (order_id, pid, qty, price),
            )

        cur.execute(
            "UPDATE orders SET total_amount = %s WHERE id = %s", (round(total, 2), order_id)
        )

    conn.commit()
    cur.close()
    conn.close()
    print(f"Seeded {len(user_ids)} users, {len(product_ids)} products, {NUM_ORDERS} orders.")


if __name__ == "__main__":
    seed()

示例 2:包含真實測試資料的SQL種子檔案

請求:為小型開發資料集建立一個純SQL種子檔案。

-- seed.sql — Idempotent seed data for local development
-- Run with: psql -U dev_user -d dev_db -f seed.sql

BEGIN;

-- Users
INSERT INTO users (id, email, password_hash, full_name, created_at) VALUES
  (1, 'alice@example.com',  'hash_alice',  'Alice Johnson',  '2024-03-15 09:00:00'),
  (2, 'bob@example.com',    'hash_bob',    'Bob Martinez',   '2024-05-20 14:30:00'),
  (3, 'carol@example.com',  'hash_carol',  'Carol Chen',     '2024-07-01 11:15:00'),
  (4, 'dave@example.com',   'hash_dave',   'Dave Okafor',    '2024-09-10 08:45:00'),
  (5, 'eve@example.com',    'hash_eve',    'Eve Andersson',  '2024-11-28 16:00:00')
ON CONFLICT (id) DO NOTHING;

-- Products
INSERT INTO products (id, name, description, price, stock_quantity, sku) VALUES
  (1, 'Wireless Keyboard',   'Bluetooth mechanical keyboard',  79.99,  150, 'SKU-00001'),
  (2, 'USB-C Hub',           '7-in-1 USB-C docking station',   49.99,  300, 'SKU-00002'),
  (3, 'Noise-Cancelling Headphones', 'Over-ear ANC headphones', 199.99, 75, 'SKU-00003'),
  (4, '4K Monitor',          '27-inch IPS 4K display',         399.99,  40, 'SKU-00004'),
  (5, 'Laptop Stand',        'Adjustable aluminum stand',       34.99, 200, 'SKU-00005')
ON CONFLICT (id) DO NOTHING;

-- Orders
INSERT INTO orders (id, user_id, status, total_amount, shipping_address, ordered_at) VALUES
  (1, 1, 'delivered',  129.98, '123 Oak St, Portland, OR 97201',   '2024-12-01 10:00:00'),
  (2, 2, 'shipped',    199.99, '456 Elm Ave, Austin, TX 78701',    '2025-01-05 14:20:00'),
  (3, 3, 'confirmed',  484.98, '789 Pine Rd, Seattle, WA 98101',   '2025-01-10 09:30:00'),
  (4, 1, 'pending',     49.99, '123 Oak St, Portland, OR 97201',   '2025-01-12 16:45:00')
ON CONFLICT (id) DO NOTHING;

-- Order items
INSERT INTO order_items (id, order_id, product_id, quantity, unit_price) VALUES
  (1, 1, 1, 1, 79.99),
  (2, 1, 2, 1, 49.99),
  (3, 2, 3, 1, 199.99),
  (4, 3, 4, 1, 399.99),
  (5, 3, 5, 1, 34.99),
  (6, 4, 2, 1, 49.99)
ON CONFLICT (id) DO NOTHING;

-- Reset sequences to avoid conflicts with future inserts
SELECT setval('users_id_seq',    (SELECT MAX(id) FROM users));
SELECT setval('products_id_seq', (SELECT MAX(id) FROM products));
SELECT setval('orders_id_seq',   (SELECT MAX(id) FROM orders));
SELECT setval('order_items_id_seq', (SELECT MAX(id) FROM order_items));

COMMIT;

最佳實踐

  • 設定固定的隨機種子(例如,Faker.seed(42))以生成確定性資料,使測試結果可重現,並使種子輸出的差異具有意義。
  • 始終尊重外部索引鍵順序——先插入父行再插入子行。在編寫指令碼前繪製依賴圖以避免違反約束。
  • 使用ON CONFLICT DO NOTHING或UPSER模式使種子指令碼冪等。執行兩次種子應產生相同結果,而不是重複資料或丟擲錯誤。
  • 按環境分離種子配置檔案——本地開發使用小而快的種子,CI整合測試使用較大的種子,負載測試使用更大的種子。通過環境變數控制。
  • 永遠不要用測試資料填充生產資料庫。在種子指令碼頂部新增環境檢查(例如,assert os.environ["ENV"] != "production")作為安全防護。
  • 在使用顯式ID填充後重置自增序列以防止應用程式插入新行時主鍵衝突。

Edge Cases

  • Faker的唯一性約束衝突:Faker不保證在大數據集中具有唯一性。使用fake.unique.email()或在生成值後附加計數器以避免重複。通過fake.unique.clear()在測試執行之間重置唯一追蹤器。
  • 迴圈外部索引鍵:當表A引用表B,而表B又引用表A時,首先插入兩個表中的行並使用可空的FK列,然後在第二輪更新FK值。
  • 大種子資料集與效能:對於超過10,000行的資料填充,使用批次插入方法(PostgreSQL中的COPY,MySQL中的LOAD DATA INFILE)而不是單個INSERT語句。在批次載入期間停用索引和約束,之後再重新啟用。
  • 時間依賴的測試資料:如果您的應用程式邏輯依賴於日期(例如,“過去30天內的訂單”),請生成相對於當前日期的日期,而不是硬編碼會過期的日期。
  • 填充二進位制或檔案資料:對於引用上傳檔案或影像的表,請使用佔位符檔案路徑或小的base64編碼測試影像進行填充,而不是嘗試生成完整的二進位制內容。

🤖 AI 評測

這個技能質量較好,能幫助開發者快速掌握資料庫測試資料的生成方法。文件結構清晰,步驟明確,程式碼示例豐富實用,支援多種程式語言和資料庫。不過內容以文字說明為主,缺少可直接使用的示例檔案,對於新手來說可能需要更多實戰指導。總體適合需要為專案生成測試資料的開發者使用。

📊 多維度評分

適應性3.8
規範性4
有效性4.6
可靠性4
可信度4.4

📁 包含檔案 (3 個)

📄 SKILL.md 10.6 KB
📄 _meta.json 135 B
📄 _skillhub_meta.json 140 B