Apex 大数据处理(4)数据删除

学习目标

完成本单元后,您将能够:

  • 在处理大量数据时,使用Salesforce批量API数据删除机制会对性能产生积极影响。
  • 从组织中抽取大量数据时,使用PK分块来对抗性能低下的问题。
  • 了解在自定义对象下截断记录以加快删除的好处。

使用批量API删除和提取

谈到您的Salesforce组织,数据管理始终处于优先级列表的首位。这部分管理包括删除和提取数据。而且,就像加载大量数据一样,批量API在删除或提取LDV时非常有用。当有一个过程涉及删除一百万或更多的记录时,批量API的硬删除选项可以做到这一点。

软与硬删除

Salesforce数据删除机制可能会对大数据量的性能产生深远的影响。 Salesforce将回收站用于用户删除的数据。通过回收站将其标记为已删除且可见,而不是删除数据。这个过程被称为软删除。当数据被软删除时,仍然会影响数据库的性能,因为它仍然存在于组织中,并且删除的记录必须从任何查询中排除。

数据保留在回收站中15天,或直到回收站增长到特定的大小。一旦达到时间或大小限制,或者使用UI,API或Apex清空回收站时,数据将从数据库中物理删除。

批量API支持硬删除(物理删除)选项,该选项允许记录绕过回收站并立即变为可用于删除。使用批量API的硬删除功能是推荐的删除大量数据卷的策略,以尽快释放空间并防止无关的材料影响性能。请注意,硬删除选项在默认情况下处于禁用状态,必须由管理员启用。

分块数据

使用批量API抽取数据时,默认情况下,查询会被分割为100,000个记录块 – 您可以使用chunkSize头域来配置较小的块,也可以使用大于250,000的较大的块。较大的块大小使用较少批量API批处理,但可能无法执行。您可能需要尝试一下才能确定最佳块大小。

在数量极高的情况下(数以亿计的记录),通过对字段值进行过滤来定义这些块可能并不实际。返回的行数可能会高于Salesforce查询优化器的选择性阈值。结果可能是全表扫描和性能下降,甚至失败。那么你需要采用不同的策略。

使用PK块

所以如果属性过滤不能帮助你将数据分成足够小的块,你可以做什么?使用PK Chunking处理超大型数据集提取。 PK代表主键 – 对象的记录ID–始终索引。 PK分块根据查询记录的记录ID将非常大的表上的批量查询拆分成块。

查询具有超过1000万条记录的表时,或批量查询始终超时时启用PK分块。 PK Chunking是Salesforce Bulk API的一项支持功能,因此它可以将查询拆分为可管理的块。只需在批量API作业中输入几个参数,平台就会自动将查询分成不同的块,对每个块执行查询并返回数据。

您可以使用大多数标准对象的PK块。它支持帐户,广告系列,CampaignMember,大小写,联系人,潜在客户,登录历史记录,机会,任务和用户以及所有自定义对象。要启用该功能,请在批量API查询的作业请求上指定标题Sforce-Enable-PKChunking。

要选择块大小,只需在标题中指定它。例如,此标题可以使用块大小为50,000的记录启用PK组块:Sforce-Enable-PKChunking:chunkSize = 50000。每个块都作为一个单独的批处理进行处理,并计入您的每日批处理限制,并且其结果必须单独下载。您可以在批量API查询中包含WHERE子句的同时使用PK块处理执行筛选。使用此方法,可能会有比chunkSize中指定的数量少的记录返回的记录。

注意

如果您查询的记录少于1000万,则可以通过将chunkSize设置为小于查询记录数的数字来练习PK分块。例如,Sforce-Enable-PKChunking:chunkSize = 1000。你会得到一个查询拆分成多个批次,并看到PK在行动。
查询成功分块时,原始批处理的状态显示为NOT_PROCESSED。如果分块失败,则原始批处理的状态显示为FAILED,但在分块尝试期间成功排队的所有分块批处理都将正常处理。当原始批次状态更改为NOT_PROCESSED时,监视后续批次。您可以在完成后从每个后续批次检索结果。那么你可以安全地关闭工作。

截断

如果要立即删除沙箱组织的自定义对象中的记录,可以尝试截断这些自定义对象。截断自定义对象是永久删除自定义对象中的所有记录的一种快速方法,同时保持对象及其元数据的完整性以供将来使用。

截断自定义对象将清除当前坐在自定义对象的回收站中的所有记录;自定义对象的历史;以及每个删除记录的相关事件,任务,注释和附件。

注意

截断自定义对象会导致截断对象及其记录的一些不可逆转的更改。他们不能回到原来的状态。

截断是有用的,例如,如果您创建了一个自定义对象并填充了测试记录。当您完成测试数据时,可以截断对象以清除测试记录,但保留该对象并将其投入生产。这比批量删除记录快得多,并且可能重新创建对象。

这是简单的设置过程:

  1. 首先,通过在快速查找框中输入User Interface,选择User Interface,然后选择权限,为您的组织启用截断。
  2. 接下来,转到自定义对象的对象管理设置。
  3. 单击对象名称以转到该对象的详细信息页面,然后 Truncate.
  4. 在“Confirm Custom Object Truncate”窗口中,查看警告,然后在空字段中输入要截断的对象的名称。
  5. 点击 Truncate.

截断之后必须使用擦除功能来释放存储空间。

截断自定义对象时,对象的所有记录都将永久删除,但对象的定义仍然存在。记录不再计入您的组织限制。相反,如果您删除自定义对象,对象将移动到回收站15天(如上所述)。之后,对象及其记录被永久删除。

不能截断由另一个对象通过查找字段引用的标准对象或自定义对象,或者在主 – 从关系的主方一侧引用的标准对象或自定义对象在报告快照中被引用,具有自定义索引或外部标识,或者激活了瘦子表。而且,当组织已经达到允许的自定义对象的限制时,不能截断自定义对象。

使用诸如截断之类的策略,以及PK分块和批量API的硬删除,可以帮助您防止大量数据卷毁你的组织。定期和根据需要采用这些方法是保持稳健性能的明智做法。

Apex 大数据处理(3)加载数据

学习目标

完成本单元后,您将能够:

  • 描述Salesforce中精益数据加载的好处。
  • 加载大量数据时,了解批量API优于SOAP API的优点。
  • 通过暂停数据验证和浓缩操作加快加载大型数据集的过程。

加载精益

无论我们正在谈论LDV迁移还是正在进行的大数据同步操作,将这些操作对业务关键型操作的影响降至最低是最佳做法。实现这一目标的一个明智的策略是加载精简 – 仅包括满足业务关键操作所需的数据和配置。

加载精益需要什么?

  • 在将用户移至Salesforce之前识别业务关键型操作。
  • 确定实现这些操作所需的最小数据集和配置。
  • 根据您确定的要求定义数据和配置策略。
  • 尽可能快地加载数据以减少同步的范围。

    在决定数据加载和配置策略时,请考虑这些设置选项,这些选项使您能够推迟非关键进程并加快LDV加载速度。

全组织共享默认值. 当您使用私人共享模式加载数据时,系统会在记录添加时计算共享。如果使用公共读/写共享模式加载,则可以将该处理推迟到切换之后。

复杂的对象关系. 您在对象上定义的查找次数越多,数据加载期间系统执行的检查就越多。但是,如果你能够在后期阶段建立这些关系,那么加载速度会更快。

共享规则. 如果在加载数据之前配置了基于所有权的共享规则,则如果记录的所有者属于定义要共享的数据的角色或组,则您插入的每条记录都需要共享计算。如果您在加载数据之前配置了基于条件的共享规则,则每个记录的字段与规则选择条件相匹配也需要共享计算。

工作流规则,验证规则和触发器. 这些功能强大的工具可以确保在日常操作中输入的数据是干净的,并在记录之间包含适当的关系但是,如果在海量数据加载期间启用它们,它们也可能会减慢处理速度。

但不是太瘦

他们说你不能太富有或太瘦。但是当涉及到数据加载时,你肯定可能太瘦了。虽然消除更快数据加载的障碍是明智之举,但要记住,在数据加载过程中,少量配置是必不可少的(或者至少是高度期望的),而且不应该混淆:

  • 与主 – 子细节的父记录. 如果父母不存在,您将无法加载子记录。
  • 记录所有者. 在大多数情况下,您的记录将由个人用户拥有,业主需要存在于系统中才能加载数据。
  • 角色层次结构. 如果记录的所有者不是角色层次结构的成员,则可能认为加载速度会更快。但几乎在所有情况下,性能都是一样的,如果您加载门户帐户,速度会更快。所以推迟这个配置方面没有任何好处。

