这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

加载并行度

Vertica 可以拆分加载数据的工作,从而利用并行度来加快操作速度。Vertica 支持多种类型的并行度:

  • 分布式加载:Vertica 会将多文件加载中的文件分配给多个节点以并行加载,而不是在单个节点上加载所有文件。Vertica 会管理分布式加载;您无需在 UDL 中执行任何特殊操作。

  • 协作解析:在单个节点上加载的源会使用多线程来并行执行解析。协作解析会根据线程的调度方式在执行时拆分加载。您必须在解析器中启用协作解析。请参阅协作解析

  • 分摊加载:Vertica 会将单个大型文件或其他单个源拆分成多个段,以将段分配给多个节点进行并行加载。分摊加载会根据每个节点上的可用节点和核心在计划时拆分加载。您必须在源代码和解析器中启用分摊加载。请参阅分摊加载

您可以在同一 UDL 中同时支持协作解析和分摊加载。Vertica 可确定要对每个加载操作使用哪个并行度,也可能同时使用这两者。请参阅组合协作解析和分摊加载

1 - 协作解析

默认情况下,Vertica 会在一个数据库节点上的单个线程中解析数据源。您可以选择使用协作解析,以在节点上使用多个线程来解析源。更具体地说,源中的数据将通过块分割器,块分割器会将源流中的块分组为逻辑单元。可以并行解析这些块。块分割器会将输入拆分为可单独解析的块,然后由解析器同时进行解析。协作解析仅适用于非隔离 UDx。(请参阅隔离和非隔离模式。)

要使用协作解析,块分割器必须能够在输入中找到记录结尾标记。并非在所有输入格式中都能找到这些标记。

块分割器由解析器工厂创建。在加载时,Vertica 会先调用 UDChunker 以将输入拆分为块,然后调用 UDParser 以解析每个块。

您可以单独或同时使用协作解析和分摊加载。请参阅组合协作解析和分摊加载

Vertica 如何拆分加载

当 Vertica 收到来自源的数据时,它会重复调用块分割器的 process() 方法。块分割器本质上是一个轻量级解析器。process() 方法用于将输入拆分为块,而不是进行解析。

块分割器完成将输入拆分为块后,Vertica 会将这些块发送到尽可能多的可用解析器,从而在解析器上调用 process() 方法。

实施协作解析

要实施协作解析,请执行以下操作:

  • 子类化 UDChunker 并实施 process()

  • ParserFactory 中,实施 prepareChunker() 以返回 UDChunker

请参阅 C++ 示例:分隔解析器和块分割器以了解同样支持分摊加载的 UDChunker

2 - 分摊加载

解析器可以使用多个数据库节点来并行加载单个输入源。此方法称为分摊加载。在 Vertica 内置的解析器中,默认(分隔)解析器支持分摊加载。

与协作解析一样,分摊加载也需要可以在记录边界进行拆分的输入。不同之处在于,协作解析会执行顺序扫描以查找记录边界,而分摊加载会先跳(寻找)至给定位置,然后再执行扫描。某些格式(例如通用 XML)不支持寻找。

要使用分摊加载,您必须确保所有参与的数据库节点都可以访问源。分摊加载通常与分布式文件系统结合使用。

解析器可以不直接支持分摊加载,但需要包含支持分摊的块分割器。

您可以单独或同时使用分摊加载和协作解析。请参阅组合协作解析和分摊加载

Vertica 如何分摊加载

如果解析器及其源均支持分摊,则您可以指定将单个输入分发到多个数据库节点进行加载。SourceFactory 可将输入拆分为多个部分,并将它们分配给执行节点。每个 Portion 包含一个输入偏移量和一个大小。Vertica 会将各个部分及其参数分发到执行节点。在每个节点上运行的源工厂将为给定部分生成一个 UDSource

UDParser 首先会确定从何处开始解析:

  • 如果该部分是输入中的第一部分,则解析器会前进至该偏移量并开始解析。

  • 如果不是输入中的第一部分,则解析器会前进该偏移量,然后执行扫描直至找到记录的结尾。由于记录分散在多个部分,因此在到达第一个记录结尾之后开始解析。

解析器必须完成整个记录,这可能要求解析器在该部分的结尾之后继续读取。无论记录在何处结束,解析器都负责处理从已分配的部分开始的所有记录。此工作主要在解析器的 process() 方法中进行。

有时,一个部分不包含可由已分配的节点解析的任何内容。例如,假设某个记录从第 1 部分开始,而且贯穿第 2 部分并在第 3 部分结束。分配给第 1 部分的解析器将解析该记录,而分配给第 3 部分的解析器将在该记录之后开始解析。但是,分配给第 2 部分的解析器没有任何记录从此部分开始。

如果加载也使用 协作解析,则在分摊加载之后和解析之前,Vertica 会将部分拆分成块以进行并行加载。

实施分摊加载

要实施分摊加载,请在源、解析器及其工厂中执行下列操作。

