查询限制

Kusto 是一个即席查询引擎,它承载着大型数据集,并尝试通过在内存中保留所有相关数据来满足查询。 存在一个固有的风险,即查询会无限地独占服务资源。 Kusto 以默认查询限制的形式提供若干内置保护。 如果要考虑消除这些限制,请首先确定这样做实际上是否会带来任何价值。

对请求并发的限制

“请求并发”是指群集对同时运行的若干请求施加的限制。

  • 此限制的默认值取决于运行群集的 SKU,并按以下方式计算:Cores-Per-Node x 10
    • 例如,对于在 D14v2 SKU 上设置的群集(其中每台计算机都有 16 Vcore),默认限制为 16 cores x10 = 160
  • 可通过配置 default 工作负荷组的请求速率限制策略来更改默认值。
    • 可以在群集上并发运行的实际请求数取决于不同的因素。 最主要的因素是群集 SKU、群集的可用资源和使用模式。 可以根据对类生产使用模式执行的负载测试来配置策略。

有关详细信息,请参阅使用 Azure 数据资源管理器进行优化以实现高并发性

有关结果集大小的限制(结果截断)

结果截断是针对查询返回的结果集默认设置的限制。 Kusto 将返回给客户端的记录数限制为 500,000,将这些记录的总数据大小限制为 64 MB。 当超出其中任一限制时,查询将失败并显示“部分查询失败”。 超出总数据大小将生成包含以下消息的异常:

The Kusto DataEngine has failed to execute a query: 'Query result set has exceeded the internal data size limit 67108864 (E_QUERY_RESULT_SET_TOO_LARGE).'

超出记录数则会失败,并会显示以下异常:

The Kusto DataEngine has failed to execute a query: 'Query result set has exceeded the internal record count limit 500000 (E_QUERY_RESULT_SET_TOO_LARGE).'

有多个策略可用于处理此错误。

  • 将查询修改为仅返回令人感兴趣的数据,从而减小结果集的大小。 当初始的失败查询范围太广时,此策略非常有用。 例如,查询未抛弃不需要的数据列。
  • 通过将查询后处理(例如聚合)切换到查询本身中来减小结果集的大小。 如果要将查询输出馈送到另一个处理系统,再由该系统执行其他聚合,此策略很有用。
  • 要从服务中导出大量数据时,请从查询切换到使用数据导出
  • 使用下面列出的 set 语句或客户端请求属性中的标志来指示服务取消此查询限制。

用于减小查询生成的结果集大小的方法包括:

你可以通过使用 notruncation 请求选项来禁用结果截断。 建议你仍然实施某种形式的限制。

例如:

set notruncation;
MyTable | take 1000000

还可以通过设置 truncationmaxsize(以字节为单位的最大数据大小,默认为 64 MB)和 truncationmaxrecords(最大记录数,默认为 500,000)的值,对结果截断进行更精确的控制。 例如,以下查询设置在达到 1,105 条记录或 1 MB 时截断超出限制的结果。

set truncationmaxsize=1048576;
set truncationmaxrecords=1105;
MyTable | where User=="UserId1"

去除结果截断限制意味着你打算将大量数据移出 Kusto。

你可以去除结果截断限制,以方便使用 .export 命令进行导出,或方便以后进行聚合。 如果选择稍后进行聚合,请考虑使用 Kusto 进行聚合。

Kusto 提供的许多客户端库能够以将“无限大的”结果流式传输给调用方的方式来处理这些结果。 请使用这些库中的一个,并将其配置为流式传输模式。 例如,使用 .NET Framework 客户端 (Microsoft.Azure.Kusto.Data),并将连接字符串的 streaming 属性设置为 true,或使用始终会流式传输结果的 ExecuteQueryV2Async() 调用。 有关如何使用 ExecuteQueryV2Async() 的示例,请参阅 HelloKustoV2 应用程序。

你可能还会发现 C# 流引入示例应用程序很有帮助。

默认情况下,结果截断不仅仅应用于返回给客户端的结果流。 默认情况下,它还应用于跨群集查询中一个群集向另一个群集发出的任何子查询,并具有类似的效果。

设置多个结果截断属性

使用 set 语句时,并且/或者当在客户端请求属性中指定标志时,以下情况适用。

  • 如果设置了 notruncation,并且还设置了 truncationmaxsizetruncationmaxrecordsquery_take_max_records,则会忽略 notruncation
  • 如果多次设置了 truncationmaxsizetruncationmaxrecords 和/或 query_take_max_records,则采用每个属性的下限值。

查询运算符消耗的内存限制 (E_RUNAWAY_QUERY)

Kusto 会限制每个查询运算符可消耗的内存,以防止查询“失控”。 某些查询运算符可能会达到此限制,例如 joinsummarize,它们在运算时会在内存中保存极大量的数据。 默认情况下,限制为 5GB(每个群集节点),可以通过设置请求选项 maxmemoryconsumptionperiterator 来提高限制:

set maxmemoryconsumptionperiterator=68719476736;
MyTable | summarize count() by Use

达到此限制时,将触发部分查询失败并显示一条包含文本 E_RUNAWAY_QUERY 的消息。

The ClusterBy operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete E_RUNAWAY_QUERY.

The DemultiplexedResultSetCache operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The ExecuteAndCache operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The HashJoin operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The Sort operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The Summarize operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The TopNestedAggregator operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The TopNested operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