批量API与SOAP API数据加载

当您加载LDV时,您选择的API会有所不同。标准Force.com SOAP API针对一次更新一些记录的实时客户端应用程序进行了优化。 SOAP API要求开发人员和管理员实现复杂的流程,以小尺寸的块来上传数据,监视结果并重试失败的记录。这种方法对于小数据负载是可以接受的,但是对于大数据集却变得笨重和耗时。

另一方面,批量API旨在简化从数千到数百万条记录的数据处理过程。批量API基于REST原则,专门为简化和优化加载或删除大型数据集的过程而开发。

使用批量API进行LDV可以实现超快的处理速度,同时减少客户端编程语言,易于监控的作业状态,失败记录的自动重试,并行处理支持,Force.com的最小往返次数,最小化API调用,有限的丢弃连接,以及易于调整的批量大小。简而言之,这是插入,查询和删除记录的最快方法。

批量API的工作原理

当您使用批量API上传记录时,这些记录将流式传输到Force.com以创建新作业。随着数据卷入作业,它被存储在临时存储器中,然后被分割成用户定义的批次(最多10,000条记录)。即使您的数据仍然被发送到服务器,Force.com平台也会提交批处理进行处理。

批次可以根据您的需要并行或串行处理。批量API将功能从您的客户端应用程序移动到服务器。 API记录每个作业的状态,并尝试自动为您重新处理失败的记录。如果作业超时,批量API会自动将其重新放入队列中,并为您重新尝试。

每个批次都是独立处理的,一旦批次完成(成功与否),作业将更新结果。具有适当访问权限的任何人都可以通过Salesforce.com管理界面对作业进行监控和管理。

通过暂停事件来提高速度

当您需要快速加载LDV时,务必确保每个插入程序尽可能高效。通过正确的准备和后期处理,您可以在加载时禁用数据验证和增强操作,而不会影响您的数据完整性或业务规则。

Force.com平台包含强大的工具,可确保用户输入的数据清晰,并在记录之间包含适当的关系。验证规则确保数据用户输入的新记录和现有记录符合您业务指定的标准。通过工作流程规则,您可以自动执行现场更新,电子邮件警报,出站邮件以及与工作流程,审批和里程碑关联的任务。触发器允许您在记录插入操作数据和执行其他操作。

虽然这些工具允许您在正常操作期间保持数据完整性,但是如果在海量数据加载期间启用这些工具,还可能导致插入操作变慢。但是,如果关闭验证,工作流程和触发器,那么如何确保一旦完成加载,就可以获得准确的数据,并在对象之间建立正确的关系?这个工作有三个关键阶段 – 分析和准备数据,禁止加载事件和后期处理。

分析和准备数据

要在没有触发器,验证规则和工作流规则运行的情况下安全地加载,请检查您通常可以通过这些操作满足的业务需求,然后回答几个问题。

首先,您可以在数据加载之前通过数据清理来满足您的哪些要求,或者在对象之间存在关键依赖关系的情况下对负载操作进行排序?例如,如果通常使用验证规则来确保用户条目在有效范围内,则可以在加载之前查询数据集以查找和修复不符合规则的记录。

其次,您可以在数据加载之后通过后处理记录满足哪些要求?这里一个典型的用例集涉及到数据丰富 – 可能涉及添加对象之间的查找关系,将汇总字段汇总到父记录以及记录之间的其他数据关系。

禁用加载事件

一旦分析了所有数据验证和充实要求,并计划在数据加载之前或之后对其进行管理的操作,可以临时禁用规则和触发器以加快加载速度。只需编辑每个规则并将其设置为“无效”状态即可。您可以以相同的方式禁用验证,潜在客户和案例分配规则以及区域分配规则。

暂时禁用触发器有点复杂,需要做一些准备。首先,创建一个自定义设置和相应的复选框字段来控制何时触发一个触发器。然后在您的触发器代码中包含一个语句,就像本例中突出显示的那样。

一旦完成,禁用或启用触发器就像编辑复选框字段一样简单。

后期处理

当您完成加载数据时,是时候完成您推迟的数据丰富和配置任务,直到这一点:

  • 添加对象之间的查找关系,将汇总字段汇总到父记录以及使用批量Apex或批量API记录之间的其他数据关系。
  • 使用外键或其他数据增强Salesforce中的记录,以利用批量Apex或批量API与其他系统集成。
  • 重置您为触发器创建的自定义设置上的字段,以便在记录创建和更新时适当触发。
  • 重新打开验证,工作流程和分配规则,以便在用户输入和编辑记录时触发相应的操作。

所以你有它:通过加载精益,使用批量API和暂停事件,您可以确保您的数据加载是有效的,尽可能快,并保持其完整性。现在,我们已经加载了数据,移动到下一个单元,我们覆盖删除和提取。

Apex 大数据处理(3)加载数据

学习目标

完成本单元后,您将能够:

  • 描述Salesforce中精益数据加载的好处。
  • 加载大量数据时,了解批量API优于SOAP API的优点。
  • 通过暂停数据验证和浓缩操作加快加载大型数据集的过程。

加载精益

无论我们正在谈论LDV迁移还是正在进行的大数据同步操作,将这些操作对业务关键型操作的影响降至最低是最佳做法。实现这一目标的一个明智的策略是加载精简 – 仅包括满足业务关键操作所需的数据和配置。

加载精益需要什么?

  • 在将用户移至Salesforce之前识别业务关键型操作。
  • 确定实现这些操作所需的最小数据集和配置。
  • 根据您确定的要求定义数据和配置策略。
  • 尽可能快地加载数据以减少同步的范围。

    在决定数据加载和配置策略时,请考虑这些设置选项,这些选项使您能够推迟非关键进程并加快LDV加载速度。

全组织共享默认值. 当您使用私人共享模式加载数据时,系统会在记录添加时计算共享。如果使用公共读/写共享模式加载,则可以将该处理推迟到切换之后。

复杂的对象关系. 您在对象上定义的查找次数越多,数据加载期间系统执行的检查就越多。但是,如果你能够在后期阶段建立这些关系,那么加载速度会更快。

共享规则. 如果在加载数据之前配置了基于所有权的共享规则,则如果记录的所有者属于定义要共享的数据的角色或组,则您插入的每条记录都需要共享计算。如果您在加载数据之前配置了基于条件的共享规则,则每个记录的字段与规则选择条件相匹配也需要共享计算。

工作流规则,验证规则和触发器. 这些功能强大的工具可以确保在日常操作中输入的数据是干净的,并在记录之间包含适当的关系但是,如果在海量数据加载期间启用它们,它们也可能会减慢处理速度。

但不是太瘦

他们说你不能太富有或太瘦。但是当涉及到数据加载时,你肯定可能太瘦了。虽然消除更快数据加载的障碍是明智之举,但要记住,在数据加载过程中,少量配置是必不可少的(或者至少是高度期望的),而且不应该混淆:

  • 与主 – 子细节的父记录. 如果父母不存在,您将无法加载子记录。
  • 记录所有者. 在大多数情况下,您的记录将由个人用户拥有,业主需要存在于系统中才能加载数据。
  • 角色层次结构. 如果记录的所有者不是角色层次结构的成员,则可能认为加载速度会更快。但几乎在所有情况下,性能都是一样的,如果您加载门户帐户,速度会更快。所以推迟这个配置方面没有任何好处。

批量API与SOAP API数据加载

当您加载LDV时,您选择的API会有所不同。标准Force.com SOAP API针对一次更新一些记录的实时客户端应用程序进行了优化。 SOAP API要求开发人员和管理员实现复杂的流程,以小尺寸的块来上传数据,监视结果并重试失败的记录。这种方法对于小数据负载是可以接受的,但是对于大数据集却变得笨重和耗时。

另一方面,批量API旨在简化从数千到数百万条记录的数据处理过程。批量API基于REST原则,专门为简化和优化加载或删除大型数据集的过程而开发。

使用批量API进行LDV可以实现超快的处理速度,同时减少客户端编程语言,易于监控的作业状态,失败记录的自动重试,并行处理支持,Force.com的最小往返次数,最小化API调用,有限的丢弃连接,以及易于调整的批量大小。简而言之,这是插入,查询和删除记录的最快方法。

批量API的工作原理

当您使用批量API上传记录时,这些记录将流式传输到Force.com以创建新作业。随着数据卷入作业,它被存储在临时存储器中,然后被分割成用户定义的批次(最多10,000条记录)。即使您的数据仍然被发送到服务器,Force.com平台也会提交批处理进行处理。

