mcpField
B
batch-operations

batch-operations

github.com/happy-technologies-llcデータ・データベース4143 回インストール3 日前に更新
リポジトリ

batch-operations について

大量のレコード作成、更新、インポートを扱う ServiceNow 管理者、開発者、データ移行担当者向けのスキルです。ServiceNow のツールやスクリプトを用いたバッチ処理、性能調整、エラー追跡、再試行、ロールバックを説明します。

主な機能

  1. 01レコードの一括作成と更新
  2. 02関連レコード作成のパターン
  3. 03バッチ処理とクエリの最適化
  4. 04レコード単位のエラー追跡と再試行
  5. 05ロールバックとデータ移行のパターン

活用シーン

  1. 01ServiceNow レコードの一括作成・更新
  2. 02テーブル間のデータ移行
  3. 03外部 JSON データのインポート
  4. 04エラーを追跡しながらレコードを一括修正

MCP 対応

SN-Batch-Create、SN-Batch-Update、SN-Create-Record、SN-Execute-Background-Script などの MCP ツールによる一括・並列操作を説明します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/happy-technologies-llc/happy-platform-skills --skill batch-operations

インストール後、Claude Code で/batch-operationsを入力して読み込まれたか確認します。

詳細

一括操作

概要

このスキルでは、ServiceNow で一括操作を効率的に行う手法について説明します。

  • 適切なリレーションを設定した大量のレコード作成
  • 検証とエラー処理を伴う一括更新
  • 大規模なデータセットを扱う際のパフォーマンス上の考慮事項
  • トランザクション管理とロールバック戦略
  • 並列処理のパターン

使用する場面: 多数のレコードを一度に作成または更新するとき、データ移行、一括インポート、大量のデータ修正を行うとき。

対象ユーザー: 管理者、開発者、データ移行のスペシャリスト。

前提条件

  • ロール: admin またはテーブル固有の書き込み権限
  • アクセス: 対象テーブルと関連する参照テーブル
  • 知識: GlideRecord API、テーブルのリレーション、ServiceNow のデータモデル
  • 環境: 大規模な操作は、まず本番環境以外でテストしてください

パフォーマンスのガイドライン

レコード数の推奨事項
件数方法推定所要時間
1~10MCP の並列呼び出し< 5 秒
10~100SN-Batch-Create/Update5~30 秒
100~1,000バックグラウンドスクリプトのバッチ1~5 分
1,000~10,000バッチ処理を行うスケジュール済みジョブ10~60 分
10,000 以上インポートセットまたはデータポンプ数時間
MCP の並列処理

テスト済み・検証済み: 1 つのメッセージで 43 件以上の MCP 並列呼び出しに成功しています。

Parallel MCP calls are preferred for:
- Independent record operations
- Different tables
- No interdependencies
- Maximum throughput

手順

フェーズ 1:大量のレコード作成
ステップ 1.1:シンプルな一括作成

1 回の操作で複数のレコードを作成します。

MCP を使用:

Tool: SN-Batch-Create
Parameters:
  records:
    - table_name: incident
      data:
        short_description: "Server down - Web01"
        caller_id: [user_sys_id]
        category: hardware
        priority: 1
    - table_name: incident
      data:
        short_description: "Server down - Web02"
        caller_id: [user_sys_id]
        category: hardware
        priority: 1
    - table_name: incident
      data:
        short_description: "Server down - Web03"
        caller_id: [user_sys_id]
        category: hardware
        priority: 1

応答:

{
  "success": true,
  "created": [
    { "table": "incident", "sys_id": "abc123...", "number": "INC0010001" },
    { "table": "incident", "sys_id": "def456...", "number": "INC0010002" },
    { "table": "incident", "sys_id": "ghi789...", "number": "INC0010003" }
  ],
  "errors": []
}
ステップ 1.2:MCP の並列呼び出し

最大のスループットを得るには、1 つのメッセージで MCP を並列に呼び出します。

インシデントの並列作成(10 件):

# Call 1:
Tool: SN-Create-Record
Parameters:
  table_name: incident
  data:
    short_description: "Batch test 1"
    category: inquiry

# Call 2:
Tool: SN-Create-Record
Parameters:
  table_name: incident
  data:
    short_description: "Batch test 2"
    category: inquiry

# Call 3-10: Continue pattern...

