使用者定義的匯總函式

本文件說明如何在 BigQuery 中建立、呼叫及刪除使用者定義的匯總函式 (UDAF)。

使用 UDAF 時,您可以使用含有程式碼的運算式建立匯總函式。UDAF 會接受輸入資料欄,一次對一組資料列執行計算,然後以單一值的形式傳回計算結果。

建立 SQL UDAF

本節說明在 BigQuery 中建立永久性或暫時性 SQL UDAF 的各種方式。

建立永久性 SQL UDAF

您可以建立永久性的 SQL UDAF,也就是說,您可以在多個查詢中重複使用 UDAF。當持分者共用持久性 UDAF 時,呼叫這些 UDAF 是安全的。UDAF 無法變異資料、與外部系統通訊,或將記錄傳送至 Google Cloud Observability 或類似應用程式。

如要建立永久性 UDAF,請使用 CREATE AGGREGATE FUNCTION 陳述式,但不要使用 TEMPTEMPORARY 關鍵字。您必須在函式路徑中加入資料集。

例如,下列查詢會建立名為 ScaledAverage 的永久性 UDAF:

CREATE AGGREGATE FUNCTION myproject.mydataset.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  AVG(dividend / divisor)
);

建立暫時性 SQL UDAF

您可以建立暫時性的 SQL UDAF,也就是說,UDAF 只會存在於單一查詢、指令碼、工作階段或程序的範圍內。

如要建立臨時 UDAF,請使用 CREATE AGGREGATE FUNCTION 陳述式,並搭配 TEMPTEMPORARY 關鍵字。

舉例來說,下列查詢會建立名為 ScaledAverage 的臨時 UDAF:

CREATE TEMP AGGREGATE FUNCTION ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  AVG(dividend / divisor)
);

使用匯總和非匯總參數

您可以建立同時包含匯總和非匯總參數的 SQL UDAF。

UDAF 通常會匯總群組中所有資料列的函式參數。不過,您可以使用 NOT AGGREGATE 關鍵字,將函式參數指定為非匯總函式。

非匯總函式參數是向量函式參數,其中包含群組中所有資料列的常數值。有效的非匯總函式參數必須是常值。在 UDAF 定義中,匯總函式參數只能以匯總函式呼叫的函式引數形式顯示。非匯總函式參數的參照項目可以在 UDAF 定義的任何位置出現。

舉例來說,下列函式包含名為 dividend 的匯總參數,以及名為 divisor 的非匯總參數:

-- Create the function.
CREATE TEMP AGGREGATE FUNCTION ScaledSum(
  dividend FLOAT64,
  divisor FLOAT64 NOT AGGREGATE)
RETURNS FLOAT64
AS (
  SUM(dividend) / divisor
);

在函式主體中使用預設專案

在 SQL UDAF 的內文中,任何 BigQuery 實體的參照 (例如資料表或檢視畫面) 都必須包含專案 ID,除非實體位於包含 UDAF 的相同專案中。

例如,請看以下敘述:

CREATE AGGREGATE FUNCTION project1.dataset_a.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  ( SELECT AVG(dividend / divisor) FROM dataset_a.my_table )
);

如果您在 project1 專案中執行上述陳述式,由於 my_table 存在於 project1 中,因此陳述式會成功。不過,如果您從其他專案執行上述陳述式,陳述式就會失敗。如要修正這項錯誤,請在表格參照中加入專案 ID:

CREATE AGGREGATE FUNCTION project1.dataset_a.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  ( SELECT AVG(dividend / divisor) FROM project1.dataset_a.my_table )
);

您也可以從建立函式的專案或資料集中,參照其他專案或資料集中的實體:

CREATE AGGREGATE FUNCTION project1.dataset_a.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  ( SELECT AVG(dividend / divisor) FROM project2.dataset_c.my_table )
);

建立 JavaScript UDAF