批次可以根据您的需要并行或串行处理。批量API将功能从您的客户端应用程序移动到服务器。 API记录每个作业的状态,并尝试自动为您重新处理失败的记录。如果作业超时,批量API会自动将其重新放入队列中,并为您重新尝试。

每个批次都是独立处理的,一旦批次完成(成功与否),作业将更新结果。具有适当访问权限的任何人都可以通过Salesforce.com管理界面对作业进行监控和管理。

通过暂停事件来提高速度

当您需要快速加载LDV时,务必确保每个插入程序尽可能高效。通过正确的准备和后期处理,您可以在加载时禁用数据验证和增强操作,而不会影响您的数据完整性或业务规则。

Force.com平台包含强大的工具,可确保用户输入的数据清晰,并在记录之间包含适当的关系。验证规则确保数据用户输入的新记录和现有记录符合您业务指定的标准。通过工作流程规则,您可以自动执行现场更新,电子邮件警报,出站邮件以及与工作流程,审批和里程碑关联的任务。触发器允许您在记录插入操作数据和执行其他操作。

虽然这些工具允许您在正常操作期间保持数据完整性,但是如果在海量数据加载期间启用这些工具,还可能导致插入操作变慢。但是,如果关闭验证,工作流程和触发器,那么如何确保一旦完成加载,就可以获得准确的数据,并在对象之间建立正确的关系?这个工作有三个关键阶段 – 分析和准备数据,禁止加载事件和后期处理。

分析和准备数据

要在没有触发器,验证规则和工作流规则运行的情况下安全地加载,请检查您通常可以通过这些操作满足的业务需求,然后回答几个问题。

首先,您可以在数据加载之前通过数据清理来满足您的哪些要求,或者在对象之间存在关键依赖关系的情况下对负载操作进行排序?例如,如果通常使用验证规则来确保用户条目在有效范围内,则可以在加载之前查询数据集以查找和修复不符合规则的记录。

其次,您可以在数据加载之后通过后处理记录满足哪些要求?这里一个典型的用例集涉及到数据丰富 – 可能涉及添加对象之间的查找关系,将汇总字段汇总到父记录以及记录之间的其他数据关系。

禁用加载事件

一旦分析了所有数据验证和充实要求,并计划在数据加载之前或之后对其进行管理的操作,可以临时禁用规则和触发器以加快加载速度。只需编辑每个规则并将其设置为“无效”状态即可。您可以以相同的方式禁用验证,潜在客户和案例分配规则以及区域分配规则。

暂时禁用触发器有点复杂,需要做一些准备。首先,创建一个自定义设置和相应的复选框字段来控制何时触发一个触发器。然后在您的触发器代码中包含一个语句,就像本例中突出显示的那样。

一旦完成,禁用或启用触发器就像编辑复选框字段一样简单。

后期处理

当您完成加载数据时,是时候完成您推迟的数据丰富和配置任务,直到这一点:

  • 添加对象之间的查找关系,将汇总字段汇总到父记录以及使用批量Apex或批量API记录之间的其他数据关系。
  • 使用外键或其他数据增强Salesforce中的记录,以利用批量Apex或批量API与其他系统集成。
  • 重置您为触发器创建的自定义设置上的字段,以便在记录创建和更新时适当触发。
  • 重新打开验证,工作流程和分配规则,以便在用户输入和编辑记录时触发相应的操作。

所以你有它:通过加载精益,使用批量API和暂停事件,您可以确保您的数据加载是有效的,尽可能快,并保持其完整性。现在,我们已经加载了数据,移动到下一个单元,我们覆盖删除和提取。

Apex 大数据处理(2)查询

学习目标

完成本单元后,您将能够:

  • 在处理大量数据时使用查询而不降低性能。
  • 使用批量查询有效地查询大型数据集。
  • 描述使用瘦表来包含经常使用的字段的好处。

搜索架构

将大量数据存储在您的组织中可能会影响性能,而且肯定包含搜索。搜索是基于自由格式文本查询记录的功能。 Salesforce搜索体系结构基于其自己的数据存储库,该数据存储库已针对搜索该文本进行了优化。

对于要搜索的数据,必须先对其进行索引。 Force.com会自动索引大多数文本字段,以便您的用户可以构建跨对象搜索并快速查找包含感兴趣的字符串的记录。索引搜索是通过首先在索引中搜索适当的记录,然后根据访问权限,搜索限制和其他过滤器来缩小结果。

这创建了一个结果集,通常包含最相关的结果。在结果集达到预定大小后,剩余的记录被丢弃。然后使用结果集来查询数据库中的记录以检索用户看到的字段。而当大量数据被添加或更改时,整个过程可能需要很长时间。

使用查询

考虑这种情况:你有一个很好的瘦对象集。所有用于集成和自定义Visualforce页面的代码都已经编写好,并且可以与测试数据一起使用。随着客户开始使用该系统,一切都很顺利。但是当组织加载或积累大量数据时,性能开始严重下降。

解决方案:查询建立。这是设计一个可以处理LDV的组织的关键。设计选择性列表视图,报告和SOQL查询以及理解查询优化是非常重要的。

SOQL与SOSL查询

搜索可以通过SOQL或SOSL查询来访问。 SOQL是Force.com的数据库查询语言,类似于SQL。您可以使用SOQL来查询通常是多对一的子对父关系,并查询几乎总是一对多的父对子关系。

SOSL是Force.com的全文搜索语言。 SOSL可以标记一个字段中的多个术语,并可以建立一个搜索索引。如果你正在寻找一个你知道存在于一个字段中的特殊的术语,你可能会发现SOSL比SOQL更快。但是,对于每个Apex交易,SOSL查询的州长限制是2000; SOQL查询是5万。所以如果你需要检索超过2000条记录,SOQL是更好的选择。

Force.com查询优化器

由于Salesforce使用多租户架构,因此数据库系统的优化程序无法独立有效地优化Salesforce查询。因此,Salesforce平台包含自己的查询优化程序,该查询优化程序利用索引字段为给定查询创建最有效的执行计划,从而帮助数据库系统的优化程序为Salesforce查询生成有效的执行计划。

Force.com查询优化器维护一个关于每个索引中数据分布的统计表。它使用此表执行预查询以确定使用索引是否可以加快查询速度。它适用于自动生成的查询,以处理报表,列表视图以及SOQL查询和其他背负的查询。

批量Apex

一般来说,在Force.com平台上查询和处理大型数据集的最好方法就是批量异步执行。您可以使用Batch Apex查询和处理多达5000万条记录。

Batch Apex不能在所有使用情况下工作(例如,如果您需要同步使用,就像需要查询超过50,000条记录的Visualforce页面一样),但它是您的工具箱中的一个很好的工具。

批量查询

高效查询大型数据集的另一个策略是使用批量查询。批量查询最多可以检索15 GB的数据,分为15个1 GB的文件。

批量API查询支持query和queryAll操作。 queryAll操作返回由于合并或删除而被删除的记录。 queryAll操作也返回关于存档的任务和事件记录的信息。

将批处理添加到批量查​​询作业时,请求标头中的Content-Type必须为text / csv,application / xml或application / json,具体取决于作业创建时指定的内容类型。为批处理提供的实际SOQL语句是纯文本格式。

如何处理批量查询

处理批量查询时,Salesforce将尝试执行查询。如果查询未在标准的两分钟超时限制内执行,则作业将失败,并返回QUERY_TIMEOUT错误。如果发生这种情况,请重写更简单的查询并重新提交批处理。

如果查询成功,Salesforce将尝试检索结果。如果结果超过1 GB的文件大小限制,或者需要超过10分钟的时间才能检索,则完成的结果将被缓存,然后再进行一次尝试。尝试15次后,作业失败,返回超过15次的错误消息。如果发生这种情况,请考虑使用PK Chunking标头将查询结果拆分为更小的块。 (更多关于PK在后续单元中的组块。)如果尝试成功,结果将返回并存储七天。

使用瘦表

假设您已遵循编码最佳实践,并与Salesforce客户支持部门合作,在适当的地方放置自定义索引,但您仍然遇到性能问题。用户抱怨他们的报告和仪表板超时,而从Visualforce页面调用的SOQL表现得越来越慢。如果您迫切需要进一步提高性能,那么有一个特别的,功能强大的解决方案:瘦表。

瘦表是Force.com平台中的自定义表,它包含标准或自定义基本Salesforce对象的字段的子集。如果需要的话,Force.com可以有多个小表,并维护它们,并保持透明。

通过使用较小的行和较少的数据来扫描基本的Salesforce对象,skinny表允许Force.com在每次数据库读取时返回更多的行,从一个大对象读取时增加吞吐量,如下图所示:

Skinny Tables graphic.png