すべての呼び出しが同時に実行されるため、操作間の待機はありません。

ステップ 1.3:リレーションを設定した作成

親レコードと子レコードを、リレーションを維持したまま作成します。

MCP を使用(依存関係があるため逐次実行):

# Step 1: Create parent record
Tool: SN-Create-Record
Parameters:
  table_name: change_request
  data:
    short_description: "Server Infrastructure Upgrade"
    category: hardware
    type: standard

# Step 2: Create child tasks (use parent sys_id from step 1)
Tool: SN-Batch-Create
Parameters:
  records:
    - table_name: change_task
      data:
        parent: [change_request_sys_id]
        short_description: "Backup existing configuration"
        change_task_type: planning
        order: 100
    - table_name: change_task
      data:
        parent: [change_request_sys_id]
        short_description: "Install new hardware"
        change_task_type: implementation
        order: 200
    - table_name: change_task
      data:
        parent: [change_request_sys_id]
        short_description: "Verify functionality"
        change_task_type: testing
        order: 300
ステップ 1.4:複雑な作成処理のバックグラウンドスクリプト

複雑なロジックや非常に大規模なバッチには、次を使用します。

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Batch creation with relationships
    var projectData = [
      {
        name: 'Project Alpha',
        tasks: [
          { name: 'Task A1', order: 1 },
          { name: 'Task A2', order: 2 },
          { name: 'Task A3', order: 3 }
        ]
      },
      {
        name: 'Project Beta',
        tasks: [
          { name: 'Task B1', order: 1 },
          { name: 'Task B2', order: 2 }
        ]
      }
    ];

    var created = { projects: 0, tasks: 0 };

    projectData.forEach(function(project) {
      // Create project
      var prj = new GlideRecord('pm_project');
      prj.initialize();
      prj.short_description = project.name;
      var prjId = prj.insert();
      created.projects++;

      // Create tasks
      project.tasks.forEach(function(task) {
        var tsk = new GlideRecord('pm_project_task');
        tsk.initialize();
        tsk.parent = prjId;
        tsk.short_description = task.name;
        tsk.order = task.order;
        tsk.insert();
        created.tasks++;
      });

      gs.info('Created project: ' + project.name + ' with ' + project.tasks.length + ' tasks');
    });

    gs.info('Summary: ' + JSON.stringify(created));
  description: Batch create projects with tasks
フェーズ 2:一括更新
ステップ 2.1:シンプルな一括更新

sys_id で複数のレコードを更新します。

MCP を使用:

Tool: SN-Batch-Update
Parameters:
  updates:
    - table_name: incident
      sys_id: [incident1_sys_id]
      data:
        priority: 2
        state: 2
        work_notes: "Escalated per management request"
    - table_name: incident
      sys_id: [incident2_sys_id]
      data:
        priority: 2
        state: 2
        work_notes: "Escalated per management request"
    - table_name: incident
      sys_id: [incident3_sys_id]
      data:
        priority: 2
        state: 2
        work_notes: "Escalated per management request"
ステップ 2.2:クエリベースの一括更新

クエリに一致するすべてのレコードを更新します。

バックグラウンドスクリプトを使用:

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Query-based bulk update
    var TABLE = 'incident';
    var QUERY = 'active=true^category=inquiry^priority=5';
    var UPDATES = {
      priority: 4,
      work_notes: 'Priority adjusted per SLA review'
    };
    var MAX_UPDATES = 1000;
    var DRY_RUN = true;

    var gr = new GlideRecord(TABLE);
    gr.addEncodedQuery(QUERY);
    gr.setLimit(MAX_UPDATES);
    gr.query();

    gs.info('Found ' + gr.getRowCount() + ' records matching query');

    var updated = 0;
    var errors = 0;

    while (gr.next()) {
      try {
        if (DRY_RUN) {
          gs.info('[DRY RUN] Would update: ' + gr.number);
        } else {
          for (var field in UPDATES) {
            gr[field] = UPDATES[field];
          }
          gr.update();
          updated++;
        }
      } catch (e) {
        errors++;
        gs.error('Error updating ' + gr.number + ': ' + e.message);
      }
    }

    gs.info('Complete: Updated=' + updated + ', Errors=' + errors + ', DryRun=' + DRY_RUN);
  description: Bulk update incidents by query
ステップ 2.3:条件付き更新

