分页指南

如果有必要将结果集拆分为更小的记录集进行处理,或者因为结果集会超过允许的最大返回记录数(即 1000 条),请使用分页。 REST APIQueryResponse 提供指示结果集已拆分的值:resultTruncated$skipTokenresultTruncated 是布尔值,用于告知使用者返回的响应中是否还有其他记录。 如果 count 属性小于 totalRecords 属性,也可确定此条件。 totalRecords 定义匹配查询的记录数。

如果以下原因导致了可用资源少于查询请求的资源、禁用了分页或无法进行分页,则 resultTruncatedtrue

  • 查询包含limit or sample/take运算符。
  • 所有输出列都是 dynamicnull 类型。

如果 resultTruncatedtrue,则不会设置 $skipToken 属性。

以下示例演示了如何使用 Azure CLI 和 Azure PowerShell 跳过前 3,000 条记录,返回这些跳过的记录之后的 first 1,000 条记录:

az graph query -q "Resources | project id, name | order by id asc" --first 1000 --skip 3000
Search-AzGraph -Query "Resources | project id, name | order by id asc" -First 1000 -Skip 3000

重要

响应不包含 $skipToken 以下项:

  • 查询包含limit or sample/take运算符。
  • 所有输出列都是 dynamicnull 类型。

有关示例,请转到 REST API 文档中的下一页查询

分页限制

Azure Resource Graph 提供强大的功能,用于跨 Azure 环境查询资源。 使用需要分页的大型结果集时,了解分页在不同方案中的行为方式有助于检索一致和完整的结果。

本文介绍分页注意事项,并为在分页结果中观察到重复或缺失记录的方案提供策略。

分页限制方案:按非唯一列排序

分页结果按非唯一列排序时,即使在资源未更改的静态环境中,也可能会遇到重复或缺失的记录。 之所以发生这种情况,是因为具有相同排序值的记录没有保证的顺序,并且其位置可以在分页调用之间切换。

注释

使用 skip or first时,建议使用 asc 或 desc至少一列对结果进行排序。 不进行排序,结果是随机的,不可重复。

这种情况发生的原因

请考虑示例方案,该查询检索按位置排序的虚拟机:

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| order by location asc 
| project name, location, resourceGroup 

如果多个 VM 共享相同的位置值(例如 chinaeast2),则其相对顺序不是确定性的。 分页时:

第 1 页请求: 检索前五个虚拟机。

位置 名称 位置
1 vm-web-01 chinaeast2
2 vm-db-01 chinaeast2
3 vm-app-01 chinaeast2
4 vm-cache-01 chinaeast2
5 vm-api-01 chinaeast2

第 2 页请求: 跳过 5 条记录并检索下一个 5 条记录。

由于所有这些 VM 共享相同的位置值(chinaeast2),因此不能保证其相对顺序在分页调用中保持一致。 第二页可能会返回:

位置 名称 位置
1 vm-app-01 chinaeast2
2 vm-queue-01 chinaeast2
3 vm-monitor-01 chinanorth2
4 vm-backup-01 chinanorth2
5 vm-test-01 chinanorth2

请注意, vm-app-01 出现在这两个页面(重复)。 由于缺少排序时相同的重新排序,例如 vm-db-01 等记录可能永远不会出现在任何后续页面(缺少)。

解决方案:按唯一列排序

始终在排序顺序中包含唯一列(例如 ID),以确保确定性结果:

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| order by location asc, id asc 
| project name, location, resourceGroup

通过添加 ID(对于每个资源是唯一的)作为辅助排序列,可以建立一个稳定的确定性顺序,该顺序在分页调用中保持一致。

注释

按唯一列排序可解决不经常更改资源的静态环境中的分页不一致。 如果在添加唯一排序列后仍遇到重复或缺失的记录,则你的环境很可能在分页期间创建或删除资源。 有关处理动态环境的策略,请参阅方案 2。

分页限制方案:动态环境中的分页

如果在按唯一列排序时遇到重复记录或缺失记录,则分页期间 Azure 环境中可能发生更改的原因。 分页大型结果集时,在请求之间更改 Azure 环境可能会影响每个页面上显示的记录。

这种情况发生的原因

当资源在分页请求之间更改时,基础数据会发生变化。 请考虑以下示例方案:

第 1 页请求: 检索按 ID 排序的前 100 个虚拟机。

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| order by id asc 
| take 100

此请求从 vm-001 到 vm-100 返回具有 ID 的 VM。
在请求之间: 资源 vm-050 已从环境中删除。
第 2 页请求: 跳过前 100 条记录并检索接下来的 100 条记录。

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| order by id asc 
| skip 100 
| take 100 