此外,紧缩表不包含软删除的行(即回收站中的记录为isDeleted = true),这往往会减少表的体积。基表上的自定义索引也会被复制,并且通常会因为底层数据库查询中发生的表连接减少而更好地执行。

下面是一个简单的表格如何加快查询的例子。而不是使用01/01/16到12/31/16这样的日期范围 – 这需要花费昂贵的重复计算来创建年度或年度至今的报告 – 您可以使用瘦表来包括年份字段和在年= 2016年过滤。

Force.com平台自动同步基础对象和瘦客户端表之间的行,所以数据始终保持最新。 Force.com平台在查询运行时确定何时使用瘦表是有意义的,因此您不必修改报告或开发任何Apex代码或API调用。

瘦表对于包含数百万条记录的表是最有用的。它们可以在自定义对象上创建,也可以在Account,Contact,Opportunity,Lead和Case对象上创建。他们可以提高报告,列表视图和SOQL的性能。

注意

要启用瘦客户端表,请联系Salesforce客户支持。

瘦表可以是一个方便的方法来解决性能问题。但是,与使用高效索引从基本Salesforce对象读取相比,它们可能无法适应所有用例,或者提高性能。他们带有你应该理解的副作用,因为他们可能会限制或负担你的业务流程。

在实现瘦表之前,需要考虑以下几点:

瘦的表是瘦的. 为了确保最佳性能,它们只包含满足特定业务用例所需的最小字段集合。如果以后决定向报表或SOQL查询添加字段,则必须联系Salesforce客户支持以重新创建表。

细小的表格不会被复制到沙箱组织中. 此限制可能不是您的问题,但要保持生产环境和沙箱环境的一致性,您必须跟踪更改并与Salesforce客户支持部门协作,以保持环境同步。

紧缩表是基础Force.com数据库中的自定义表. 它们没有在基础对象中找到的动态元数据灵活性。如果更改字段类型(例如,将数字字段更改为文本字段),那么瘦客户表变得无效,并且您必须联系Salesforce客户支持以创建新的瘦客户表。

现在您已经有几个工具可以加快涉及大数据量的搜索,请继续下一个单元以减少数据加载。

Apex 大数据处理(1)数据模型

学习目标

完成本单元后,您将能够:

  • 为大数据量设计一个数据模型。
  • 描述三种类型的数据倾斜以及如何避免它们。
  • 数据模型以包含外部对象。

规划你的数据模型

数据是任何应用程序的关键元素之一。用户不断创建数据。日积月累。突然间,您的组织已经累积了数百万条记录,数千个用户和数千兆字节的数据存储。

这些大数据量(LDV)可能导致性能下降,包括查询速度较慢,搜索和列表视图较慢以及沙箱刷新速度较慢。如果您计划先行调整LDV,则可以避免这种困境,从一开始就设计您的数据模型以构建可扩展性。

数据倾斜的独家新闻

管理大数据量以获得最佳性能的关键在于仔细设计记录所有权以避免数据倾斜。如果超过10,000个子记录与组织内的同一父记录相关联,则会发生数据倾斜。

使用足够的客户规划数据模型,以将每个父级的子级记录数保持在此阈值以下,并在创建这些客户时分配新的子级记录。如果您不使用这些策略,则会出现三种类型的数据倾斜,并会对性能产生负面影响:客户数据倾斜,所有人倾斜和查找倾斜。

客户数据偏差

某些Salesforce对象(如客户和机会)具有特殊的数据关系,可以在私有共享模型下维护父子记录访问。在这些关系之一中与同一父对象关联的子记录太多会导致客户数据倾斜。假设您有一堆未分配的联系人,并将其放在名为“未分配”的一个客户下。这可能会造成记录锁定和共享性能方面的问题。

记录锁定

以下是另一种情况:您正在多个线程中更新同一客户下的大量联系人。对于每次更新,系统都锁定要更改的联系人及其父客户,以保持数据库中的完整性。即使每个锁都保持很短的时间,因为所有的更新都试图锁定同一个客户,所以更新失败的风险很高,因为前一个锁仍然持有该客户的锁。

共享问题

谈到共享,也有类似的动态。根据您配置的共享方式,当您做一些看起来很简单的事情时,比如更改客户的所有者,您可能需要检查每个客户的子记录并调整其共享。这可能包括重新计算角色层次和共享规则。如果我们谈论成千上万的子记录,可能会吃掉很多时间。

所有权倾斜

当具有相同对象类型的大量记录属于单个用户时,这种不平衡会导致所有权倾斜。由于每个记录都需要拥有一个所有者,所以似乎自然的解决办法是将这些记录倾斜到一个通用所有者上,例如前面提到的“未分配”。但是这可能会导致性能问题,因为共享计算需要管理这些记录的可见性。

当角色层次结构中存在倾斜所有者时,像删除或所有者更新这样的操作必须从角色层次结构中的旧所有者和所有父用户以及共享规则访问的所有用户中移除共享。这就是为什么所有权变更往往是系统中成本最高的交易变更之一。

在某些情况下,所有权倾斜根本无法避免。在这些情况下,最好确保倾斜的所有者没有角色。这样,您就可以将用户及其记录从角色层次结构及其关联的共享规则中分离出来。

查找倾斜

当大量记录与查找对象(您正在搜索的对象)中的单个记录相关联时,会发生查找倾斜。因为您可以将查找字段放在Salesforce中的任何对象上,所以查找偏斜可能会为组织中的任何对象创建问题。

如果最终发现查询偏斜并且具有非常复杂的自定义实现,那么您可能会在没有意识到的情况下创建问题。通过仔细考虑管理查找倾斜的选项,您可以避免锁定查找字段的问题,以确保您的架构可以扩展以满足您的组织成长。

是什么让查找偏斜如此糟糕? Salesforce中的查找字段实质上是对象之间的外键关系。每次插入或更新记录时,Salesforce都必须锁定为每个查找字段选择的目标记录。这确保了当数据被提交到数据库时,其完整性得以保持。

在正常情况下,保存操作执行得如此之快以至于您不会遇到锁定。但是,当您在自动化进程中同时添加自定义代码和LDV时,您可能会遇到锁定异常,当您尝试插入或更新记录时会导致失败。

由于没有任何专门用于识别查找偏斜的工具,查找这些架构问题可能就像在大海捞针一样。请注意,在某些使用模式下,查找偏移可能根本不会导致任何问题,因此最好根据会导致问题的模式进行搜索。您应该评估具有大量记录的对象以及大量的并发插入和更新活动。

使用外部对象

LDV的另一个策略是使用外部对象 – 这意味着不需要将数据带入Salesforce。通过数据分层策略,将数据分散到多个对象中,并根据需要从另一个对象或外部存储中提取数据,避免在组织中存储大量数据,并避免与LDV相关的性能问题。

外部对象与自定义对象类似,只不过它们映射到存储在Salesforce组织外部的数据,使用户和Force.com平台可以搜索外部数据并与之交互。

通过按需访问记录数据,外部对象总是反映外部数据的当前状态。您不必在Salesforce中管理该数据的副本,因此您不会浪费存储和资源来保持数据同步。如果您有大量数据无法或不想存储在Salesforce组织中,则最好使用外部对象,并且您只需要在任何时候使用少量的数据。

外部数据源指定如何访问外部系统。 Salesforce Connect使用外部数据源来访问存储在Salesforce组织外部的数据。 Files Connect使用外部数据源访问第三方内容系统。外部数据源具有关联的外部对象,您的用户和Force.com平台用于与外部数据和内容进行交互。

外部对象查找

外部对象支持标准的查找关系,它使用18个字符的Salesforce记录标识将相关记录相互关联。但是,存储在Salesforce组织外部的数据通常不包含这些记录标识。因此,外部对象有两种特殊类型的查找关系:外部查找和间接查找。

这些外部查找和间接查找将父对象上的特定字段的值与子对象上的关系字段的值进行比较。当值匹配时,记录是相互关联的。

父级是外部对象时使用外部查找关系。外部查找关系将子标准,自定义或外部对象链接到父级外部对象。父外部对象上的标准外部标识字段的值与外部查找关系字段的值相匹配。对于子外部对象,外部查找关系字段的值来自指定的外部列名称。

外部数据不包括Salesforce记录标识时,请使用间接查找关系。间接查找关系将子外部对象链接到父标准或自定义对象。在外部对象上创建间接查找关系字段时,指定父对象字段和子对象字段以相互匹配,在父对象上选择一个自定义的唯一外部ID字段以匹配子对象的间接查找关系字段,其值由指定的外部列名决定。

以下是可用于外部对象的关系类型的细分:

关系 允许的子对象 允许的父对象 父字段匹配记录
Lookup 标准
自定义
外部
标准
自定义
18个字符的Salesforce记录标识
外部查询 标准
自定义
外部
外部 外部ID标准字段
间接查询 外部 标准
自定义
您选择具有外部ID和唯一属性的自定义字段

现在,当您为大数据量构建组织架构时,您应该牢记(避免)关键事项。 您可能还需要聘请Salesforce Strategic Services的架构师来帮助您设计管理初始配置和增长的最佳方法。 在下一个单元中,我们将LDV查询和搜索放入混合中。

Apex-事件驱动(3)

学习目标

完成本单元后,您将能够:

  • 描述如何订阅平台事件消息。
  • 使用Apex触发器订阅事件。
  • 用Apex测试方法测试平台事件。
  • 通过CometD订阅平台事件。

订阅平台事件

现在您已经看到了如何发布平台事件,您如何订阅他们以获得最新消息或发货的通知?在Salesforce平台上,Apex触发器,流程和流程接收事件通知。 Visualforce和Lightning组件应用程序通过CometD接收事件。在外部应用程序中,您也可以使用CometD订阅事件。

使用Apex触发器订阅平台事件通知

您可能以前使用过Apex触发器,以基于数据库事件执行操作。通过平台事件,过程是相似的。您只需在事件对象上插入一个插入Apex触发器来订阅传入事件即可。触发器在Apex中提供自动订阅机制。不需要明确创建和收听频道。触发器接收来自各种来源的事件通知,不管它们是通过Apex还是API发布的。

平台事件仅在插入触发器后才支持。后插入触发器事件对应于发布平台事件之后的时间。事件消息发布后,触发后插入触发器。

要创建平台事件触发器,请使用开发者控制台。

  1. 单击设置图标,选择 Developer Console, 然后单击 File | New | Apex Trigger.
  2. 提供一个名称并为sObject选择事件,然后单击 Submit.

开发者控制台会自动在触发器模板中添加after插入事件。另外,您可以方便地从“触发器”相关列表中的“设置”中的事件定义页面创建触发器,但是必须指定after insert关键字。

以下示例显示了Cloud News事件的触发器。它遍历每个事件并通过Urgent__c字段检查消息是否紧急。如果消息紧急,则触发器创建一个派发新闻记者的案例,并将事件位置添加到案例主题。

// 触发Cloud_News事件。
trigger CloudNewsTrigger on Cloud_News__e (after insert) {    
    // 列举所有要创建的案例。
    List<Case> cases = new List<Case>();
    
    // 获取案例所有者的队列ID
    Group queue = [SELECT Id FROM Group WHERE Name='Regional Dispatch' LIMIT 1];
       
    // 遍历每个通知
    for (Cloud_News__e event : Trigger.New) {
        if (event.Urgent__c == true) {
            // Create Case to dispatch new team.
            Case cs = new Case();
            cs.Priority = 'High';
            cs.Subject = 'News team dispatch to ' + 
                event.Location__c;
            cs.OwnerId = queue.Id;
            cases.add(cs);
        }
   }
    
    // 插入与收到的事件相对应的所有案例。
    insert cases;
}
设置调试日志记录

与标准或自定义对象上的触发器不同,平台事件上的触发器不会在与发布事件相同的Apex事务中执行。触发器在系统用户Automated Process实体下的自己的进程中运行。因此,与触发器执行相对应的调试日志由Automated Process实体创建,并且在Developer Console中不可用。要收集平台事件触发器日志,请在“安装”中为“自动过程”实体添加跟踪标志条目。

  1. 在安装程序中,在快速查找框中输入调试日志,然后单击 Debug Logs.
  2. 点击 New.
  3. 对于跟踪的实体类型,请选择 Automated Process.
  4. 选择您要收集的日志的开始日期和到期日期。
  5. 对于调试级别,输入*然后单击 Search.
  6. 选择一个预定义的调试级别,例如SFDC_DevConsole或单击New来创建您自己的调试级别。
  7. 点击 Save.

注意

Apex测试的调试日志是一个例外。它们包括在同一个测试执行日志中记录事件触发器。

有关平台事件触发器的注意事项

事件处理的顺序
触发器按收到的顺序处理平台事件通知。事件的顺序基于事件重播ID。 Apex触发器可以一次接收一批事件。事件的顺序保存在每个批次中。批处理中的事件可以来自一个或多个发布者。
异步触发器执行
平台事件触发器异步运行在其自己的进程中,不是发布事件的事务的一部分。因此,事件发布时间和触发器处理事件之间可能存在延迟。不要期望触发器执行的结果在事件发布之后立即可用。
自动化的过程系统用户
由于平台事件触发器不会在执行它们的用户(正在运行的用户)下运行,而是在Automated Process系统用户下运行,所以我们在CloudNewsTrigger示例中明确地设置了所有者ID字段。我们使用了一个称为Regional Dispatch的示例用户队列的ID作为触发器示例。如果您在触发器(例如案例或商机)中创建带有OwnerId字段的Salesforce记录,请明确设置所有者ID。对于案例和潜在客户,您可以使用分配规则来设置所有者。
此外,系统字段(例如CreatedById和LastModifiedById)引用自动处理实体,而不是正在运行的用户。
Apex Governor 限制
与标准或自定义对象触发器一样,平台事件触发器也受到Apex控制器限制。
Apex Trigger 限制
平台事件触发器共享许多自定义和标准对象触发器的相同限制。例如,您不能从触发器中同步创建Apex标注。

订阅事件定义页面上的相关列表

您可以在安装程序的“平台事件定义详细信息”页面上查看所有事件触发器的状态。 CometD用户不在此列表中。在订阅下,每个激活的触发器都与执行信息和状态一起列出。信息包括上次发布和上次处理事件的重播ID。由于错误不可恢复或权限不足,状态会指示触发器是否正在运行或已与订阅断开连接。仅当触发器重试次数达到最大次数时,才会达到错误状态。以下屏幕截图显示了“云新闻”事件详细信息页面上的“订阅”相关列表。

Subscriptions related list shows the state of subscribed triggers

测试平台事件触发器

通过添加Apex测试,确保您的平台事件触发器正常工作。在将任何Apex代码(包括触发器)打包或部署到生产之前,您的Apex代码必须进行测试。要在Apex测试中发布平台事件,请将发布语句放在Test.startTest和Test.stopTest语句中。

// 创建测试事件
Test.startTest();
// 发布事件
Test.stopTest();
// 在这里执行验证
在测试上下文中,发布方法调用将发布操作排队。 Test.stopTest()语句导致事件发布被执行。 Test.stopTest()后,执行您的验证。

以下是我们的Cloud_News事件及其相关触发器的测试类示例。发布事件会导致关联的触发器触发。在Test.stopTest()之后,测试通过检查Database.SaveResult中的isSuccess()返回的值来验证发布是否成功。另外,测试查询触发器创建的情况。如果找到案例记录,则触发器成功执行,并通过测试。

@isTest
public class PlatformEventTest {
    @isTest static void test1() {
        // 创建测试事件实例
        Cloud_News__e newsEvent = new Cloud_News__e(
            Location__c='Mountain City', 
            Urgent__c=true, 
            News_Content__c='Test message.');
        
        Test.startTest();

        // 调用方法来发布事件
        Database.SaveResult sr = EventBus.publish(newsEvent);
        
        Test.stopTest();
        
        // 在这里执行验证

        // 验证发布是否成功
        System.assertEquals(true, sr.isSuccess());

        // 检查创建的触发器是否存在。
        List<Case> cases = [SELECT Id FROM Case];
        // 验证是否发现此案例。
        // 在测试上下文中只有一个测试用例。
        System.assertEquals(1, cases.size());
    }
}

使用点击订阅平台事件通知

要订阅没有代码的事件消息,请创建一个在发生平台事件时启动的进程。

此屏幕截图显示了一个进程在发生Cloud News事件时开始。当它开始时,该过程查找邮件城市匹配事件通知位置的联系人记录。

Process Builder matching criteria screen

同样,您可以通过使用Wait元素来订阅具有流程的平台事件消息。当发生平台事件时,不是启动流程,而是先前启动的流程等待平台事件,然后恢复。例如,以下是等待Cloud News事件消息发生的Wait元素。只有当事件的位置匹配{!MailingCity_Location.MailingCity}时才会继续。 {!MailingCity_Location}是流中的一个sObject变量。

Cloud Flow Designer Wait element

使用CometD订阅平台事件通知