レコードの条件に応じて、異なる更新を適用します。

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Conditional bulk updates
    var gr = new GlideRecord('incident');
    gr.addQuery('active', true);
    gr.addQuery('priority', 'IN', '1,2');
    gr.setLimit(500);
    gr.query();

    var stats = { p1_updates: 0, p2_updates: 0 };

    while (gr.next()) {
      if (gr.priority == 1) {
        // P1 gets immediate attention
        if (gr.assigned_to.nil()) {
          gr.assignment_group = 'Critical Response Team';
          gr.work_notes = 'Auto-assigned to Critical Response Team';
          gr.update();
          stats.p1_updates++;
        }
      } else if (gr.priority == 2) {
        // P2 gets SLA check
        var age = GlideDateTime.subtract(new GlideDateTime(gr.sys_created_on), new GlideDateTime()).getDayPart();
        if (age > 2 && gr.state == 1) {
          gr.escalation = 1;
          gr.work_notes = 'Auto-escalated: P2 older than 2 days without progress';
          gr.update();
          stats.p2_updates++;
        }
      }
    }

    gs.info('Conditional updates complete: ' + JSON.stringify(stats));
  description: Apply conditional updates based on priority
フェーズ 3:パフォーマンスの最適化
ステップ 3.1:バッチ処理パターン

大規模なデータセットを、管理しやすいバッチに分けて処理します。

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Optimized batch processing
    var CONFIG = {
      table: 'incident',
      query: 'active=true',
      batchSize: 200,
      maxBatches: 50,
      pauseBetweenBatches: false  // true adds 100ms delay
    };

    var totalProcessed = 0;
    var batchNum = 0;
    var startTime = new GlideDateTime();

    while (batchNum < CONFIG.maxBatches) {
      var gr = new GlideRecord(CONFIG.table);
      gr.addEncodedQuery(CONFIG.query);
      gr.orderBy('sys_created_on');
      gr.chooseWindow(batchNum * CONFIG.batchSize, (batchNum + 1) * CONFIG.batchSize);
      gr.query();

      if (!gr.hasNext()) {
        break;
      }

      var batchProcessed = 0;
      while (gr.next()) {
        // Process record (minimal operations for speed)
        batchProcessed++;
      }

      totalProcessed += batchProcessed;
      batchNum++;

      // Progress logging every 10 batches
      if (batchNum % 10 === 0) {
        gs.info('Progress: Batch ' + batchNum + ', Total processed: ' + totalProcessed);
      }

      // Optional pause to reduce system load
      if (CONFIG.pauseBetweenBatches) {
        gs.sleep(100);
      }
    }

    var endTime = new GlideDateTime();
    var duration = GlideDateTime.subtract(startTime, endTime).getNumericValue() / 1000;
    var rate = totalProcessed / duration;

    gs.info('Complete: ' + totalProcessed + ' records in ' + duration.toFixed(2) + ' seconds (' + rate.toFixed(0) + ' records/sec)');
  description: Optimized batch processing with metrics
ステップ 3.2:クエリの最適化

一括操作には、効率的なクエリパターンを使用します。

件数の集計には GlideAggregate を使用:

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Efficient counting with GlideAggregate
    var ga = new GlideAggregate('incident');
    ga.addQuery('active', true);
    ga.addAggregate('COUNT');
    ga.groupBy('priority');
    ga.query();

    var results = [];
    while (ga.next()) {
      results.push({
        priority: ga.priority.getDisplayValue(),
        count: parseInt(ga.getAggregate('COUNT'))
      });
    }

    gs.info('Priority Distribution:\n' + JSON.stringify(results, null, 2));
  description: Count incidents by priority efficiently

一括更新には setWorkflow(false) を使用:

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Disable business rules for bulk operations
    var gr = new GlideRecord('incident');
    gr.addQuery('state', 7);  // Closed
    gr.addQuery('sys_updated_on', '<', gs.daysAgo(365));
    gr.setLimit(1000);
    gr.query();

    // Disable workflows/business rules
    gr.setWorkflow(false);

    var count = 0;
    while (gr.next()) {
      gr.archived = true;
      gr.update();
      count++;
    }

    gs.info('Archived ' + count + ' old closed incidents (business rules disabled)');
  description: Bulk archive with business rules disabled

警告: ワークフローを無効にするのは、その影響を十分に理解している場合に限ってください。

ステップ 3.3:メモリの最適化