本節將說明在 BigQuery 中建立 JavaScript UDAF 的各種方式。建立 JavaScript UDAF 時,請遵守以下幾項規則:

  • JavaScript UDAF 的內容必須是代表 JavaScript 程式碼的引號字串文字。如要進一步瞭解可使用的不同引號字串文字類型,請參閱「引號字串文字的格式」。

  • 只允許特定類型的編碼。如需更多資訊,請參閱「JavaScript UDAF 中允許的 SQL 類型編碼」。

  • JavaScript 函式主體必須包含四個 JavaScript 函式,這些函式會初始化、匯總、合併及完成 JavaScript UDAF 的結果 (initialStateaggregatemergefinalize)。如需更多資訊,請參閱「JavaScript UDAF 中允許的 SQL 型別編碼」。

  • initialState 函式傳回的任何值,或在呼叫 aggregatemerge 函式後留在 state 引數中的值,都必須可序列化。如果您想使用無法順序化的匯總資料 (例如函式或符號欄位),就必須使用內含的 serializedeserialize 函式。如需更多資訊,請參閱「在 JavaScript UDAF 中序列化和反序列化資料」。

建立永久性 JavaScript UDAF

您可以建立永久性的 JavaScript UDAF,也就是說,您可以在多個查詢中重複使用 UDAF。當持分者共用持久性 UDAF 時,您可以安全地呼叫這些 UDAF。UDAF 無法變異資料、與外部系統通訊,或將記錄傳送至 Google Cloud Observability 或類似應用程式。

如要建立永久性 UDAF,請使用 CREATE AGGREGATE FUNCTION 陳述式,但不要使用 TEMPTEMPORARY 關鍵字。您必須在函式路徑中加入資料集。

以下查詢會建立名為 SumPositive 的永久性 JavaScript UDAF:

CREATE OR REPLACE AGGREGATE FUNCTION my_project.my_dataset.SumPositive(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  export function initialState() {
    return {sum: 0}
  }
  export function aggregate(state, x) {
    if (x > 0) {
      state.sum += x;
    }
  }
  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }
  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([1.0, -1.0, 3.0, -3.0, 5.0, -5.0]) AS x)
SELECT my_project.my_dataset.SumPositive(x) AS sum FROM numbers;

/*-----*
 | sum |
 +-----+
 | 9.0 |
 *-----*/

建立暫時性 JavaScript UDAF

您可以建立臨時性的 JavaScript UDAF,也就是說,UDAF 只會存在於單一查詢、指令碼、工作階段或程序的範圍內。

如要建立臨時 UDAF,請使用 CREATE AGGREGATE FUNCTION 陳述式,並搭配 TEMPTEMPORARY 關鍵字。

以下查詢會建立名為 SumPositive 的暫時性 JavaScript UDAF:

CREATE TEMP AGGREGATE FUNCTION SumPositive(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  export function initialState() {
    return {sum: 0}
  }
  export function aggregate(state, x) {
    if (x > 0) {
      state.sum += x;
    }
  }
  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }
  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([1.0, -1.0, 3.0, -3.0, 5.0, -5.0]) AS x)
SELECT SumPositive(x) AS sum FROM numbers;

/*-----*
 | sum |
 +-----+
 | 9.0 |
 *-----*/

在 JavaScript UDAF 中加入非匯總參數

您可以建立同時包含匯總和非匯總參數的 JavaScript UDAF。

UDAF 通常會匯總群組中所有資料列的函式參數。不過,您可以使用 NOT AGGREGATE 關鍵字,將函式參數指定為非匯總函式。

非匯總函式參數是向量函式參數,其中包含群組中所有資料列的常數值。有效的非匯總函式參數必須是常值。在 UDAF 定義中,匯總函式參數只能以匯總函式呼叫的函式引數形式顯示。非匯總函式參數的參照項目可出現在 UDAF 定義的任何位置。

在以下範例中,JavaScript UDAF 包含名為 s 的匯總參數和名為 delimiter 的非匯總參數:

CREATE TEMP AGGREGATE FUNCTION JsStringAgg(
  s STRING,
  delimiter STRING NOT AGGREGATE)
RETURNS STRING
LANGUAGE js
AS r'''

  export function initialState() {
    return {strings: []}
  }
  export function aggregate(state, s) {
    state.strings.push(s);
  }
  export function merge(state, partialState) {
    state.strings = state.strings.concat(partialState.strings);
  }
  export function finalize(state, delimiter) {
    return state.strings.join(delimiter);
  }

''';

-- Call the JavaScript UDAF.
WITH strings AS (
  SELECT * FROM UNNEST(["aaa", "bbb", "ccc", "ddd"]) AS values)
