

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

# Amazon Neptune 中的查询计划缓存
<a name="access-graph-qpc"></a>

 查询提交至 Neptune 时，查询字符串会被解析、优化并转换为查询计划，然后由引擎执行。应用程序通常依赖通用查询模式，这些模式会通过传入不同参数值来实例化。查询计划缓存可以通过缓存查询计划，避免对此类重复的模式进行解析和优化，从而降低整体延迟。

 查询计划缓存可用于**OpenCypher**查询，包括非参数化查询或参数化查询。READ（包括 HTTP 和 Bolt）支持该功能。OC 突变查询**不**支持该功能。Gremlin 或 SPARQL 查询**不**支持该功能。

## 如何强制启用或禁用查询计划缓存
<a name="access-graph-qpc-enable"></a>

 默认情况下，查询计划缓存处于启用状态，用于低延迟参数化查询。仅当延迟低于 **100 毫秒**的阈值时，系统才会缓存参数化查询的计划。查询级别的查询提示 `QUERY:PLANCACHE` 可以在每个查询（无论是否参数化）的基础上覆盖此行为。它需要与 `USING` 子句一起使用。该查询提示接受 `enabled` 或 `disabled` 作为值。

------
#### [ Amazon CLI ]

强制对计划进行缓存或重复使用：

```
aws neptunedata execute-open-cypher-query \
  --endpoint-url https://{{your-neptune-endpoint}}:{{port}} \
  --open-cypher-query "Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1"
```

参数为：

```
aws neptunedata execute-open-cypher-query \
  --endpoint-url https://{{your-neptune-endpoint}}:{{port}} \
  --open-cypher-query "Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
  --parameters '{"arg": 123}'
```

强制既不缓存也不重复使用计划：

```
aws neptunedata execute-open-cypher-query \
  --endpoint-url https://{{your-neptune-endpoint}}:{{port}} \
  --open-cypher-query "Using QUERY:PLANCACHE \"disabled\" MATCH(n) RETURN n LIMIT 1"
```