在您的 SourceFactory 子类中:

  • 实施 isSourceApportionable() 并返回 true

  • 实施 plan(),以确定部分大小,指定部分,以及将各个部分分配给执行节点。要将多个部分分配给特定的执行程序,请使用计划上下文 (PlanContext::getWriter()) 上的参数编写器来传递信息。

  • 实施 prepareUDSources()。Vertica 将使用由工厂创建的计划上下文对每个执行节点调用此方法。此方法将返回 UDSource 实例,以用于该节点的已分配部分。

  • 如果源可以利用并行度,您可以实施 getDesiredThreads() 为每个源请求多个线程。有关此方法的详细信息,请参阅 SourceFactory 类

UDSource 子类中,与对任何其他源一样使用已分配的部分实施 process()。可以使用 getPortion() 检索此部分。

在您的 ParserFactory 子类中:

  • 实施 isParserApportionable() 并返回 true

  • 如果解析器使用支持分摊加载的 UDChunker,请实施 isChunkerApportionable()

在您的 UDParser 子类中:

  • 编写 UDParser 子类,使其对各个部分而非整个源执行操作。您可以通过处理流状态 PORTION_STARTPORTION_END 或使用 ContinuousUDParser API 来完成该编写。解析器必须扫描该部分的开头,查找该部分之后的第一个记录边界并解析至从该部分开始的最后一个记录的结尾。请注意,此行为可能会要求解析器在该部分的结尾之后继续读取。

  • 对某个部分不包含任何记录这一特殊情况进行如下处理:返回但不写入任何输出。

UDChunker 子类中,实施 alignPortion()。请参阅对齐部分

示例

SDK 在 ApportionLoadFunctions 目录中提供了分摊加载的 C++ 示例:

  • FilePortionSourceUDSource 的子类。

  • DelimFilePortionParserContinuousUDParser 的子类。

将这些类一起使用。您还可以将 FilePortionSource 与内置的分隔解析器结合使用。

以下示例显示了如何加载库并在数据库中创建函数:


=> CREATE LIBRARY FilePortionSourceLib as '/home/dbadmin/FP.so';

=> CREATE LIBRARY DelimFilePortionParserLib as '/home/dbadmin/Delim.so';

=> CREATE SOURCE FilePortionSource AS
LANGUAGE 'C++' NAME 'FilePortionSourceFactory' LIBRARY FilePortionSourceLib;

=> CREATE PARSER DelimFilePortionParser AS
LANGUAGE 'C++' NAME 'DelimFilePortionParserFactory' LIBRARY DelimFilePortionParserLib;

以下示例显示了如何使用源和解析器来加载数据:


=> COPY t WITH SOURCE FilePortionSource(file='g1/*.dat') PARSER DelimFilePortionParser(delimiter = '|',
    record_terminator = '~');

3 - 组合协作解析和分摊加载

您可以在同一解析器中同时启用协作解析分摊加载,从而允许 Vertica 决定如何加载数据。

决定如何拆分加载

Vertica 在查询规划时会尽可能使用分摊加载。它决定是否在执行时也使用协作解析。

分摊加载需要 SourceFactory 支持。如果指定合适的 UDSource,Vertica 将在规划时对 ParserFactory 调用 isParserApportionable() 方法。如果此方法返回 true,Vertica 将分摊加载。

如果 isParserApportionable() 返回 false,但 isChunkerApportionable() 返回 true,则块分割器可用于协作解析且块分割器支持分摊加载。Vertica 会分摊加载。

如果这些方法均未返回 true,则 Vertica 不会分摊加载。

在执行时,Vertica 会先检查加载是否在非隔离模式下运行,并仅在非隔离模式下运行才继续操作。在隔离模式下,不支持协作解析。

如果未分摊加载且有多个线程可用,Vertica 将使用协作解析。

如果已分摊加载且正好只有一个线程可用,则 Vertica 在当且仅当解析器不可分摊时才使用协作解析。在这种情况下,块分割器是可分摊的,但解析器是不可分摊的。

如果已分摊加载、有多个线程可用且块分割器是可分摊的,则 Vertica 会使用协作解析。

如果 Vertica 使用协作解析,但 prepareChunker() 未返回 UDChunker 实例,则 Vertica 会报告错误。

执行分摊的协作加载

如果加载同时使用分摊加载和协作解析,则 Vertica 会使用 SourceFactory 将输入分解为多个部分。然后,它将这些部分分配给执行节点。请参阅 Vertica 如何分摊加载

在执行节点上,Vertica 会调用块分割器的 alignPortion() 方法以将输入与部分边界对齐。(此步骤在第一部分已跳过,且根据定义已在开始时对齐。)必须执行此步骤,因为使用分摊加载的解析器有时必须在相应部分结尾之后继续读取,因此块分割器需要找到终点。

对齐相应部分后,Vertica 会重复调用块分割器的 process() 方法。请参阅 Vertica 如何拆分加载

然后,将块分割器找到的各个块发送给解析器的 process() 方法以按照常规方式进行处理。