

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# `joinOrder` SPARQL 查询提示
<a name="sparql-query-hints-joinOrder"></a>

在提交 SPARQL 查询时，Amazon Neptune 查询引擎将调查查询的结构。它将对查询的各个部分重新排序，并尝试最大程度地减少计算所需的工作量和查询响应时间。

例如，通常不会按给定顺序计算一系列连接的三元组模式。使用试探法和统计数据（例如，各个模式的选择性以及它们通过共享变量连接的方式）来对查询重新排序。此外，如果您的查询包含更复杂的模式，例如子查询 FILTERs、或复杂的 OPTIONAL 或 MINUS 块，Neptune 查询引擎会尽可能对它们进行重新排序，以实现有效的评估顺序。

对于更复杂的查询，Neptune 选择计算查询的顺序可能并不总是最佳的。例如，Neptune 可能会丢失在计算查询期间发生的实例数据特定的特征（例如命中图形中的电源节点）。

如果您知道确切的数据特性并且想要手动指示查询执行顺序，请使用 Neptune `joinOrder` 查询提示指定按给定的顺序计算查询。

## `joinOrder` SPARQL 提示语法
<a name="sparql-query-hints-joinOrder-syntax"></a>

`joinOrder` 查询提示被指定为 SPARQL 查询中包含的三元组模式。

为清晰起见，以下语法使用查询中定义并包含的 `hint` 前缀来指定 Neptune 查询提示命名空间：

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
scope hint:joinOrder "Ordered" .
```

**可用范围**
+ `hint:Query`
+ `hint:Group`

有关查询提示范围的更多信息，请参阅 [Neptune 中的 SPARQL 查询提示范围](sparql-query-hints.md#sparql-query-hints-scope)。

## `joinOrder` SPARQL 提示示例
<a name="sparql-query-hints-joinOrder-example"></a>

本节介绍使用和未使用 `joinOrder` 查询提示和相关优化编写的查询。

在此示例中，假定数据集包含以下内容：
+ 一个名为 `John` 的人（`:likes` 1000 人，包括 `Jane`）。
+ 一个名为 `Jane` 的人（`:likes` 10 人，包括 `John`）。

**无查询提示**  
以下 SPARQL 查询将从一组社交网络数据中提取所有名为 `John` 和 `Jane` 的人员（相互关注）对：

```
PREFIX : <https://example.com/>
SELECT ?john ?jane {
  ?person1 :name "Jane" .
  ?person1 :likes ?person2 .
  ?person2 :name "John" .
  ?person2 :likes ?person1 .
}
```

Neptune 查询引擎可能会以不同于编写的顺序计算语句。例如，它可能选择按以下顺序计算：

1. 查找所有名为 `John` 的人。

1. 查找通过 `:likes` 边缘连接到 `John` 的所有人。

1. 按名为 `Jane` 的人筛选此集。

1. 按通过 `:likes` 边缘连接到 `John` 的人筛选此集。

根据此数据集，按此顺序进行计算会导致在第二步中提取 1000 个实体。第三步将此范围缩小到单个节点 `Jane`。之后，最后一步确定 `Jane` 也将 `:likes` 节点 `John`。

**查询提示**  
从 `Jane` 节点开始是有利的，因为她只有 10 个传出 `:likes` 边缘。这将避免在第二步中提取 1000 个实体，从而减少了查询计算期间的工作量。

以下示例使用 **joinOrder** 查询提示，通过对查询禁用所有自动联接重新排序来确保先处理 `Jane` 节点及其传出边缘：

```
PREFIX : <https://example.com/>
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ?john ?jane {
  hint:Query hint:joinOrder "Ordered" .
  ?person1 :name "Jane" .
  ?person1 :likes ?person2 .
  ?person2 :name "John" .
  ?person2 :likes ?person1 .
}
```

一个适用的现实场景可能是社交网络应用程序，其中网络中的人员被分为具有许多连接的影响者和具有很少连接的普通用户。在此场景中，您可以确保在类似于上一个示例的查询中，先处理普通用户 (`Jane`)，再处理影响者 (`John`)。

**查询提示和重新排序**  
您可以进一步了解此示例。如果您知道 `:name` 属性对于单一节点是唯一的，则可通过重新排序和使用 `joinOrder` 查询提示来加快查询速度。此步骤确保首先提取唯一节点。

```
PREFIX : <https://example.com/>
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ?john ?jane {
  hint:Query hint:joinOrder "Ordered" .
  ?person1 :name "Jane" .
  ?person2 :name "John" .
  ?person1 :likes ?person2 .
  ?person2 :likes ?person1 .
}
```

在此情况下，您可以在每个步骤中将查询减少到以下单个操作：

1. 查找包含 `:name` `Jane` 的单个人节点。

1. 查找包含 `:name` `John` 的单个人节点。

1. 检查使用 `:likes` 边缘连接到第二个节点的第一个节点。

1. 检查使用 `:likes` 边缘连接到第一个节点的第二个节点。



**重要**  
如果您选择了错误的顺序，则 `joinOrder` 查询提示可能会导致性能显著下降。例如，如果 `:name` 属性不是唯一的，则上一个示例的效率低下。如果所有 100 个节点都名为 `Jane` 并且所有 1000 个节点都名为 `John`，则查询将最终检查 `:likes` 边缘的 1000 \$1 100 (100000) 个对。