由于 vm-050 已删除,因此所有后续资源都向上移动了一个位置。 资源 vm-101 现在处于 100 位置,因此当跳过 100 条记录时,结果中不包含 vm-101。

同样,如果在请求之间创建了一个新资源,则可能在结果中看到重复的记录。

动态环境的客户端策略

如果你的方案需要更一致的资源检索,请考虑以下方法之一。 这些策略以可复原更改的方式对数据进行分区,还可以通过并行执行来提高性能。

注释

这些客户端策略将分页逻辑移动到应用程序,这有助于避免前面所述的分页不一致。 但是,它们不能保证跨调用完全一致性。 可以在初始查询(用于计数或检索 ID)和后续数据提取之间添加或删除资源。 这可能会导致出现差异,例如预期计数与提取的资源总数不匹配,或者在作期间删除资源时缺少结果。 对于需要严格一致性的方案,请考虑时间点准确性是否对用例至关重要。

选项 1:基于哈希的数据分区

此方法使用哈希函数对数据进行分区,以确保多个查询中一致且不重叠的结果。 每个资源都完全属于一个基于其唯一标识符的分区。

步骤 1:获取总记录计数

首先,确定与查询匹配的记录数:

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| count 

使用计数来确定所需的分区数。 例如,如果计数返回 7,712 条记录,并且由于 Azure Resource Graph 为每个查询返回最多 1,000 条记录,则至少需要 8 个分区。

步骤 2:查询每个位置

使用 hash() 函数根据资源 ID 对数据进行分区。 单独查询每个分区:

分区 0

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| where hash(tolower(id)) % 8 == 0 

分区 1

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| where hash(tolower(id)) % 8 == 1 

通过分区 7 继续执行每个分区:

分区 7

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| where hash(tolower(id)) % 8 == 7

伪代码

步骤 1:获取总计计数和计算分区
totalCount = executeQuery("Resources | where type =~ 'microsoft.compute/virtualmachines' | count") 

numPartitions = ceiling(totalCount / 1000) 
步骤 2:为每个分区生成查询
queries = [] 

for i = 0 to numPartitions - 1: 

    queries.append("Resources 

                    | where type =~ 'microsoft.compute/virtualmachines' 

                    | where hash(tolower(id)) % {numPartitions} == {i}") 

  
步骤 3:并行执行所有查询并合并结果
allResults = executeInParallel(queries) 
优点
  • 无重复记录或未命中记录: 每个资源 ID 哈希都正好是一个分区。
  • 并行执行: 所有分区查询都可以同时运行,从而减少总查询时间。

选项 2:使用资源 ID 进行批处理

此方法首先检索所有资源 ID,然后查询小批的完整记录。 这可确保在检索完整资源数据之前具有一组一致的标识符。

步骤 1:检索所有资源 ID

使用包含 make_set() 的 summarize 检索所有资源 ID:

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| summarize make_set(id)
步骤 2:批量查询

获取资源 ID 列表后,请查询成批 1,000 或更少的完整记录:

第 1 批

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| where id in~ ('id1', 'id2', ... , 'id1000') 

第 2 批

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| where id in~ ('id1001', 'id1002', ... , 'id2000') 

继续,直到涵盖所有 ID。

优点
  • 保证完整性: 在查询详细信息之前,你有一组固定的 ID。
  • 并行执行: 批处理查询可以同时运行。

如果查询的响应很大(> 16 MB),并且不适合单个调用,建议使用前面提到的分区技术提取多个调用中的所有数据。

下面是可能超过响应大小限制 16 MB 的查询示例:

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| summarize make_set(id) 

在这种情况下,请使用分区:

分区 0

Resources 
| where type =~ 'microsoft.compute/virtualmachines' 
| where hash(tolower(id))%10 == 0 
| summarize make_set(id) 

分区 1

 Resources 
 | where type =~ 'microsoft.compute/virtualmachines' 
 | where hash(tolower(id))%10 == 1 
 | summarize make_set(id) 

....

分区 9

 Resources 
 | where type =~ 'microsoft.compute/virtualmachines' 
 | where hash(tolower(id))%10 == 9 
 | summarize make_set(id) 

总结

在本文中,你能够学习:

  • 按非唯一列排序如何在分页期间导致重复或缺失记录
  • 更改资源的动态环境如何影响分页结果
  • 客户端策略,包括使用资源 ID 进行基于哈希的分区和批处理