如果多次设置了 maxmemoryconsumptionperiterator(例如在两个客户端请求属性中使用 set 语句设置),将应用较小的值。

可能触发 E_RUNAWAY_QUERY 部分查询失败的附加限制是单个运算符保存的字符串的最大累积大小限制。 上面的请求选项不能替代此限制:

Runaway query (E_RUNAWAY_QUERY). Aggregation over string column exceeded the memory budget of 8GB during evaluation.

超过此限制时,相关查询运算符很可能是 joinsummarizemake-series。 若要解决该限制,应修改查询以使用随机排布查询策略。 (这还有可能会提高查询性能。)

在发生 E_RUNAWAY_QUERY 的所有情况下,一个附加选项(除了通过设置请求选项和更改查询以使用随机排布策略来提高限制之外)是切换到采样。 下面的两个查询展示了如何进行采样。 第一个查询是使用随机数生成器的统计性采样。 第二个查询是确定性采样,通过对数据集中的某些列(通常是某个 ID)进行哈希处理来完成。

T | where rand() < 0.1 | ...

T | where hash(UserId, 10) == 1 | ...

每个节点的内存限制

每个节点每个查询的最大内存是用于防范“失控”查询的另一个限制。 此限制通过请求选项 max_memory_consumption_per_query_per_node 表示,用于设置可以在单个节点上用于特定查询的内存量的上限。

set max_memory_consumption_per_query_per_node=68719476736;
MyTable | ...

如果多次设置了 max_memory_consumption_per_query_per_node(例如在两个客户端请求属性中使用 set 语句设置),将应用较小的值。

如果查询使用 summarizejoinmake-series 运算符,可以使用随机执行查询策略来减轻单台计算机的内存压力。

限制执行超时

服务器超时是应用于所有请求的服务端超时。 Kusto 中的多个点针对运行中的请求(查询和管理命令)强制实施了超时限制:

  • 客户端库(如果使用)
  • 接受请求的服务终结点
  • 处理请求的服务引擎

默认情况下,查询超时设置为 4 分钟,管理命令超时设置为 10 分钟。 如果需要,可以增大该值(上限为 1 小时)。

  • 多种客户端工具支持将超时更改为其全局或每个连接设置的一部分。 例如,在 Kusto.Explorer 中,使用“工具”>“选项”*>“连接”>“查询服务器超时”。
  • 以编程方式,SDK 支持通过 servertimeout 属性设置超时。 例如,在 .NET SDK 中,可以通过客户端请求属性,设置类型 System.TimeSpan 的值来完成此操作。

有关超时的说明

  • 在客户端,超时将从创建请求时开始算起,直到响应开始到达客户端为止。 在客户端上读回有效负载所花费的时间不计入超时。 这取决于调用方从流中拉取数据的速度。
  • 此外,在客户端使用的实际超时值略高于用户所请求的服务器超时值。 此差异考虑了网络延迟。
  • 若要自动使用允许的最大请求超时,请将客户端请求属性 norequesttimeout 设置为 true

注意

有关如何在 Azure 数据资源管理器 Web UI、Kusto.Explorer、Kusto.Cli、Power BI 中以及在使用 SDK 时设置超时的分步指南,请参阅设置超时限制

对查询 CPU 资源使用量的限制

Kusto 允许你在运行查询时使用群集拥有的全部 CPU 资源。 如果有多个查询正在运行,它会尝试在查询之间进行公平的轮循。 对于查询定义的函数,此方法可以实现最佳性能。 在其他时候,你可能希望限制用于特定查询的 CPU 资源。 例如,如果你运行“后台作业”,系统可能会容忍更高的延迟,以便向并发内联查询授予高优先级。

Kusto 支持在运行查询时指定两个请求属性。 属性为 query_fanout_threads_percent 和 query_fanout_nodes_percent 。 这两个属性都是默认值为最大值 (100) 的整数,但对于特定查询,可以将其降低为某个其他值。

第一个属性 query_fanout_threads_percent 控制线程使用的扇出因子。 如果将此属性设置为 100%,则群集将分配每个节点上的所有 CPU。 例如,在 Azure D14 节点上部署的群集上的 16 个 CPU。 如果将此属性设置为 50%,则将使用一半的 CPU,依此类推。 数值向上舍入到整数个 CPU,因此将属性值设置为 0 是安全的。

第二个属性 query_fanout_nodes_percent 控制每个子查询分发操作将使用群集中的多少个查询节点。 它以类似的方式工作。

如果多次设置 query_fanout_nodes_percentquery_fanout_threads_percent(例如在两个客户端请求属性中使用 set 语句设置),将应用每个属性的较小值。

有关查询复杂性的限制

在查询执行期间,查询文本将转换为表示查询的关系运算符的树。 如果树深度超出了内部阈值,则查询会被视为太复杂,无法处理,因此会失败并显示错误代码。 此失败表示关系运算符树超出了其限制。

下面的示例显示了可能导致查询超过此限制并失败的常见查询模式:

  • 链接在一起的二元运算符的长列表。 例如:
T 
| where Column == "value1" or 
        Column == "value2" or 
        .... or
        Column == "valueN"

对于此特定案例,请使用 in() 运算符来重新编写查询。

T 
| where Column in ("value1", "value2".... "valueN")
  • 具有运行过宽架构分析的联合运算符的查询,尤其是,联合的默认风格是返回“外层”联合架构(这意味着,输出将包括基础表的所有列)。

在这种情况下,建议评审查询并减少查询所用的列数。