SELECT JsStringAgg(values, '.') AS result FROM strings;

/*-----------------*
 | result          |
 +-----------------+
 | aaa.bbb.ccc.ddd |
 *-----------------*/

在 JavaScript UDAF 中序列化和反序列化資料

BigQuery 必須將 initialState 函式傳回的任何物件序列化,或在呼叫 aggregatemerge 函式後,將其保留在 state 引數中。如果所有欄位皆為下列其中一種,BigQuery 就會支援序列化物件:

  • JavaScript 原始值 (例如:2"abc"nullundefined)。
  • BigQuery 支援將所有欄位值序列化的 JavaScript 物件。
  • BigQuery 支援將所有元素序列化的 JavaScript 陣列。

下列傳回值可序列化:

export function initialState() {
  return {a: "", b: 3, c: null, d: {x: 23} }
}
export function initialState() {
  return {value: 2.3};
}

下列傳回值無法序列化:

export function initialState() {
  return {
    value: function() {return 6;}
  }
}
export function initialState() {
  return 2.3;
}

如果您想使用無法順序化的匯總狀態,JavaScript UDAF 必須包含 serializedeserialize 函式。serialize 函式會將匯總狀態轉換為可序列化的物件;deserialize 函式會將可序列化的物件轉換回匯總狀態。

在以下範例中,外部程式庫會使用介面計算總和:

export class SumAggregator {
 constructor() {
   this.sum = 0;
 }
 update(value) {
   this.sum += value;
 }
 getSum() {
   return this.sum;
 }
}

由於 SumAggregator 類別物件內含函式,因此無法以 BigQuery 序列化,因此下列查詢不會執行。