大規模なデータセットによるメモリの問題を防ぎます。

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Memory-efficient processing
    var BATCH_SIZE = 100;
    var offset = 0;
    var totalProcessed = 0;
    var hasMore = true;

    while (hasMore) {
      // Use GlideRecord with window to avoid loading all records
      var gr = new GlideRecord('cmdb_ci');
      gr.addQuery('operational_status', 1);
      gr.orderBy('sys_id');  // Consistent ordering
      gr.chooseWindow(offset, offset + BATCH_SIZE);
      gr.query();

      if (gr.getRowCount() === 0) {
        hasMore = false;
        break;
      }

      while (gr.next()) {
        // Process record - avoid storing in arrays
        // Direct operations only
        totalProcessed++;
      }

      offset += BATCH_SIZE;

      // Check if we got fewer than batch size (last batch)
      if (gr.getRowCount() < BATCH_SIZE) {
        hasMore = false;
      }
    }

    gs.info('Processed ' + totalProcessed + ' CI records');
  description: Memory-efficient CI processing
フェーズ 4:エラー処理
ステップ 4.1:レコードごとのエラー処理

成功と失敗を個別に記録します。

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Comprehensive error tracking
    var results = {
      success: [],
      errors: [],
      skipped: []
    };

    var gr = new GlideRecord('incident');
    gr.addQuery('active', true);
    gr.setLimit(100);
    gr.query();

    while (gr.next()) {
      try {
        // Validation
        if (gr.short_description.nil()) {
          results.skipped.push({
            number: gr.number.toString(),
            reason: 'Missing short description'
          });
          continue;
        }

        // Attempt update
        gr.work_notes = 'Batch processed on ' + new GlideDateTime().getDisplayValue();
        gr.update();

        results.success.push({
          number: gr.number.toString(),
          sys_id: gr.sys_id.toString()
        });

      } catch (e) {
        results.errors.push({
          number: gr.number.toString(),
          error: e.message
        });
      }
    }

    gs.info('Results Summary:');
    gs.info('  Success: ' + results.success.length);
    gs.info('  Errors: ' + results.errors.length);
    gs.info('  Skipped: ' + results.skipped.length);

    if (results.errors.length > 0) {
      gs.error('Errors:\n' + JSON.stringify(results.errors, null, 2));
    }

    if (results.skipped.length > 0) {
      gs.warn('Skipped:\n' + JSON.stringify(results.skipped, null, 2));
    }
  description: Batch update with comprehensive error tracking
ステップ 4.2:再試行パターン

一時的な障害に備えて、再試行ロジックを実装します。

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Retry pattern for batch operations
    var MAX_RETRIES = 3;
    var RETRY_DELAY = 1000;  // milliseconds

    function updateWithRetry(tableName, sysId, data) {
      var attempts = 0;
      var lastError = null;

      while (attempts < MAX_RETRIES) {
        attempts++;
        try {
          var gr = new GlideRecord(tableName);
          if (gr.get(sysId)) {
            for (var field in data) {
              gr[field] = data[field];
            }
            gr.update();
            return { success: true, attempts: attempts };
          } else {
            return { success: false, error: 'Record not found', attempts: attempts };
          }
        } catch (e) {
          lastError = e.message;
          gs.warn('Attempt ' + attempts + ' failed: ' + e.message);
          if (attempts < MAX_RETRIES) {
            gs.sleep(RETRY_DELAY * attempts);  // Exponential backoff
          }
        }
      }

      return { success: false, error: lastError, attempts: attempts };
    }

    // Example usage
    var recordsToUpdate = [
      { sys_id: '[sys_id_1]', data: { state: 2 } },
      { sys_id: '[sys_id_2]', data: { state: 2 } }
    ];

    var results = [];
    recordsToUpdate.forEach(function(record) {
      var result = updateWithRetry('incident', record.sys_id, record.data);
      result.sys_id = record.sys_id;
      results.push(result);
    });

    gs.info('Update Results:\n' + JSON.stringify(results, null, 2));
  description: Batch update with retry logic
ステップ 4.3:トランザクションのロールバック