外部应用程序使用CometD订阅平台事件并执行长时间轮询。平台应用程序(如Visualforce页面和Lightning组件)也可以使用CometD。 CometD是一个可扩展的基于HTTP的事件路由总线,它使用了一种名为Comet的AJAX推送技术模式。它实现了Bayeux协议。长轮询(也称为Comet编程)允许模拟从服务器到客户端的信息推送。与普通轮询类似,客户端连接并请求来自服务器的信息。但是,如果信息不可用,服务器不会发送空的响应,而是等待信息可用(发生事件)。

Salesforce提供了一个Java库EMP连接器,该连接器实现了连接到CometD和监听通道的所有细节。您可以使用EMP Connector轻松订阅平台事件。 EMP连接器隐藏了订阅事件的复杂性。有关EMP Connector的更多信息,请查看Streaming API开发人员指南中的Java客户端示例。

通过CometD订阅平台事件通知的过程与订阅PushTopic事件或通用事件类似。唯一的区别是频道名称。以下是平台事件主题(频道)名称的格式:

/event/<EventName>__e
例如,如果您有名为“云新闻”的平台事件,请在订阅时提供此频道名称。
/event/Cloud_News__e
在CometD URL末尾指定API版本,如下所示。
// 连接到CometD端点
    cometd.configure({
               url: 'https://<Salesforce_URL>/cometd/41.0/',
               requestHeaders: { Authorization: 'OAuth <Session_ID>'}
    });

JSON格式的平台事件消息

交付平台事件的消息与Cloud News事件的以下示例类似。

{
  "data": {
    "schema": "_2DBiqh-utQNAjUH78FdbQ", 
    "payload": {
      "CreatedDate": "2017-04-27T16:50:40Z", 
      "CreatedById": "005D0000001cSZs", 
      "Location__c": "San Francisco", 
      "Urgent__c": true, 
      "News_Content__c": "Large highway is closed due to asteroid collision."
    }, 
    "event": {
      "replayId": 2
    }
  }, 
  "channel": "/event/Cloud_News__e"
}

事件消息中的模式字段包含平台事件模式的标识(在本例中为“schema”:“_2DBiqh-utQNAjUH78FdbQ”)。模式是版本化的 – 当模式改变时,模式ID也改变。

要确定事件的模式是否已更改,请通过REST API检索模式。通过对此REST API资源执行GET请求来使用模式标识:/vXX.X/event/eventSchema/Schema_ID。或者,您可以通过将事件名称提供给此端点来检索事件模式:/vXX.X/sobjects/Platform_Event_Name__e/eventSchema。有关更多信息,请参阅Force.com REST API开发人员指南。

注意

与PushTopic和泛型事件不同,平台事件不支持使用过滤的订阅。例如,订阅/事件/ Cloud_News__e?Location__c =’旧金山’按位置过滤不受支持。

现在您已经看到了如何在Salesforce平台和外部应用程序中使用平台事件,这种可能性是无止境的!将平台事件用于任何数量的应用程序和集成,例如处理业务交易或参与主动客户服务。借助平台事件,您可以采用基于事件的编程模式,并享受基于事件的软件架构的优势。

Apex-事件驱动(2)

学习目标

完成本单元后,您将能够:

  • 定义一个平台事件。
  • 描述如何发布平台事件消息。
  • 使用Apex方法发布一个事件。
  • 通过插入一个sObject来发布一个使用REST API的事件。

定义和发布平台事件

现在,您已经了解了平台事件以及何时使用了平台事件,接下来我们将介绍如何定义平台事件。还记得云端通讯社吗?我们来创建一个平台事件定义来保存新闻事件的数据。

定义一个名为Cloud News的平台事件:

  1. 从安装程序中,在快速查找框中输入平台事件,然后选择 Platform Events.
  2. 在“平台事件”页面上,单击 New Platform Event.
  3. 对于标签,请输入 Cloud News.
  4. 对于多标签,请输入 Cloud News.
  5. 对于描述,输入 Cloud news events deliver news at your fingertips.
  6. 点击 Save.
  7. 在“自定义字段和关系”相关列表中,单击 New.
  8. 选择 Text, 然后单击 Next.
  9. 对于字段标签/名称,输入 Location.
  10. 对于“长度”,请键入100.保留其他字段的默认值,并将“说明”字段保留为空。点击 Save.
  11. 按照步骤7,8和9添加下两个字段:
    字段标签/名称 字段类型
    Urgent Checkbox
    News Content Text Area (Long)

对于您刚定义的Cloud News事件,您创建了各种类型的字段,如文本字段或复选框。平台事件支持的所有字段类型是:

  • Checkbox
  • Date
  • Date/Time
  • Number
  • Text
  • Text Area (Long)

事件保留和ReplayId系统字段

Salesforce将平台事件存储24小时。您可以检索API CometD客户端中存储的事件,但不能检索Apex中的事件。您可以检索所有存储的事件,也可以将事件的重播ID指定为检索事件的基线。

即使Salesforce暂时保留事件记录,也不能通过SOQL或SOSL查询它们。同样,您不能在报告,列表视图和搜索中的用户界面中使用事件记录。只有在订购CometD和使用ReplayId选项时才能检索过去的事件。我们向您展示如何订阅下一单元的活动。

每个事件消息被分配一个包含在ReplayId字段中的不透明ID。由系统填充的ReplayId字段值指的是事件流中事件的位置。重放ID值不保证连续事件连续。例如,ID为999的事件之后的事件可以具有1,025的ID。订阅者可以存储重播ID值并在重新订阅时使用它来检索保留窗口内的事件。例如,用户可以在连接失败后检索错过的事件。订阅者不得根据存储的重播ID来计算新的重播ID,以引用流中的其他事件。

API名称后缀

在创建平台事件时,系统会附加__e后缀来创建事件的API名称。例如,对于Cloud News事件,API名称是Cloud_News__e。只要以编程方式引用该事件,请使用API​​名称,例如,在Apex,REST API和Enterprise API中。

发布事件

如果您的应用程序位于Salesforce平台上,则可以使用Apex方法或声明性工具(如Process Builder或Cloud Flow Designer)发布事件。如果您的应用是外部应用,则可以使用Salesforce API发布事件。

使用Apex发布事件消息

要发布事件消息,请创建事件的实例并将其传递给EventBus.publish方法。

以下示例创建一个类型为Cloud_News__e的事件,将其发布,然后检查发布是成功还是遇到错误。 EventBus.publish()方法返回一个Database.SaveResult对象,其中包含发布的结果。如果isSuccess()返回true,则事件已在Salesforce事件总线中发布。否则,该事件遇到在Database.Error对象中返回的错误。

// 创建一个事件的实例并将其存储在newsEvent变量中
Cloud_News__e newsEvent = new Cloud_News__e(
           Location__c='Mountain City', 
           Urgent__c=true, 
           News_Content__c='Lake Road is closed due to mudslides.');

// 调用方法来发布事件
Database.SaveResult sr = EventBus.publish(newsEvent);

// 检查发布结果
if (sr.isSuccess()) {
    System.debug('Successfully published event.');
} else {
    for(Database.Error err : sr.getErrors()) {
        System.debug('Error returned: ' +
                     err.getStatusCode() +
                     ' - ' +
                     err.getMessage());
    }
}
要在同一个调用中发布多个事件,请将您的事件添加到事件列表中,然后将该列表传递给EventBus.publish()方法。此方法的输出是Database.SaveResult对象的数组:每个发布的事件一个。 EventBus.publish()可以发布一些传入事件,即使由于错误而无法发布其他事件。 EventBus.publish()方法不会因发布操作失败而引发异常。在使用部分成功选项调用时,它的行为类似于Apex Database.insert()方法。
// List来保存要发布的事件对象。
List<Cloud_News__e> newsEventList = new List<Cloud_News__e>();
// 创建事件对象
Cloud_News__e newsEvent1 = new Cloud_News__e(
           Location__c='Mountain City', 
           Urgent__c=true, 
           News_Content__c='Lake Road is closed due to mudslides.');
Cloud_News__e newsEvent2 = new Cloud_News__e(
           Location__c='Mountain City', 
           Urgent__c=false, 
           News_Content__c='Small incident on Goat Lane causing traffic.');
// 将事件对象添加到列表中。
newsEventList.add(newsEvent1);
newsEventList.add(newsEvent2);

// 调用方法来发布事件。
List<Database.SaveResult> results = EventBus.publish(newsEventList);

// 检查每个事件的发布结果
for (Database.SaveResult sr : results) {
    if (sr.isSuccess()) {
        System.debug('Successfully published event.');
    } else {
        for(Database.Error err : sr.getErrors()) {
            System.debug('Error returned: ' +
                        err.getStatusCode() +
                        ' - ' +
                        err.getMessage());
        }
    }       
}

注意

