如果有必要将结果集拆分为更小的记录集进行处理,或者因为结果集会超过允许的最大返回记录数(即 1000 条),请使用分页。
REST APIQueryResponse 提供指示结果集已拆分的值:resultTruncated 和 $skipToken。
resultTruncated 是布尔值,用于告知使用者返回的响应中是否还有其他记录。 如果 count 属性小于 totalRecords 属性,也可确定此条件。
totalRecords 定义匹配查询的记录数。
如果以下原因导致了可用资源少于查询请求的资源、禁用了分页或无法进行分页,则 resultTruncated 为 true:
- 查询包含
limitorsample/take运算符。 - 所有输出列都是
dynamic或null类型。
如果 resultTruncated 为 true,则不会设置 $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 以下项:
- 查询包含
limitorsample/take运算符。 - 所有输出列都是
dynamic或null类型。
有关示例,请转到 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 进行基于哈希的分区和批处理