バッチ操作が失敗した場合のロールバックを実装します。

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Batch operation with rollback capability
    var operations = [];  // Track for potential rollback
    var allSuccess = true;

    try {
      // Operation 1
      var inc1 = new GlideRecord('incident');
      inc1.get('[incident_1_sys_id]');
      var oldState1 = inc1.state.toString();
      inc1.state = 6;
      inc1.update();
      operations.push({ table: 'incident', sys_id: inc1.sys_id.toString(), field: 'state', oldValue: oldState1 });

      // Operation 2
      var inc2 = new GlideRecord('incident');
      inc2.get('[incident_2_sys_id]');
      var oldState2 = inc2.state.toString();
      inc2.state = 6;
      inc2.update();
      operations.push({ table: 'incident', sys_id: inc2.sys_id.toString(), field: 'state', oldValue: oldState2 });

      // Operation 3 (simulated failure)
      // throw new Error('Simulated failure for testing rollback');

      gs.info('All ' + operations.length + ' operations completed successfully');

    } catch (e) {
      allSuccess = false;
      gs.error('Error occurred: ' + e.message);
      gs.info('Rolling back ' + operations.length + ' operations...');

      // Rollback in reverse order
      for (var i = operations.length - 1; i >= 0; i--) {
        var op = operations[i];
        try {
          var rollback = new GlideRecord(op.table);
          if (rollback.get(op.sys_id)) {
            rollback[op.field] = op.oldValue;
            rollback.setWorkflow(false);  // Avoid triggering additional logic
            rollback.update();
            gs.info('Rolled back: ' + op.table + ' ' + op.sys_id);
          }
        } catch (rollbackError) {
          gs.error('Rollback failed for ' + op.sys_id + ': ' + rollbackError.message);
        }
      }

      gs.info('Rollback complete');
    }
  description: Batch operation with transaction-like rollback
フェーズ 5:データ移行パターン
ステップ 5.1:テーブル間の移行

変換を行いながら、テーブル間でデータを移行します。

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // Table-to-table migration
    var SOURCE_TABLE = 'x_old_app_requests';
    var TARGET_TABLE = 'sc_request';
    var BATCH_SIZE = 100;

    var fieldMapping = {
      'old_number': 'number',
      'old_description': 'description',
      'requestor': 'requested_for',
      'submit_date': 'opened_at'
    };

    var migrated = 0;
    var errors = 0;

    var source = new GlideRecord(SOURCE_TABLE);
    source.addQuery('migrated', false);
    source.setLimit(BATCH_SIZE);
    source.query();

    while (source.next()) {
      try {
        var target = new GlideRecord(TARGET_TABLE);
        target.initialize();

        // Apply field mapping
        for (var oldField in fieldMapping) {
          var newField = fieldMapping[oldField];
          target[newField] = source[oldField];
        }

        // Transform values
        target.state = mapState(source.old_state);
        target.priority = mapPriority(source.old_priority);

        var newSysId = target.insert();

        // Mark source as migrated
        source.migrated = true;
        source.migrated_to = newSysId;
        source.update();

        migrated++;

      } catch (e) {
        errors++;
        gs.error('Error migrating ' + source.old_number + ': ' + e.message);
      }
    }

    gs.info('Migration complete: ' + migrated + ' migrated, ' + errors + ' errors');

    function mapState(oldState) {
      var stateMap = { 'open': 1, 'in_progress': 2, 'closed': 3 };
      return stateMap[oldState] || 1;
    }

    function mapPriority(oldPriority) {
      var priorityMap = { 'critical': 1, 'high': 2, 'medium': 3, 'low': 4 };
      return priorityMap[oldPriority] || 4;
    }
  description: Table-to-table data migration with transformation
ステップ 5.2:外部データのインポート

