Bulk API 2.0 for Salesforce Query 部分详解

28 阅读5分钟

一、核心概念:这是什么?

Bulk API 2.0 Query 是 Salesforce 提供的一种批量数据查询服务,专门用于:

  1. 处理大量数据:当需要查询百万甚至千万级别的记录时
  2. 异步执行:查询在后台运行,不会阻塞你的应用程序
  3. 自动分块处理:系统会自动把大数据查询分解成小任务并行处理
  4. 结果压缩:返回的数据总是被压缩以减少传输量

简单比喻:就像你要从图书馆(Salesforce数据库)复印100万页资料,不是自己一页页去复印,而是:

  • 把需求清单给管理员(提交查询作业)
  • 管理员找多个助手同时复印(自动分块并行处理)
  • 复印完打包压缩给你(返回压缩结果)

二、主要特点和工作流程

工作流程图示

image.png

关键特性详解

  1. 异步处理

    • 你提交查询后立即得到一个jobId
    • 不必等待查询完成,可以去做其他事情
    • 定期检查作业状态,完成后下载结果
  2. 自动分块(PK Chunking)

image.png

三、支持的API端点(URIs和HTTP方法)

文档中列出的6个端点构成了完整的查询作业生命周期管理:

操作HTTP方法端点路径用途
创建作业POST/jobs/query发起一个新的查询作业
列出所有作业GET/jobs/query查看组织中所有的查询作业
查看单个作业GET/jobs/query/{id}查看特定作业的详细信息
获取结果GET/jobs/query/{id}/results下载查询结果(压缩格式)
中止作业PATCH/jobs/query/{id}停止正在运行的作业
删除作业DELETE/jobs/query/{id}删除作业(包括结果)

版本要求:需要 API 版本 47.0 或更高。

四、重要限制和注意事项(SOQL考虑因素)

这是最需要注意的部分,因为这些限制会影响查询是否能够成功执行。

1. 禁用PK分块的情况

重要规则:如果在查询中使用 LIMITORDER BY,PK分块功能会被禁用

  • 后果:查询变慢,可能超时失败
  • 建议:如果遇到超时,首先去掉 ORDER BY 或 LIMIT 子句

2. 完全不支持的SOQL功能

Bulk API 2.0 无法执行包含以下内容的查询:

❌ 不支持 GROUP BY(分组)
❌ 不支持 OFFSET(偏移量)
❌ 不支持 TYPEOF(类型判断)
❌ 不支持 COUNT()等聚合函数
❌ 不支持 GROUP BY中的日期函数
❌ 不支持复合地址字段或地理字段(要查询其单独的子字段)
❌ 不支持父对子关系查询(只支持子对父)

3. 支持的查询示例

-- ✅ 支持的查询示例
SELECT Id, Name, Account.Name, CreatedDate 
FROM Contact 
WHERE CreatedDate = LAST_N_DAYS:30 
  AND Account.Industry = 'Technology'
-- ❌ 不支持的查询示例
SELECT COUNT(Id) FROM Contact  -- 使用了聚合函数
SELECT Id FROM Contact ORDER BY CreatedDate  -- 禁用PK分块
SELECT Id, Name FROM Contact GROUP BY Name  -- 使用了GROUP BY

/jobs/query POST 详细步骤解析

1. 请求地址(URI)

/services/data/vXX.X/jobs/query
  • vXX.X:API版本号,必须是 47.0 或更高
  • /jobs/query:专门用于创建查询作业的端点

2. 认证方式

必须在请求头中提供:

Authorization: Bearer token

3. 请求格式(JSON)

必须发送一个JSON格式的数据包:

{
  "operation": "query",
  "query": "SELECT Id FROM Account"
}

两个必填参数

参数说明
operation"query" 或 "queryAll"query:只查询未删除的记录 queryAll:包含已删除和归档的记录
querySOQL查询语句要执行的SQL查询

4. 完整的请求示例

简单查询示例

curl -X POST \
  https://your-instance.salesforce.com/services/data/v55.0/jobs/query \
  -H "Authorization: Bearer 00DC8000000NTCb!AQEAQL..." \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "query",
    "query": "SELECT Id, Name, Industry FROM Account WHERE CreatedDate = LAST_N_DAYS:30"
  }'

带可选参数的复杂示例

{
  "operation": "query",
  "query": "SELECT Id, Name FROM Account",
  "contentType": "CSV",
  "columnDelimiter": "COMMA",
  "lineEnding": "CRLF"
}

可选参数详解

参数可选值默认值说明
contentType"CSV""CSV"结果格式,目前只支持CSV
columnDelimiter"COMMA""PIPE""TAB""CARET""BACKQUOTE""SEMICOLON""COMMA"CSV列分隔符
lineEnding"LF""CRLF""LF"行结束符(换行符)

分隔符对照表

  • COMMA = ,(逗号)
  • PIPE = |(竖线)
  • TAB = \t(制表符)
  • CARET = ^(脱字符)
  • BACKQUOTE = `(反引号)
  • SEMICOLON = ;(分号)

5. 响应解析

当您成功提交查询后,会得到类似这样的响应:

{
  "id": "750R0000000zlh9IAA",
  "operation": "query",
  "object": "Account",
  "createdById": "005R0000000GiwjIAC",
  "createdDate": "2018-12-10T17:50:19.000+0000",
  "systemModstamp": "2018-12-10T17:50:19.000+0000",
  "state": "UploadComplete",
  "concurrencyMode": "Parallel",
  "contentType": "CSV",
  "apiVersion": 46.0,
  "lineEnding": "LF",
  "columnDelimiter": "COMMA"
}

最重要的响应参数

  1. id"750R0000000zlh9IAA"

    • 这是最重要的信息!  后续所有操作(检查状态、下载结果)都需要这个ID
    • 就像餐厅的取餐号,凭这个号码才能取餐
  2. state"UploadComplete"

    • 作业的当前状态

    • 状态流转:UploadComplete → InProgress → JobComplete

    • 可能的状态:

      UploadComplete
      InProgress
      JobComplete
      Failed
      Aborted
      
  3. 其他关键信息

    • object:查询的对象类型(如"Account")
    • createdDate:作业创建时间
    • concurrencyMode:并行模式(目前都是"Parallel")

/jobs/query/{id}/results Get 详细步骤解析

1. 请求地址(URI)

GET /services/data/vXX.X/jobs/query/{queryJobId}/results

前提条件

  • 查询作业必须处于 JobComplete 状态
  • 必须使用创建查询时相同的 API 版本

2. 关键参数

  • queryJobId(必需):查询作业的ID
  • locator(可选):用于分页的定位器字符串
  • maxRecords(可选):每次请求返回的最大记录数

3. 分页机制

  1. 首次请求:不使用 locator 参数,获取第一批结果
  2. 检查响应头:
  • Sforce-Locator:下一个结果集的定位器
  • Sforce-NumberOfRecords:当前批次返回的记录数 image.png
  1. 后续请求:如果 Sforce-Locator 的值不是 "null",则使用该值作为 locator 参数继续请求 image.png 循环直到完成:重复上述步骤,直到 Sforce-Locator 的值为 "null"

4. 响应格式

  • 默认为 CSV 格式
  • 必须设置 Accept: text/csv 请求头
  • 从 API 版本 50.0 开始,列的顺序与查询请求的顺序一致