

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

# 获取 PartiQL 语句统计信息
<a name="working.statement-stats"></a>

**重要**  
终止支持通知：现有客户将能够使用 Amazon QLDB，直到 2025 年 7 月 31 日终止支持。有关更多详细信息，请参阅[将亚马逊 QLDB 账本迁移到亚马逊 Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/)。

Amazon QLDB 提供语句执行统计信息，可帮助您通过运行更高效的 PartiQL 语句来优化 QLDB 的使用。QLDB 将这些统计信息与语句结果一起返回。它们包含量化消耗的 I/O 使用情况和服务器端处理时间的指标，您可以使用这些指标来识别低效的语句。

此功能当前用于[QLDB 控制台](console_QLDB.md)、 [QLDB Shell](data-shell.md)以及最新版 [QLDB 驱动程序](getting-started-driver.md)（所有语言）的*PartiQL 编辑器*。您还可在控制台上查看查询历史的语句统计信息。

**Topics**
+ [I/O 使用率](#statement-stats.io-usage)
+ [计时信息](#statement-stats.timing-information)

## I/O 使用率
<a name="statement-stats.io-usage"></a>

I/O 使用率指标介绍了读取 I/O 请求的数量。如果读取 I/O 请求的数量高于预期，则表示语句未经优化，例如缺少索引。我们建议您在上一主题 *优化查询性能* 中复习[最优查询模式](working.optimize.md#working.optimize.patterns)。

**注意**  
在非空表上运行`CREATE INDEX`语句时，I/O 使用率指标仅包含同步索引创建调用的读取请求。  
QLDB 异步为表中的任何现有文档创建索引。这些异步读取请求不包括在语句结果的 I/O 使用率指标中。异步读取请求单独收费，且在索引构建完成后计入您的读取 I/O 总数。

### 使用 QLDB 控制台
<a name="statement-stats.io-usage.con"></a>

若要使用 QLDB 控制台获取语句的读取 I/O 使用情况，请执行以下步骤：

1. [在 /qldb 上打开亚马逊 QLDB 控制台。https://console.aws.amazon.com](https://console.aws.amazon.com/qldb)

1. 在导航窗格中，选择 **‬PartiQL 编辑器**。

1. 从分类账下拉列表中选择分类帐。

1. 在查询编辑器窗口中，输入您选择的任何语句，然后选择 **运行**。以下是查询示例。

   ```
   SELECT * FROM testTable WHERE firstName = 'Jim'
   ```

   要运行语句，你可对 Windows 使用快捷键Ctrl\$1Enter，对 macOS 使用Cmd\$1Return。有关更多键盘快捷键的信息，请参阅 ‭[PartiQL 编辑器键盘快捷键](console_QLDB.md#console_QLDB.partiql-editor-shortcuts)。

1. 在查询编辑器窗口下方，您的查询结果包括*读取 I/O*，此语句发出的读取请求数。

您还可通过执行以下步骤来查看查询历史记录的读取 I/O：

1. 在导航窗格中，选择**PartiQL 编辑器**下的**最新查询**。

1. **读取 I/O** 列显示每条语句发出的读取请求数。

### 使用 QLDB 驱动程序
<a name="statement-stats.io-usage.driver"></a>

要使用 QLDB 驱动程序获取语句 I/O 使用情况，请调用结果的流指针或缓冲指针的`getConsumedIOs`操作。

以下代码示例显示如何从语句结果的*流指针* 中读取 I/O。

------
#### [ Java ]

```
import com.amazon.ion.IonSystem;
import com.amazon.ion.IonValue;
import com.amazon.ion.system.IonSystemBuilder;
import software.amazon.qldb.IOUsage;
import software.amazon.qldb.Result;

IonSystem ionSystem = IonSystemBuilder.standard().build();
IonValue ionFirstName = ionSystem.newString("Jim");

driver.execute(txn -> {
    Result result = txn.execute("SELECT * FROM testTable WHERE firstName = ?", ionFirstName);

    for (IonValue ionValue : result) {
        // User code here to handle results
    }

    IOUsage ioUsage = result.getConsumedIOs();
    long readIOs = ioUsage.getReadIOs();
});
```

------
#### [ .NET ]

```
using Amazon.IonDotnet.Builders;
using Amazon.IonDotnet.Tree;
using Amazon.QLDB.Driver;
using IAsyncResult = Amazon.QLDB.Driver.IAsyncResult;

// This is one way of creating Ion values. We can also use a ValueFactory.
// For more details, see: https://docs.aws.amazon.com/qldb/latest/developerguide/driver-cookbook-dotnet.html#cookbook-dotnet.ion
IIonValue ionFirstName = IonLoader.Default.Load("Jim");

await driver.Execute(async txn =>
{
    IAsyncResult result = await txn.Execute("SELECT * FROM testTable WHERE firstName = ?", ionFirstName);

    // Iterate through stream cursor to accumulate read IOs.
    await foreach (IIonValue ionValue in result)
    {
        // User code here to handle results.
        // Warning: It is bad practice to rely on results within a lambda block, unless
        // it is to check the state of a result. This is because lambdas are retryable.
    }

    var ioUsage = result.GetConsumedIOs();
    var readIOs = ioUsage?.ReadIOs;
});
```

**注意**  
要转换为同步代码，请移除 `await` 和 `async` 关键字，然后将 `IAsyncResult` 类型更改为 `IResult`。

------
#### [ Go ]

```
import (
    "context"
    "fmt"
    "github.com/awslabs/amazon-qldb-driver-go/v2/qldbdriver"
)

driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) {
    result, err := txn.Execute("SELECT * FROM testTable WHERE firstName = ?", "Jim")

    if err != nil {
        panic(err)
    }

    for result.Next(txn) {
        // User code here to handle results
    }

    ioUsage := result.GetConsumedIOs()
    readIOs := *ioUsage.GetReadIOs()
    fmt.Println(readIOs)
    return nil,nil
})
```

------
#### [ Node.js ]

```
import { IOUsage, ResultReadable, TransactionExecutor } from "amazon-qldb-driver-nodejs";

await driver.executeLambda(async (txn: TransactionExecutor) => {
    const result: ResultReadable = await txn.executeAndStreamResults("SELECT * FROM testTable WHERE firstName = ?", "Jim");

    for await (const chunk of result) {
        // User code here to handle results
    }

    const ioUsage: IOUsage = result.getConsumedIOs();
    const readIOs: number = ioUsage.getReadIOs();
});
```

------
#### [ Python ]

```
def get_read_ios(transaction_executor):
    cursor = transaction_executor.execute_statement("SELECT * FROM testTable WHERE firstName = ?", "Jim")

    for row in cursor:
        # User code here to handle results
        pass

    consumed_ios = cursor.get_consumed_ios()
    read_ios = consumed_ios.get('ReadIOs')

qldb_driver.execute_lambda(lambda txn: get_read_ios(txn))
```

------

以下代码示例显示如何从语句结果的*缓冲指针*中读取 I/O。这将返回来自 `ExecuteStatement` 和`FetchPage` 请求的读取 I/O 总数。

------
#### [ Java ]

```
import com.amazon.ion.IonSystem;
import com.amazon.ion.IonValue;
import com.amazon.ion.system.IonSystemBuilder;
import software.amazon.qldb.IOUsage;
import software.amazon.qldb.Result;

IonSystem ionSystem = IonSystemBuilder.standard().build();
IonValue ionFirstName = ionSystem.newString("Jim");

Result result = driver.execute(txn -> {
    return txn.execute("SELECT * FROM testTable WHERE firstName = ?", ionFirstName);
});

IOUsage ioUsage = result.getConsumedIOs();
long readIOs = ioUsage.getReadIOs();
```

------
#### [ .NET ]

```
using Amazon.IonDotnet.Builders;
using Amazon.IonDotnet.Tree;
using Amazon.QLDB.Driver;
using IAsyncResult = Amazon.QLDB.Driver.IAsyncResult;

IIonValue ionFirstName = IonLoader.Default.Load("Jim");

IAsyncResult result = await driver.Execute(async txn =>
{
    return await txn.Execute("SELECT * FROM testTable WHERE firstName = ?", ionFirstName);
});

var ioUsage = result.GetConsumedIOs();
var readIOs = ioUsage?.ReadIOs;
```

**注意**  
要转换为同步代码，请移除 `await` 和 `async` 关键字，然后将 `IAsyncResult` 类型更改为 `IResult`。

------
#### [ Go ]

```
import (
    "context"
    "fmt"
    "github.com/awslabs/amazon-qldb-driver-go/v2/qldbdriver"
)

result, err := driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) {
    result, err :=  txn.Execute("SELECT * FROM testTable WHERE firstName = ?", "Jim")
    if err != nil {
        return nil, err
    }
    return txn.BufferResult(result)
})

if err != nil {
    panic(err)
}

qldbResult := result.(*qldbdriver.BufferedResult)
ioUsage := qldbResult.GetConsumedIOs()
readIOs := *ioUsage.GetReadIOs()
fmt.Println(readIOs)
```

------
#### [ Node.js ]

```
import { IOUsage, Result, TransactionExecutor } from "amazon-qldb-driver-nodejs";

const result: Result = await driver.executeLambda(async (txn: TransactionExecutor) => {
    return await txn.execute("SELECT * FROM testTable WHERE firstName = ?", "Jim");
});

const ioUsage: IOUsage = result.getConsumedIOs();
const readIOs: number = ioUsage.getReadIOs();
```

------
#### [ Python ]

```
cursor = qldb_driver.execute_lambda(
    lambda txn: txn.execute_statement("SELECT * FROM testTable WHERE firstName = ?", "Jim"))

consumed_ios = cursor.get_consumed_ios()
read_ios = consumed_ios.get('ReadIOs')
```

------

**注意**  
流指针是有状态的，因为它会对结果集分页。因此，`getConsumedIOs` 和`getTimingInformation`操作会返回您调用这些指标时的累积指标。  
缓冲后的指针将结果集缓存至内存中，并返回累积的指标总数。

## 计时信息
<a name="statement-stats.timing-information"></a>

计时信息指标描述了服务器端处理时间（以毫秒为单位）。服务器端处理时间定义为 QLDB 在处理语句上所需时间。这不包括网络通话或暂停时间。该指标将 QLDB 服务端的处理时间与客户端处理时间区分开来。

### 使用 QLDB 控制台
<a name="statement-stats.timing-information.con"></a>

要使用 QLDB 控制台获取语句时序信息，请执行以下步骤：

1. [在 /qldb 上打开亚马逊 QLDB 控制台。https://console.aws.amazon.com](https://console.aws.amazon.com/qldb)

1. 在导航窗格中，选择 **‬PartiQL 编辑器**。

1. 从分类账下拉列表中选择分类帐。

1. 在查询编辑器窗口中，输入您选择的任何语句，然后选择 **运行**。以下是查询示例。

   ```
   SELECT * FROM testTable WHERE firstName = 'Jim'
   ```

   要运行语句，你可对 Windows 使用快捷键Ctrl\$1Enter，对 macOS 使用Cmd\$1Return。有关更多键盘快捷键的信息，请参阅 ‭[PartiQL 编辑器键盘快捷键](console_QLDB.md#console_QLDB.partiql-editor-shortcuts)。

1. 在查询编辑器窗口下方，您的查询结果包括*服务器端延迟*，即 QLDB 收到语句请求与发送响应之间的时间长度。这是总查询时长子集。

您还可通过执行以下步骤来查看查询历史记录的计时信息：

1. 在导航窗格中，选择**PartiQL 编辑器**下的**最新查询**。

1. **执行时间（ms）**列将会显示每条语句的计时信息。

### 使用 QLDB 驱动程序
<a name="statement-stats.timing-information.driver"></a>

要使用 QLDB 驱动程序获取语句的计时信息，请调用结果的流指针或缓冲指针的`getTimingInformation`操作。

以下代码示例显示如何从语句结果的*流指针* 中获取处理时间。

------
#### [ Java ]

```
import com.amazon.ion.IonSystem;
import com.amazon.ion.IonValue;
import com.amazon.ion.system.IonSystemBuilder;
import software.amazon.qldb.Result;
import software.amazon.qldb.TimingInformation;

IonSystem ionSystem = IonSystemBuilder.standard().build();
IonValue ionFirstName = ionSystem.newString("Jim");

driver.execute(txn -> {
    Result result = txn.execute("SELECT * FROM testTable WHERE firstName = ?", ionFirstName);

    for (IonValue ionValue : result) {
        // User code here to handle results
    }

    TimingInformation timingInformation = result.getTimingInformation();
    long processingTimeMilliseconds = timingInformation.getProcessingTimeMilliseconds();
});
```

------
#### [ .NET ]

```
using Amazon.IonDotnet.Builders;
using Amazon.IonDotnet.Tree;
using Amazon.QLDB.Driver;
using IAsyncResult = Amazon.QLDB.Driver.IAsyncResult;

IIonValue ionFirstName = IonLoader.Default.Load("Jim");

await driver.Execute(async txn =>
{
    IAsyncResult result = await txn.Execute("SELECT * FROM testTable WHERE firstName = ?", ionFirstName);

    // Iterate through stream cursor to accumulate processing time.
    await foreach(IIonValue ionValue in result)
    {
        // User code here to handle results.
        // Warning: It is bad practice to rely on results within a lambda block, unless
        // it is to check the state of a result. This is because lambdas are retryable.
    }

    var timingInformation = result.GetTimingInformation();
    var processingTimeMilliseconds = timingInformation?.ProcessingTimeMilliseconds;
});
```

**注意**  
要转换为同步代码，请移除 `await` 和 `async` 关键字，然后将 `IAsyncResult` 类型更改为 `IResult`。

------
#### [ Go ]

```
import (
    "context"
    "fmt"
    "github.com/awslabs/amazon-qldb-driver-go/v2/qldbdriver"
)

driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) {
    result, err := txn.Execute("SELECT * FROM testTable WHERE firstName = ?", "Jim")

    if err != nil {
        panic(err)
    }

    for result.Next(txn) {
        // User code here to handle results
    }

    timingInformation := result.GetTimingInformation()
    processingTimeMilliseconds := *timingInformation.GetProcessingTimeMilliseconds()
    fmt.Println(processingTimeMilliseconds)
    return nil, nil
})
```

------
#### [ Node.js ]

```
import { ResultReadable, TimingInformation, TransactionExecutor } from "amazon-qldb-driver-nodejs";

await driver.executeLambda(async (txn: TransactionExecutor) => {
    const result: ResultReadable = await txn.executeAndStreamResults("SELECT * FROM testTable WHERE firstName = ?", "Jim");

    for await (const chunk of result) {
        // User code here to handle results
    }

    const timingInformation: TimingInformation = result.getTimingInformation();
    const processingTimeMilliseconds: number = timingInformation.getProcessingTimeMilliseconds();
});
```

------
#### [ Python ]

```
def get_processing_time_milliseconds(transaction_executor):
    cursor = transaction_executor.execute_statement("SELECT * FROM testTable WHERE firstName = ?", "Jim")

    for row in cursor:
        # User code here to handle results
        pass

    timing_information = cursor.get_timing_information()
    processing_time_milliseconds = timing_information.get('ProcessingTimeMilliseconds')

qldb_driver.execute_lambda(lambda txn: get_processing_time_milliseconds(txn))
```

------

以下代码示例显示如何从语句结果的 *缓冲指针* 中获取处理时间。这将返回来自 `ExecuteStatement`和`FetchPage` 请求的总处理时间。

------
#### [ Java ]

```
import com.amazon.ion.IonSystem;
import com.amazon.ion.IonValue;
import com.amazon.ion.system.IonSystemBuilder;
import software.amazon.qldb.Result;
import software.amazon.qldb.TimingInformation;

IonSystem ionSystem = IonSystemBuilder.standard().build();
IonValue ionFirstName = ionSystem.newString("Jim");

Result result = driver.execute(txn -> {
    return txn.execute("SELECT * FROM testTable WHERE firstName = ?", ionFirstName);
});

TimingInformation timingInformation = result.getTimingInformation();
long processingTimeMilliseconds = timingInformation.getProcessingTimeMilliseconds();
```

------
#### [ .NET ]

```
using Amazon.IonDotnet.Builders;
using Amazon.IonDotnet.Tree;
using Amazon.QLDB.Driver;
using IAsyncResult = Amazon.QLDB.Driver.IAsyncResult;

IIonValue ionFirstName = IonLoader.Default.Load("Jim");

IAsyncResult result = await driver.Execute(async txn =>
{
    return await txn.Execute("SELECT * FROM testTable WHERE firstName = ?", ionFirstName);
});

var timingInformation = result.GetTimingInformation();
var processingTimeMilliseconds = timingInformation?.ProcessingTimeMilliseconds;
```

**注意**  
要转换为同步代码，请移除 `await` 和 `async` 关键字，然后将 `IAsyncResult` 类型更改为 `IResult`。

------
#### [ Go ]

```
import (
    "context"
    "fmt"
    "github.com/awslabs/amazon-qldb-driver-go/v2/qldbdriver"
)

result, err := driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) {
    result, err :=  txn.Execute("SELECT * FROM testTable WHERE firstName = ?", "Jim")
    if err != nil {
        return nil, err
    }
    return txn.BufferResult(result)
})

if err != nil {
    panic(err)
}

qldbResult := result.(*qldbdriver.BufferedResult)
timingInformation := qldbResult.GetTimingInformation()
processingTimeMilliseconds := *timingInformation.GetProcessingTimeMilliseconds()
fmt.Println(processingTimeMilliseconds)
```

------
#### [ Node.js ]

```
import { Result, TimingInformation, TransactionExecutor } from "amazon-qldb-driver-nodejs";

const result: Result = await driver.executeLambda(async (txn: TransactionExecutor) => {
    return await txn.execute("SELECT * FROM testTable WHERE firstName = ?", "Jim");
});

const timingInformation: TimingInformation = result.getTimingInformation();
const processingTimeMilliseconds: number = timingInformation.getProcessingTimeMilliseconds();
```

------
#### [ Python ]

```
cursor = qldb_driver.execute_lambda(
    lambda txn: txn.execute_statement("SELECT * FROM testTable WHERE firstName = ?", "Jim"))

timing_information = cursor.get_timing_information()
processing_time_milliseconds = timing_information.get('ProcessingTimeMilliseconds')
```

------

**注意**  
流指针是有状态的，因为它会对结果集分页。因此，`getConsumedIOs` 和`getTimingInformation`操作会返回您调用这些指标时的累积指标。  
缓冲后的指针将结果集缓存至内存中，并返回累积的指标总数。

要了解如何查询系统目录，请继续 [查询系统目录](working.catalog.md)。