外部ソース(JSON 配列)からデータをインポートします。

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    // External data import pattern
    var importData = [
      { email: '[email protected]', first_name: 'John', last_name: 'Doe', department: 'IT' },
      { email: '[email protected]', first_name: 'Jane', last_name: 'Smith', department: 'HR' },
      { email: '[email protected]', first_name: 'Bob', last_name: 'Wilson', department: 'Finance' }
    ];

    var results = { created: 0, updated: 0, errors: 0 };

    importData.forEach(function(data) {
      try {
        // Check for existing record
        var existing = new GlideRecord('sys_user');
        existing.addQuery('email', data.email);
        existing.query();

        if (existing.next()) {
          // Update existing
          existing.first_name = data.first_name;
          existing.last_name = data.last_name;
          existing.department = lookupDepartment(data.department);
          existing.update();
          results.updated++;
          gs.info('Updated user: ' + data.email);
        } else {
          // Create new
          var newUser = new GlideRecord('sys_user');
          newUser.initialize();
          newUser.email = data.email;
          newUser.user_name = data.email.split('@')[0];
          newUser.first_name = data.first_name;
          newUser.last_name = data.last_name;
          newUser.department = lookupDepartment(data.department);
          newUser.active = true;
          newUser.insert();
          results.created++;
          gs.info('Created user: ' + data.email);
        }

      } catch (e) {
        results.errors++;
        gs.error('Error importing ' + data.email + ': ' + e.message);
      }
    });

    gs.info('Import complete: ' + JSON.stringify(results));

    function lookupDepartment(name) {
      var dept = new GlideRecord('cmn_department');
      dept.addQuery('name', name);
      dept.query();
      if (dept.next()) {
        return dept.sys_id.toString();
      }
      return '';
    }
  description: Import external user data with upsert logic

ツールの使用概要

操作MCP ツール目的
一括作成SN-Batch-Create複数のレコードを作成
一括更新SN-Batch-Updatesys_id で複数のレコードを更新
並列作成SN-Create-Record(複数)最大のスループット
並列更新SN-Update-Record(複数)最大のスループット
複雑なバッチ処理SN-Execute-Background-Script高度なロジック
クエリSN-Query-Table一括操作の対象レコードを検索

パフォーマンス比較

方法100 件1,000 件10,000 件
MCP の逐次呼び出し約 50 秒約 500 秒実用的ではありません
MCP の並列呼び出し(10)約 5 秒約 50 秒約 500 秒
SN-Batch-Create約 3 秒約 30 秒約 300 秒
バックグラウンドスクリプト約 2 秒約 20 秒約 200 秒
setWorkflow(false)約 1 秒約 10 秒約 100 秒

ベストプラクティス

  • まずテストする: DRY_RUN=true を指定するか、小規模なサブセットで実行します
  • 上限を設定する: 無制限のレコードを処理しないでください
  • 適切にバッチ処理する: パフォーマンスを最適化するには、1 バッチあたり 100~500 件にします
  • 進捗を記録する: 10~100 件の処理ごとに進捗を報告します
  • エラーに対処する: レコードごとに try-catch を実装します
  • 変更を追跡する: ロールバックに備えて古い値を保存します
  • ビジネスルールを考慮する: 適切な場合にのみ setWorkflow(false) を使用します
  • パフォーマンスを監視する: 処理速度(レコード数/秒)を追跡します
  • トランザクションを使用する: 関連する変更をまとめ、アトミックな操作にします
  • 操作を記録する: 監査のため、変更内容を記録します

トラブルシューティング

操作のタイムアウト

症状: スクリプトの実行が処理の途中で停止します
原因:

  • 1 回の実行で処理するレコード数が多すぎる
  • 複雑なビジネスルールが実行された 解決策:
  • バッチサイズを小さくします
  • 自己スケジューリングのパターンを使用します
  • 適切な場合はワークフローを無効にします
メモリエラー

症状: 「メモリ不足」またはパフォーマンスの低下
原因:

  • 一度に読み込むレコード数が多すぎる
  • 結果を配列に格納している 解決策:
  • ページネーションには chooseWindow() を使用します
  • 処理したデータはすぐに破棄します
  • 結果をメモリに蓄積しないでください
重複レコードが作成される

症状: 同じレコードが複数作成されます
原因:

  • 一意制約のチェックがない
  • スクリプトが複数回実行された 解決策:
  • 挿入前に必ず既存のレコードを確認します
  • 重複排除には一意キーを使用します
  • 冪等性チェックを追加します
ビジネスルールが実行されない

症状: 期待される副作用が発生しません
原因:

  • setWorkflow(false) が使用されている
  • レコードが正しく更新されていない 解決策:
  • ルールの実行が必要な場合は setWorkflow(false) を削除します
  • フィールドの更新が有効であることを確認します
  • ビジネスルールの条件を確認します

関連スキル

  • admin/script-execution - バックグラウンドスクリプトの実行
  • admin/update-set-management - バッチ操作の変更を追跡
  • admin/user-provisioning - ユーザーの一括操作
  • admin/deployment-workflow - インスタンス間でバッチスクリプトをデプロイ

参考資料

コメント