有关更多信息，请参阅《 Amazon CLI 命令参考》[execute-open-cypher-query](https://docs.amazonaws.cn/cli/latest/reference/neptunedata/execute-open-cypher-query.html)中的。

------
#### [ SDK ]

```
import boto3
from botocore.config import Config

client = boto3.client(
    'neptunedata',
    endpoint_url='https://{{your-neptune-endpoint}}:{{port}}',
    config=Config(read_timeout=None, retries={'total_max_attempts': 1})
)

# Forcing plan to be cached or reused
response = client.execute_open_cypher_query(
    openCypherQuery='Using QUERY:PLANCACHE "enabled" MATCH(n) RETURN n LIMIT 1'
)

print(response['results'])
```

有关其他语言 Amazon 的 SDK 示例，请参阅[Amazon SDK](access-graph-opencypher-sdk.md)。

------
#### [ awscurl ]

强制对计划进行缓存或重复使用：

```
awscurl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  --region {{us-east-1}} \
  --service neptune-db \
  -X POST \
  -d "query=Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1"
```

**注意**  
此示例假设您的 Amazon 证书是在您的环境中配置的。{{us-east-1}}替换为 Neptune 集群的区域。

------
#### [ curl ]

强制对计划进行缓存或重复使用：

```
curl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1"
```

参数为：

```
curl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
  -d "parameters={\"arg\": 123}"
```

强制既不缓存也不重复使用计划：

```
curl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  -d "query=Using QUERY:PLANCACHE \"disabled\" MATCH(n) RETURN n LIMIT 1"
```

------

## 如何确定计划是否已缓存
<a name="access-graph-qpc-status"></a>

 对于 HTTP READ，如果已提交查询且计划已缓存，则 `explain` 将显示与查询计划缓存相关的详细信息。

------
#### [ Amazon CLI ]

```
aws neptunedata execute-open-cypher-explain-query \
  --endpoint-url https://{{your-neptune-endpoint}}:{{port}} \
  --open-cypher-query "Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1" \
  --explain-mode details
```

有关更多信息，请参阅《 Amazon CLI 命令参考》中的 [execute-open-cypher-explain-query](https://docs.amazonaws.cn/cli/latest/reference/neptunedata/execute-open-cypher-explain-query.html)。

------
#### [ SDK ]

```
import boto3
from botocore.config import Config

client = boto3.client(
    'neptunedata',
    endpoint_url='https://{{your-neptune-endpoint}}:{{port}}',
    config=Config(read_timeout=None, retries={'total_max_attempts': 1})
)

response = client.execute_open_cypher_explain_query(
    openCypherQuery='Using QUERY:PLANCACHE "enabled" MATCH(n) RETURN n LIMIT 1',
    explainMode='details'
)

print(response['results'].read().decode('utf-8'))
```

有关其他语言 Amazon 的 SDK 示例，请参阅[Amazon SDK](access-graph-opencypher-sdk.md)。

------
#### [ awscurl ]

```
awscurl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  --region {{us-east-1}} \
  --service neptune-db \
  -X POST \
  -d "query=Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1" \
  -d "explain=details"
```

**注意**  
此示例假设您的 Amazon 证书是在您的环境中配置的。{{us-east-1}}替换为 Neptune 集群的区域。

------
#### [ curl ]

```
curl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1" \
  -d "explain=details"
```

------

如果计划已缓存，则`explain`输出将显示：

```
Query: <QUERY STRING>
Plan cached by request: <REQUEST ID OF FIRST TIME EXECUTION>
Plan cached at: <TIMESTAMP OF FIRST TIME EXECUTION>
Parameters: <PARAMETERS, IF QUERY IS PARAMETERIZED QUERY>
Plan cache hits: <NUMBER OF CACHE HITS FOR CACHED PLAN>
First query evaluation time: <LATENCY OF FIRST TIME EXECUTION>

The query has been executed based on a cached query plan. Detailed explain with operator runtime statistics can be obtained by running the query with plan cache disabled (using HTTP parameter planCache=disabled).
```

 使用 Bolt 时，不支持解释功能。

## 驱逐
<a name="access-graph-qpc-eviction"></a>

 当达到缓存生存时间（TTL）或缓存查询计划的最大数量时，查询计划将被驱逐。当查询计划被命中时，TTL 会刷新。默认值为：
+  1000 – 每个实例可以缓存的最大计划数。
+  TTL – 30 万毫秒或 5 分钟。缓存命中会重新启动 TTL，并将其重置回 5 分钟。

## 导致计划无法缓存的条件
<a name="access-graph-qpc-conditions"></a>

 在以下条件下，系统不会使用查询计划缓存：

1.  使用查询提示 `QUERY:PLANCACHE "disabled"` 提交查询。您可以重新运行查询并删除 `QUERY:PLANCACHE "disabled"` 以启用查询计划缓存。

1.  提交的查询不是参数化查询且不包含提示 `QUERY:PLANCACHE "enabled"`。

1.  如果查询评估时间大于延迟阈值，则该查询不会被缓存，并且被视为长时查询，不会使用查询计划缓存。

1.  查询包含不返回任何结果的模式。
   +  例如 `MATCH (n:nonexistentLabel) return n`（当具有指定标签的节点为零时）。
   +  例如带有 `parameters={"param": "abcde"}` 的 `MATCH (n {name: $param}) return n`（当包含 `name=abcde` 的节点为零时）。

1.  查询参数是复合类型，例如 `list` 或 `map`。

   ```
   curl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
     -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
     -d "parameters={\"arg\": [1, 2, 3]}"
   
   curl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
     -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
     -d "parameters={\"arg\": {\"a\": 1}}"
   ```

1.  查询参数是一个未参与数据加载或数据插入操作的字符串。例如，如果运行 `CREATE (n {name: "X"})` 以插入 `"X"`，则 `RETURN "X"` 会被缓存，而 `RETURN "Y"` 不会被缓存，因为 `"Y"` 尚未插入且不在数据库中。