Salesforce平台对您可以在组织中定义的事件数量以及您可以在一个小时内发布的事件记录数量进行限制。此外,由于事件发布相当于DML插入操作,所以适用DML限制和其他Apex调控限制。有关平台事件限制和Apex调控器限制的更多信息,请参阅参考资料部分。

使用点击发布事件消息

要发布没有代码的事件消息,请在流程或流程中使用记录创建功能。

此屏幕截图显示了在发布Cloud News事件消息的Process Builder中创建记录操作的示例。基本上,将“记录类型”设置为要发布的平台事件(云新闻),然后设置事件的值。

The Create a Record action in Process Builder is set to the Cloud News record type. The fields of the Cloud News event are filled.

同样,您可以使用流发布平台事件消息。配置Record Create元素以创建平台事件(Cloud_News__c)的实例,然后设置事件的值。要设置布尔字段的值(如Urgent__c),请使用{!$ GlobalConstant.True}。

使用Salesforce API发布事件消息

外部应用使用API​​发布平台事件消息。您可以像插入sObjects一样创建事件记录来发布事件。您可以使用Salesforce API来创建平台事件记录,如SOAP API,REST API或Bulk API。

例如,对于Cloud News事件,您可以通过插入Cloud_News__e记录来发布事件通知。以下示例在REST API中创建一个类型为Cloud_News__e的事件。

sObject REST端点:

/services/data/v40.0/sobjects/Cloud_News__e/
POST请求的请求主体:
{
   "Location__c" : "Mountain City",
   "Urgent__c" : true,
   "News_Content__c" : "Lake Road is closed due to mudslides."
}
平台事件记录创建后,REST响应看起来像这个输出。为了简洁,标题被删除。
HTTP/1.1 201 Created 

{   
   "id" : "e00xx000000000B",
   "success" : true,
   "errors" : [ ],
   "warnings" : [ ] 
}
您可以使用任何REST API工具或HTTP客户端应用程序来进行REST API调用。例如,您可以按照以下步骤使用Workbench。
  1. 登录到您的Trailhead DE组织。
  2. 打开一个新标签页并导航到Workbench https://workbench.developerforce.com/login.php
  3. 对于环境,请选择 Production.
  4. 对于API版本,请选择可用的最高编号。
  5. 选择 I agree to the terms of service.
  6. 点击 Login with Salesforce.
  7. 在下一个屏幕上,单击 Allow.
  8. 在顶部菜单中,选择 utilities | REST Explorer.
  9. 点击 POST.
  10. 将URI替换为:
    /services/data/v40.0/sobjects/Cloud_News__e
  11. 对于请求正文,以JSON格式添加以下正文。
    {
       "Location__c" : "Mountain City",
       "Urgent__c" : true,
       "News_Content__c" : "Lake Road is closed due to mudslides."
    }
  12. 点击 Execute.

    Salesforce在发布事件后返回的响应类似于以下内容。

    {
      "id" : "e00xx0000000001AAA",
      "success" : true,
      "errors" : [ ],
      "warnings" : [ ]
    }
    
    或者,您可以通过create()调用或在Bulk API中使用批处理作业在SOAP API中发布事件。

平台事件和事务

与自定义对象不同,平台事件不在Salesforce平台的数据库事务中处理。 因此,发布的平台事件无法回滚。 请注意以下几点:

  • 当您通过API发布平台事件时,allOrNoneHeader API标头将被忽略。
  • 平台事件不支持Apex setSavepoint()和rollback()数据库方法。

当您发布平台事件时,适用DML限制和其他Apex调控限制。

现在你已经看到了如何定义和发布事件,让我们看看如何订阅它们!

Apex-事件驱动(1)

学习目标

完成本单元后,您将能够:

  • 列出基于事件的软件体系结构的组件。
  • 解释一个事件驱动的软件架构的好处。
  • 描述平台事件功能的用例。
  • 描述平台事件的特征。

了解事件驱动的软件体系结构

您的订单系统是否有包裹?打印机墨盒是否需要更换?无论您希望得到什么通知,Salesforce企业消息传递平台都可以在Salesforce内部和外部来源提供安全且可扩展的自定义通知。通过平台事件,您可以监视系统并将更改传达给其他系统。

注意

如果尚未完成,请先完成API基础模块,然后再使用该模块。熟悉Streaming API的概念是此模块的先决条件。

基于事件的沟通的范例围绕发布者 – 订阅者模型展开 – 发送者广播一个或多个接收者捕获的消息。这就像无线电传输 – 发射塔发射无线电信号,接收机获得信号,如果他们调整到正确的频率。

就像无线电传输一样,基于事件的通信从发送者流向接收者。无论接收者是否正在侦听,事件都会被发送,接收者在收到事件时不会确认。基于事件的通信可以实时进行,或者更准确地说,可以近乎实时地进行。无线电波以光速行进,但基于事件的软件和硬件系统通常有一些延迟。非必要的披露:Salesforce速度很快,但速度不及光速!

在API基础模块中,我们使用海盗船上雷达的类比来表示事件检测。这个类比适用于基于Salesforce记录更改的PushTopic事件流。该通信模型只需要一个用户。但是对于平台事件,通信有两方:发送方和接收方。它们是事件驱动架构的两个组成部分。

事件驱动系统的组件

在我们继续之前,让我们定义一些术语。

Event
在业务流程中有意义的状态变化例如,采购订单的放置是一个有意义的事件,因为订单履行中心希望在处理订单前收到通知。
Event message
包含有关事件数据的消息。也被称为事件通知。例如,事件消息可以是关于包含关于订单的信息的订单放置的通知。
Event producer
通过频道发布事件消息。例如,一个订单放置应用程序。
Event channel
事件生成器发送事件消息和事件消费者读取这些消息的事件流。在Salesforce中也称为事件总线。
Event consumer
从频道接收讯息的频道的订阅者。例如,通知新订单的订单履行应用程序。

下图说明了一个基于事件的软件体系结构。

A diagram showing components of event-based systems: event producers, which feed information into the event bus, which sends messages to the event consumers

与请求响应通信模型不同,基于事件驱动模型的软件架构将事件生成者与事件消费者分离,从而简化了连接系统中的通信模型。不需要向服务器请求获取关于某个状态的信息。相反,系统订阅事件通道,并在新状态发生时通知。任何数量的消费者都可以接收和响应相同的事件。当事件发生时,系统会获得这些信息,并可以近乎实时地对其作出反应。除了消息内容的语义之外,发送事件的系统和接收事件的系统彼此之间没有依赖关系。

Salesforce企业消息传递平台提供事件驱动软件体系结构的好处。平台事件是您的应用程序发送和接收的事件消息。它们简化了沟通变化和响应变化的过程,而无需编写复杂的逻辑。发布者和订阅者通过平台事件相互通信。一个或多个用户可以听相同的事件并执行操作。

假设一家名为“云新闻”的新闻机构向订阅的客户发送活动信息,以及有关山区撤退目的地的交通和道路状况的最新突发消息。这些事件的内容不仅仅是新闻事件本身,还包括新闻是否紧急以及事件的发生地点等相关细节。用户可以接收这些事件,并根据新闻的紧急性确定要采取的行动。

所有这一切听起来都不错,但是当你可以使用平台事件时,真实情况是什么呢?当然,平台活动的使用不限于新闻机构。以下是一些有用的应用程序。

何时使用平台事件的示例

我们来看看使用平台事件的一些业务场景。在这些情况下,Salesforce和外部系统通过平台事件消息进行通信。在第一种情况下,Salesforce中的应用程序通知产品装运订单的外部订单履行应用程序。在第二种情况下,外部产品应用程序通知Salesforce商品退货。最后一个场景显示了如何使用触发器在Salesforce中使用事件消息。

平台到外部应用程序:订单履行供应商应用程序

当Salesforce关闭一个机会时,您的公司已经赢得了与客户的交易。假设您使用供应商来运送与机会相关的产品。每个供应商都有一个处理装运订单的外部应用。外部应用程序监听平台事件。当机会关闭时,作为Salesforce产品订购应用程序一部分的触发器会触发并发布平台事件消息。每个供应商应用程序都会收到有关该事件的通知,并为特定产品创建装运订单。

In this diagram, a product order app publishes an order event to an event bus. Various vendor apps subscribe to the event bus and receive the event.

平台应用程序的外部应用程序:处理Salesforce中的商品退货

比方说,有人想把购买的商品退还给供应商。外部系统将商品退货请求发送给Salesforce进行处理。外部系统发布平台事件以提醒Salesforce返回商品。 Salesforce中的事件侦听器(触发器)接收事件并执行一些操作。例如,触发器可能会提醒销售代表退货,并向客户发送确认电子邮件。