CREATE TEMP AGGREGATE FUNCTION F(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  class SumAggregator {
   constructor() {
     this.sum = 0;
   }

   update(value) {
     this.sum += value;
   }

   getSum() {
     return this.sum;
   }
  }

  export function initialState() {
   return new SumAggregator();
  }

  export function aggregate(agg, value) {
   agg.update(value);
  }

  export function merge(agg1, agg2) {
   agg1.update(agg2.getSum());
  }

  export function finalize(agg) {
   return agg.getSum();
  }

''';

--Error: getSum is not a function
SELECT F(x) AS results FROM UNNEST([1,2,3,4]) AS x;

如果將 serializedeserialize 函式新增至上述查詢,查詢會執行,因為 SumAggregator 類別物件會轉換為可序列化的 BigQuery 物件,然後再轉換回 SumAggregator 類別物件。

CREATE TEMP AGGREGATE FUNCTION F(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  class SumAggregator {
   constructor() {
     this.sum = 0;
   }

   update(value) {
     this.sum += value;
   }

   getSum() {
     return this.sum;
   }
  }

  export function initialState() {
   return new SumAggregator();
  }

  export function aggregate(agg, value) {
   agg.update(value);
  }

  export function merge(agg1, agg2) {
   agg1.update(agg2.getSum());
  }

  export function finalize(agg) {
   return agg.getSum();
  }

  export function serialize(agg) {
   return {sum: agg.getSum()};
  }

  export function deserialize(serialized) {
   var agg = new SumAggregator();
   agg.update(serialized.sum);
   return agg;
  }

''';

SELECT F(x) AS results FROM UNNEST([1,2,3,4]) AS x;

/*-----------------*
 | results         |
 +-----------------+
 | 10.0            |
 *-----------------*/

如要進一步瞭解序列化函式,請參閱「選用 JavaScript 序列化函式」。

在 JavaScript UDAF 中加入全域變數和自訂函式

JavaScript 函式主體可包含自訂 JavaScript 程式碼,例如 JavaScript 全域變數和自訂函式。

在 JavaScript 載入至 BigQuery 並執行 initialState 函式之前,系統會執行全域變數。如果您需要執行一次性的初始化工作,且不應針對每個匯總群組重複執行,則全域變數可能會很實用,例如 initialStateaggregatemergefinalize 函式。

請勿使用全域變數來儲存匯總狀態。請改為將匯總狀態限制在傳遞至匯出函式的物件中。請只使用全域變數來快取不屬於任何特定匯總作業的耗用大量資源的作業。

在下列查詢中,SumOfPrimes 函式會計算總和,但計算結果只包含質數。在 JavaScript 函式主體中,有兩個全域變數 primesmaxTested,會先進行初始化。此外,還有一個名為 isPrime 的自訂函式,可檢查某個數字是否為質數。

CREATE TEMP AGGREGATE FUNCTION SumOfPrimes(x INT64)
RETURNS INT64
LANGUAGE js
AS r'''

  var primes = new Set([2]);
  var maxTested = 2;

  function isPrime(n) {
    if (primes.has(n)) {
      return true;
    }
    if (n <= maxTested) {
      return false;
    }
    for (var k = 2; k < n; ++k) {
      if (!isPrime(k)) {
        continue;
      }
      if ((n % k) == 0) {
        maxTested = n;
        return false;
      }
    }
    maxTested = n;
    primes.add(n);
    return true;
  }

  export function initialState() {
    return {sum: 0};
  }

  export function aggregate(state, x) {
    x = Number(x);
    if (isPrime(x)) {
      state.sum += x;
    }
  }

  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }

  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([10, 11, 13, 17, 19, 20]) AS x)
SELECT SumOfPrimes(x) AS sum FROM numbers;

/*-----*
 | sum |
 +-----+
 | 60  |
 *-----*/

加入 JavaScript 程式庫

您可以使用 OPTIONS 子句中的 library 選項擴充 JavaScript UDAF,這個選項可讓您為 JavaScript UDAF 指定外部程式碼資料庫,然後使用 import 宣告匯入這些資料庫。

在下列範例中,bar.js 中的程式碼可供 JavaScript UDAF 函式主體中的任何程式碼使用:

CREATE TEMP AGGREGATE FUNCTION JsAggFn(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
OPTIONS (library = ['gs://foo/bar.js'])
AS r'''

  import doInterestingStuff from 'bar.js';

  export function initialState() {
    return ...
  }
  export function aggregate(state, x) {
    var result = doInterestingStuff(x);
    ...
  }
  export function merge(state, partial_state) {
    ...
  }
  export function finalize(state) {
    return ...;
  }

''';

必要的 JavaScript 結構

與 JavaScript UDF 不同的是,函式主體是針對每個資料列執行的任意形式 JavaScript,而 JavaScript UDAF 的函式主體則是 JavaScript 模組,其中包含一些內建的匯出函式,會在匯總程序的不同階段叫用。其中部分內建函式為必填,其他則為選填。您也可以新增 JavaScript 函式。

必要的 JavaScript 匯總函式

您可以加入 JavaScript 函式,但 JavaScript 函式主體必須包含下列可匯出的 JavaScript 函式:

  • initialState([nonAggregateParam]):傳回 JavaScript 物件,代表尚未匯總任何資料列的匯總狀態。

  • aggregate(state, aggregateParam[, ...][, nonAggregateParam]):匯總一列資料,並更新狀態以儲存匯總結果。不會傳回值。

  • merge(state, partialState, [nonAggregateParam]):將匯總狀態 partialState 合併至匯總狀態 state。當引擎以並行方式匯總不同資料區段,且需要合併結果時,就會使用這個函式。不會傳回值。

  • finalize(finalState, [nonAggregateParam]):在指定最終匯總狀態 finalState 的情況下,傳回匯總函式的最終結果。

如要進一步瞭解必要函式,請參閱「JavaScript UDAF 中的必要函式」。

選用的 JavaScript 序列化函式

如果您想使用無法順序化的匯總狀態,JavaScript UDAF 必須提供 serializedeserialize 函式。serialize 函式會將匯總狀態轉換為可序列化 BigQuery 的物件;deserialize 函式會將可序列化 BigQuery 的物件轉換回匯總狀態。

  • serialize(state):傳回可序列化的物件,其中包含匯總狀態中的資訊,以便透過 deserialize 函式進行反序列化。

  • deserialize(serializedState):將 serializedState (先前由 serialize 函式序列化) 反序列化為可傳入 serializeaggregatemergefinalize 函式的匯總狀態。

如要進一步瞭解內建的 JavaScript 序列化函式,請參閱「JavaScript UDAF 的序列化函式」。

如要瞭解如何使用 JavaScript UDAF 序列化和反序列化資料,請參閱「在 JavaScript UDAF 中序列化和反序列化資料」。

JavaScript UDAF 中允許的 SQL 類型編碼

在 JavaScript UDAF 中,下列支援的 GoogleSQL 資料類型代表 JavaScript 資料類型,如下所示:

GoogleSQL
資料類型
JavaScript
資料類型
附註
ARRAY Array 不支援陣列的陣列。如要克服這項限制,請使用 Array<Object<Array>> (JavaScript) 和 ARRAY<STRUCT<ARRAY>> (GoogleSQL) 資料類型。
BIGNUMERIC NumberString NUMERIC 相同。
BOOL Boolean
BYTES Uint8Array
DATE Date
FLOAT64 Number
INT64 BigInt
JSON 各種類型 GoogleSQL JSON 資料類型可轉換為 JavaScript ObjectArray 或其他 GoogleSQL 支援的 JavaScript 資料類型。
NUMERIC NumberString 如果 NUMERIC 值能夠以 IEEE 754 浮點值 (範圍 [-253, 253]) 準確表示,且沒有任何小數部分,則會編碼為 Number 資料類型,否則會編碼為 String 資料類型。
STRING String
STRUCT Object 每個 STRUCT 欄位都是 Object 資料類型中的命名屬性。系統不支援未命名的 STRUCT 欄位。
TIMESTAMP Date Date 包含微秒欄位,其中包含 TIMESTAMP 的微秒部分。

呼叫 UDAF

本節說明在 BigQuery 中建立永久性或暫時性 UDAF 後,您可以呼叫的各種方式。

呼叫永久性 UDAF

您可以以呼叫內建匯總函式的方式呼叫永久性 UDAF。詳情請參閱「匯總函式呼叫」。您必須在函式路徑中加入資料集。

在以下範例中,查詢會呼叫名為 WeightedAverage 的永久 UDAF:

SELECT my_project.my_dataset.WeightedAverage(item, weight, 2) AS weighted_average
FROM (
  SELECT 1 AS item, 2.45 AS weight UNION ALL
  SELECT 3 AS item, 0.11 AS weight UNION ALL
  SELECT 5 AS item, 7.02 AS weight
);

系統會產生包含下列結果的資料表:

/*------------------*
 | weighted_average |
 +------------------+
 | 4.5              |
 *------------------*/

呼叫臨時 UDAF

您可以以呼叫內建匯總函式的方式呼叫暫時性 UDAF。詳情請參閱「匯總函式呼叫」。

臨時函式必須包含在包含 UDAF 函式呼叫的多陳述式查詢程序中。

在以下範例中,查詢會呼叫名為 WeightedAverage 的臨時 UDAF:

CREATE TEMP AGGREGATE FUNCTION WeightedAverage(...)

-- Temporary UDAF function call
SELECT WeightedAverage(item, weight, 2) AS weighted_average
FROM (
  SELECT 1 AS item, 2.45 AS weight UNION ALL
  SELECT 3 AS item, 0.11 AS weight UNION ALL
  SELECT 5 AS item, 7.02 AS weight
);

系統會產生包含下列結果的資料表:

/*------------------*
 | weighted_average |
 +------------------+
 | 4.5              |
 *------------------*/

忽略或納入含有 NULL 值的資料列

當您使用 IGNORE NULLS 引數呼叫 JavaScript UDAF 時,如果任何匯總引數評估為 NULL,BigQuery 會自動略過該資料列。這類資料列會完全從匯總中排除,且不會傳遞至 JavaScript aggregate 函式。提供 RESPECT NULLS 引數時,系統會停用 NULL 篩選,並將每個資料列傳遞至 JavaScript UDAF,不論 NULL 值為何。

如果未提供 IGNORE NULLSRESPECT NULLS 引數,預設引數為 IGNORE NULLS

以下範例說明預設 NULL 行為、IGNORE NULLS 行為和 RESPECT NULLS 行為:

CREATE TEMP AGGREGATE FUNCTION SumPositive(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  export function initialState() {
    return {sum: 0}
  }
  export function aggregate(state, x) {
    if (x == null) {
      // Use 1000 instead of 0 as placeholder for null so
      // that NULL values passed are visible in the result.
      state.sum += 1000;
      return;
    }
    if (x > 0) {
      state.sum += x;
    }
  }
  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }
  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([1.0, 2.0, NULL]) AS x)
SELECT
  SumPositive(x) AS sum,
  SumPositive(x IGNORE NULLS) AS sum_ignore_nulls,
  SumPositive(x RESPECT NULLS) AS sum_respect_nulls
FROM numbers;

/*-----+------------------+-------------------*
 | sum | sum_ignore_nulls | sum_respect_nulls |
 +-----+------------------+-------------------+
 | 3.0 | 3.0              | 1003.0            |
 *-----+------------------+-------------------*/

刪除 UDAF

本節說明在 BigQuery 中建立永久或暫時性 UDAF 後,您可以透過哪些方式刪除這些函式。

刪除永久 UDAF

如要刪除永久性 UDAF,請使用 DROP FUNCTION 陳述式。您必須在函式路徑中加入資料集。

在下列範例中,查詢會刪除名為 WeightedAverage 的永久 UDAF:

DROP FUNCTION IF EXISTS my_project.my_dataset.WeightedAverage;

刪除暫時性 UDAF

如要刪除暫時性 UDAF,請使用 DROP FUNCTION 陳述式

在下列範例中,查詢會刪除名為 WeightedAverage 的暫時性 UDAF:

DROP FUNCTION IF EXISTS WeightedAverage;

暫時性 UDAF 會在查詢完成時立即失效。除非您想提早從多個陳述式查詢程序中移除 UDAF,否則不需要刪除 UDAF。

列出 UDAF

UDAF 是一種處理常式。如要列出資料集中的所有常式,請參閱「列出常式」。

效能提示

如要改善查詢成效,請考慮下列事項:

  • 預先篩選輸入內容。在 JavaScript 中處理資料的成本比在 SQL 中處理的成本高,因此建議您盡可能先在 SQL 中篩選輸入內容。

    下列查詢效率較低,因為它會在 UDAF 呼叫中使用 x > 0 篩選輸入內容:

    SELECT JsFunc(x) FROM t;
    

    下列查詢的效率較高,因為在呼叫 UDAF 之前,會使用 WHERE x > 0 預先篩選輸入內容:

    SELECT JsFunc(x) FROM t WHERE x > 0;
    
  • 盡量使用內建匯總函式,而非 JavaScript。在 JavaScript 中重新實作內建的匯總函式,速度會比呼叫執行相同功能的內建匯總函式慢。

    以下查詢實作 UDAF,因此效率較低:

    SELECT SumSquare(x) FROM t;
    

    以下查詢的效率較高,因為它實作內建函式,可產生與先前查詢相同的結果:

    SELECT SUM(x*x) FROM t;
    
  • JavaScript UDAF 適合用於無法透過內建函式表達的更複雜匯總作業。

  • 有效率地使用記憶體。JavaScript 處理環境限制了每個查詢可用的記憶體。如果 JavaScript UDAF 查詢累積過多本機狀態,可能會因記憶體耗盡而失敗。請特別注意盡可能縮小匯總狀態物件的大小,並避免累積大量資料列的匯總狀態。

    下列查詢效率不佳,因為在處理的資料列數量變多時,aggregate 函式會使用無限量的記憶體。

    export function initialState() {
      return {rows: []};
    }
    export function aggregate(state, x) {
      state.rows.push(x);
    }
    ...
    
  • 盡可能使用分區資料表。與非分區資料表相比,JavaScript UDAF 通常在查詢分區資料表時執行效率更高,因為分區資料表會將資料儲存在許多較小的檔案中,而非分區資料表則會將資料儲存在較大的檔案中,因此分區資料表可提供更高的平行處理能力。

限制

  • UDAF 適用的限制與 UDF 相同。詳情請參閱「UDF 限制」。

  • 只有常值、查詢參數和腳本變數可做為 UDAF 的非匯總引數傳入。

  • 系統不支援在 JavaScript UDAF 函式呼叫中使用 ORDER BY 子句。

    SELECT MyUdaf(x ORDER BY y) FROM t; -- Error: ORDER BY is unsupported.
    

定價

系統會根據標準 BigQuery 定價模式收取 UDAF 費用。

配額與限制

UDAF 適用的配額和限制與 UDF 相同。如要瞭解 UDF 配額,請參閱「配額與限制」。