An external vendor app publishes a platform event message for a merchandise return request. In Salesforce, a trigger subscribes to the event bus and receives the event.

平台到平台:重新分配主要记录

在Salesforce中分配销售线索时,销售线索触发器会触发并检查与销售线索所有者相关的未决商机和案例。根据相关记录,触发器发布由Salesforce应用程序接收的事件。根据事件信息,应用程序将重新分配潜在客户并创建一个Chatter帖子。

在这种情况下,您可以使用其他Salesforce功能执行相同的操作,例如Process Builder或流程。但是通过使用平台事件,您可以从基于事件的编程模型和跨应用程序的标准编程方式中受益。

In this diagram, an app in Salesforce publishes a platform event. A trigger subscribes to this event channel and receives the event.

平台事件特征

现在您已经了解了何时使用平台事件,让我们深入了解其组件和特性。

您可以定义平台事件包含的自定义数据。就像自定义对象一样,您可以在Salesforce中定义平台事件。通过给它一个名称并添加自定义字段来创建一个平台事件定义。以下是云新闻社新闻事件的自定义字段的示例定义。

字段标签/名称 字段API名称 字段类型
Location Location__c Text

Length: 100

Urgent Urgent__c Checkbox
News Content News_Content__c Text Area (Long)

平台事件和sObjects

平台事件是一种特殊的Salesforce实体,在很多方面与sObject类似。事件消息是平台事件的实例,类似于记录是自定义对象的实例。与自定义对象不同,您不能更新或删除事件记录,也不能在Salesforce用户界面中查看事件记录。

您可以设置读取和创建平台事件的权限。您向配置文件或权限集中的用户授予权限。

在本机和外部应用程序中使用平台事件

平台事件支持Salesforce内部和外部应用程序中的事件消息流。 Salesforce平台上的应用程序使用Apex方法发布事件,并使用Apex触发器来消费事件。此外,Visualforce和Lightning组件应用程序可以使用CometD订阅事件。作为代码的替代方法,您可以使用声明性工具(如Process Builder和Cloud Flow Designer)发布事件。最后,外部应用程序使用sObject API发布事件,并使用CometD客户端消费事件。如您所见,在选择使用平台事件方面有很大的灵活性!

平台事件和其他流式事件之间的差异

其他流媒体事件呢?其他事件包括PushTopic和通用事件。借助PushTopic事件,客户端将根据预定义的查询接收有关Salesforce记录更改的消息。使用通用事件,您可以发送和接收任意消息内容(有效内容),而不一定与Salesforce记录绑定。平台事件与通用事件类似,但提供更强大的自定义功能。借助平台事件,您可以发布任何自定义数据。您可以将粒度级别的事件数据模式定义为键入的字段。另外,您可以在本地Salesforce平台应用程序和外部应用程序中使用平台事件。在以下情况下使用平台事件:

  • 使用预定义模式发送和接收自定义事件数据
  • 发布或订阅Apex中的活动
  • 为了在Salesforce平台上和以外发布和处理事件的灵活性该表比较了一般事件和平台事件的特征。

功能通用事件平台事件

特征 通用事件 平台事件
将事件模式定义为类型字段 Check mark
包含用户定义的有效载荷 Check mark Check mark
通过一个或多个API发布事件 Check mark Check mark
通过Apex发布活动 Check mark
通过CometD订阅 Check mark Check mark
通过Apex触发器订阅 Check mark
使用Process Builder以声明方式发布并流动复选标记 Check mark

在下一个单元中,我们将定义一个平台事件并发布事件。

Apex 异步(6)监视异步

学习目标

完成这个单位后,你会知道:

  • 如何监控不同类型的工作。
  • 如何使用弹性队列。

监视异步作业

异步工作的好处是他们在后台默默地工作。异步工作的难点在于他们在后台默默工作。幸运的是,有几种方法可以监视你的工作内容。

您可以监视Salesforce用户界面中所有作业的状态。从安装程序中,在快速查找框中输入作业,然后选择Apex作业。

Apex Jobs页面显示所有异步Apex作业,其中包含有关每个作业执行的信息。以下屏幕截图显示了同一个Batch Apex类的一个未来方法作业和两个已完成的批处理作业。

Apex Jobs

如果您有许多批处理作业,请使用“批处理作业”页面仅查看批处理作业。要打开“Apex批处理作业”页面,请单击“Apex作业”页面顶部的链接。使用“Apex批处理作业”页面中的滑块选择特定的日期范围,并缩小显示的批处理作业的列表。您可以查看过去尚未删除的作业。 “批处理作业”页面按批处理类别对作业进行分组。

Apex Batch Jobs

点击您感兴趣的课程ID旁边的“更多信息”,查找有关为该课程执行的作业的详细信息。此图像显示单击“更多信息”后显示的弹出窗口。这个批次类有两个成功执行的作业。

information about parent jobs

您还可以监视Apex Flex队列中Apex作业的状态,并对其进行重新排序以控制首先处理哪些作业。从“设置”中,在“快速查找”框中输入作业,然后选择 Apex Flex Queue.

监测Future Jobs

Future jobs就像任何其他工作一样出现在Apex工作页面上。但是,未来的工作目前不属于灵活队列的一部分。

你可以查询AsyncApexJob找到你未来的工作,但有一个警告。由于启动未来作业不会返回ID,因此您必须过滤其他字段(如MethodName或JobType)以查找您的作业。在这个Stack Exchange文章中有几个示例SOQL查询可能会有所帮助。

使用SOQL监视Queued Jobs

要查询有关您提交的作业的信息,请通过筛选System.enqueueJob方法返回的作业ID,在AsyncApexJob上执行SOQL查询。

AsyncApexJob jobInfo = [SELECT Status, NumberOfErrors
    FROM AsyncApexJob WHERE Id = :jobID];

使用Flex队列监视Queue Jobs

Apex Flex队列使您能够提交多达100个批处理作业执行。任何提交执行的作业都处于保持状态,并放置在Apex Flex队列中。最多可以有100个批处理作业处于保持状态。

按照先进先出的顺序处理作业。您可以查看当前的队列顺序并将其排列,以便将重要的工作移到前面,或者将重要的工作移到后面。

当系统资源可用时,系统从Apex Flex队列的顶部选取下一个作业,并将其移至批处理作业队列。系统可以为每个组织同时处理最多五个排队或活动作业。这些已移动作业的状态从“保持”更改为“已排队”。排队的作业在系统准备好处理新作业时被执行。像其他作业一样,您可以在Apex Jobs页面中监控排队的作业。

监视Scheduled Jobs

在计划完Apex作业之后,您可以通过在CronTrigger上运行SOQL查询来获得更多关于它的信息。以下示例查询作业运行的次数以及计划再次运行作业的日期和时间。它使用从System.schedule方法返回的jobID变量。

CronTrigger ct = [SELECT TimesTriggered, NextFireTime FROM CronTrigger WHERE Id = :jobID];
如果您在可调度类的execute方法内部执行此查询,则可以通过调用SchedulableContext参数变量上的getTriggerId来获取当前作业的ID。
global class DoAwesomeStuff implements Schedulable {

    global void execute(SchedulableContext sc) {
        // 一些很棒的代码
        CronTrigger ct = [SELECT TimesTriggered, NextFireTime FROM CronTrigger WHERE Id = :sc.getTriggerId()];
    }
    
}
您还可以从与CronTrigger记录关联的CronJobDetail记录中获取作业的名称和作业的类型。为此,请在CronTrigger上执行查询时使用CronJobDetail关系。本示例使用CronJobDetail中的作业名称和类型来检索最新的CronTrigger记录。
CronTrigger job = [SELECT Id, CronJobDetail.Id, CronJobDetail.Name, CronJobDetail.JobType FROM CronTrigger ORDER BY CreatedDate DESC LIMIT 1];
或者,您可以直接查询CronJobDetail以获取作业的名称和类型。 以下示例获取上例中查询的CronTrigger记录的作业名称和类型。 相应的CronJobDetail记录标识由CronTrigger记录上的CronJobDetail.Id表达式获取。
CronJobDetail ctd = [SELECT Id, Name, JobType FROM CronJobDetail WHERE Id = :job.CronJobDetail.Id];
最后,要获取所有Apex计划作业的总计数(不包括所有其他计划作业类型),请执行以下查询。 请注意,值“7”是为作业类型指定的,该作业类型对应于预定的Apex作业类型。 请参阅参考资料部分中的CronJobDetail,了解所有类型的列表。
SELECT COUNT() FROM CronTrigger WHERE CronJobDetail.JobType = '7