Einführung in Slot-Autoscaling

Reservierungen, die Sie für die Verwendung von Slot-Autoscaling konfigurieren, skalieren die zugewiesene Kapazität automatisch, um Ihre Arbeitslastanforderungen zu erfüllen. Wenn Ihre Arbeitslast zu- oder abnimmt, passt BigQuery Ihre Slots dynamisch an das entsprechende Niveau an. Reservierungen mit Slot-Autoscaling sind nur in BigQuery-Versionen verfügbar.

Autoscaling-Reservierungen verwenden

Sie müssen Slot-Zusicherungen nicht erwerben, bevor Sie Autoscaling-Reservierungen erstellen. Slot-Zusicherungen bieten einen ermäßigten Preis für konsistent verwendete Slots, sind aber bei Autoscaling-Reservierungen optional. Zum Erstellen einer Autoscaling-Reservierung weisen Sie einer Reservierung eine maximale Anzahl von Slots (die maximale Reservierungsgröße) zu. Sie können die maximale Anzahl von Autoscaling-Slots ermitteln. Dazu ziehen Sie die maximale Reservierungsgröße von allen optionalen Referenz-Slots ab, die der Reservierung zugewiesen sind.

Beachten Sie beim Erstellen von Autoscaling-Reservierungen Folgendes:

  • BigQuery skaliert Reservierungen um ein Vielfaches von 100, bis die Anzahl der Slots erreicht ist, die zum Ausführen der Jobs erforderlich sind, oder die maximale Anzahl an für die Reservierung verfügbaren Slots erreicht ist.
  • Das Hochskalieren basiert auf einer Schätzung und kann zu einer Über- oder Unterdimensionierung führen. Beispielsweise kann Autoscaling auf 500 Slots skalieren, wenn nur 400 benötigt werden, oder eine kleine Menge skalieren, wenn die Arbeitslast ohne Skalierung verarbeitet werden kann.
  • Ihre automatisch skalierten Slots werden bei der vertikalen Skalierung zum Preis für die Kapazitätsberechnung für Ihre Version abgerechnet. Ihnen wird die Anzahl der skalierten Slots in Rechnung gestellt, nicht die Anzahl der verwendeten Slots. Diese Gebühr gilt auch dann, wenn der Job, der BigQuery hochskaliert, fehlschlägt.
  • Die Skalierung der Anzahl der Slots erfolgt zwar immer in Schritten von 100, es können aber auch mehr als 100 Slots in einem Schritt skaliert werden. Wenn Ihre Arbeitslast beispielsweise zusätzliche 450 Slots benötigt, kann BigQuery versuchen, gleichzeitig um 500 Slots zu skalieren, um die Kapazitätsanforderungen zu erfüllen.
  • BigQuery skaliert herunter, wenn die zugewiesenen Slots die Anzahl der erforderlichen Slots überschreiten und die Autoscaling-Kapazität seit einiger Zeit stabil ist.

Informationen zur Arbeit mit Autoscaling finden Sie unter Mit Slot-Autoscaling arbeiten.

Reservierungen mit Baseline- und Autoscaling-Slots verwenden

Zusätzlich zur maximalen Reservierungsgröße können Sie optional eine Basisanzahl von Slots pro Reservierung angeben. Die Referenz ist die Mindestanzahl an Slots, die immer der Reservierung zugewiesen werden. Diese werden Ihnen immer in Rechnung gestellt. Autoscaling-Slots werden erst hinzugefügt, wenn alle Referenz-Slots (und gegebenenfalls inaktive Slots) verbraucht wurden. Sie können inaktive Referenz-Slots in einer Reservierung für andere Reservierungen freigeben, die Kapazitäten benötigen.

Sie können die Anzahl der Referenz-Slots in einer Reservierung alle paar Minuten erhöhen. Wenn Sie die Referenz-Slots verringern möchten, ist die Anzahl auf eine Stunde begrenzt, wenn Sie die Kapazität der Referenz-Slots kürzlich geändert haben und die Referenz-Slots die zugesicherten Slots überschreiten. Andernfalls können Sie die Referenz-Slots alle paar Minuten verringern.

Referenz- und Autoscaling-Slots sollen Kapazitäten basierend auf Ihrer letzten Arbeitslast bereitstellen. Wenn Sie eine große Arbeitslast erwarten, die sich stark von Ihren Arbeitslasten in der jüngeren Vergangenheit unterscheidet, empfehlen wir, Ihre Referenzkapazität vor dem Ereignis zu erhöhen, anstatt sich auf Autoscaling-Slots zu verlassen, um die Arbeitslastkapazität abzudecken.

Wenn die Reservierung keine Referenz-Slots hat oder nicht so konfiguriert ist, dass inaktive Slots aus anderen Reservierungen übernommen werden, versucht BigQuery zu skalieren. Andernfalls müssen Referenz-Slots vor der Skalierung vollständig ausgelastet sein.

Reservierungen verwenden und fügen Slots in der folgenden Priorität hinzu:

  1. Referenz-Slots:
  2. Freigabe inaktiver Slots (falls aktiviert). Reservierungen können nur inaktive Referenz- oder zugesicherte Slots aus anderen Reservierungen teilen, die mit derselben Version und in derselben Region erstellt wurden.
  3. Autoscaling-Slots:

Im folgenden Beispiel werden Slots von einem angegebenen Referenzbetrag skaliert. Die Reservierungen etl und dashboard haben eine Basisgröße von 700 bzw. 300 Slots.

Beispiel für Autoscaling ohne Zusicherungen.

In diesem Beispiel kann die Reservierung etl auf 1.300 Slots (700 Referenz-Slots plus 600 Autoscaling-Slots) skaliert werden. Wenn die Reservierung dashboard nicht verwendet wird, kann die Reservierung etl die 300 Slots aus der Reservierung dashboard verwenden, wenn dort kein Job ausgeführt wird, was zu einer maximalen Anzahl von 1600 möglichen Slots führt.

Die Reservierung dashboard kann auf 1.100 Slots (300 Referenz-Slots plus 800 Autoscaling-Slots) skaliert werden. Wenn die Reservierung etl vollständig inaktiv ist, kann die Reservierung dashboard auf maximal 1.800 Slots skaliert werden (300 Baseline-Slots plus 800 Autoscale-Slots plus 700 ungenutzte Slots in der etl-Reservierung).

Wenn für die etl-Reservierung mehr als 700 Referenz-Slots erforderlich sind, die immer verfügbar sind, wird versucht, Slots mit den folgenden Methoden der Reihe nach hinzuzufügen:

  1. 700 Referenz-Slots:
  2. Inaktiver Slot mit den 300 Referenz-Slots in der dashboard-Reservierung. Ihre Reservierung teilt nur inaktive Referenz-Slots mit anderen Reservierungen, die mit derselben Version erstellt werden.
  3. 600 zusätzliche Slots auf die maximale Reservierungsgröße hochskalieren

Slot-Zusicherungen verwenden

Das folgende Beispiel zeigt das Autoscaling von Slots mit Kapazitätszusicherungen.

Beispiel für eine automatische Skalierung

Wie Reservierungs-Baselines können Sie mit Slot-Zusicherungen eine feste Anzahl an Slots zuweisen, die allen Reservierungen zur Verfügung stehen. Im Gegensatz zu Referenz-Slots kann eine Zusicherung während der Laufzeit nicht reduziert werden. Slot-Zusicherungen sind optional, können jedoch Kosten sparen, wenn Referenz-Slots für einen längeren Zeitraum erforderlich sind.

In diesem Beispiel wird Ihnen ein vordefinierter Preis für die Slots für die Kapazitätszusicherung berechnet. Ihnen wird die Autoscaling-Rate für die Anzahl der Autoscaling-Slots in Rechnung gestellt, nachdem Autoscaling aktiviert ist und Reservierungen sich in einem erweiterten Status befinden. Für die Autoscaling-Rate wird Ihnen die Anzahl der skalierten Slots berechnet, nicht die Anzahl der verwendeten Slots.

Maximal verfügbare Slots

Sie können die maximale Anzahl von Slots, die eine Reservierung verwenden kann, berechnen. Dazu fügen Sie die Referenz-Slots, die maximale Anzahl von Autoscaling-Slots und alle Slots in Zusicherungen hinzu, die mit der gleichen Version erstellt wurden und nicht durch die Referenz-Slots abgedeckt sind. Das Beispiel in der vorherigen Abbildung ist so eingerichtet:

  • Eine Kapazitätszusicherung von 1.000 Slots pro Jahr. Diese Slots werden in der Reservierung etl und der Reservierung dashboard als Referenz-Slots zugewiesen.
  • 700 Referenz-Slots, die der Reservierung etl zugewiesen sind.
  • 300 Referenz-Slots, die der Reservierung dashboard zugewiesen sind.
  • Skalieren Sie Slots von 600 für die Reservierung etl automatisch.
  • Skalieren Sie Slots von 800 für die Reservierung dashboard automatisch.

Für die Reservierung etl entspricht die maximal mögliche Anzahl von Slots den etl-Referenz-Slots (700) plus den Referenz-Slots dashboard (300, wenn alle Slots inaktiv sind) plus der maximalen Anzahl von Autoscale-Slots (600). Die maximale Anzahl von Slots, die die Reservierung etl in diesem Beispiel verwenden könnte, ist also 1.600. Diese Zahl überschreitet die Zahl in der Kapazitätszusicherung.

Im folgenden Beispiel überschreitet die jährliche Zusicherung die zugewiesenen Referenz-Slots.

Verfügbare Slots berechnen

In diesem Beispiel ist:

  • Eine Kapazitätszusicherung von 1.600 Slots pro Jahr.
  • Maximale Reservierungsgröße von 1.500 (einschließlich 500 Autoscaling-Slots).
  • 1.000 Referenz-Slots, die der Reservierung etl zugewiesen sind.

Die maximale Anzahl der für die Reservierung verfügbaren Slots entspricht den Referenz-Slots (1.000) plus der Anzahl der zugesicherten inaktiven Slots, die nicht den Referenz-Slots zugeordnet sind (1.600 Slots pro Jahr – 1.000 Referenz-Slots = 600) plus der Anzahl der Autoscaling-Slots (500). Die maximalen potenzielle Slots in dieser Reservierung beträgt also 2.100. Die automatisch skalierten Slots sind zusätzliche Slots, die über die Kapazitätszusicherung hinausgehen.

Best Practices für das Autoscaling

  1. Legen Sie bei der erstmaligen Verwendung des Autoscalings die Anzahl der Autoscaling-Slots anhand der bisherigen und erwarteten Leistung auf einen sinnvollen Wert fest. Beobachten Sie nach dem Erstellen der Reservierung aktiv die Fehlerrate, Leistung und Rechnung und passen Sie die Anzahl der Autoscaling-Slots nach Bedarf an.

  2. Beachten Sie, dass Ihnen die Anzahl der skalierten Slots in Rechnung gestellt wird, nicht die Anzahl der verwendeten Slots. Wenn die maximale Anzahl von Autoscaling-Slots zu groß ist, kann BigQuery mehr als erforderlich skalieren, wodurch zusätzliche Kosten entstehen.

    Ein Job kann beispielsweise eine große Anzahl von Slots an einem Punkt verwenden, aber dann nur eine deutlich kleinere Anzahl benötigen. Da BigQuery nicht verwendete Slots nicht sofort veröffentlicht, kann dies zu einer geringeren Auslastung führen, wenn keine anderen Jobs in der Reservierung diese Slots verwenden können. Durch Reduzierung des Maximalwerts für eine Reservierung wird die maximale Anzahl der zugewiesenen Slots reduziert, wodurch die Job-Slot-Nutzung geringer ausfällt und die Jobauslastung von zugewiesenen Slots verbessert wird.

  3. Die Slot-Nutzung kann gelegentlich die Summe Ihrer Referenz plus der skalierten Slots überschreiten. Ihnen werden keine Slot-Nutzung in Rechnung gestellt, die über Ihrer Referenz liegt, plus die skalierten Slots.

  4. Autoscaling ist am besten für große Arbeitslasten mit langer Laufzeit geeignet, z. B. für Arbeitslasten mit mehreren gleichzeitigen Abfragen. Vermeiden Sie es, Abfragen einzeln an das Backend zu senden, unabhängig davon, ob diese Abfragen den Cache verwenden. Ohne Referenz-Slots kann dies zu einer unerwarteten Skalierung führen und hohe Kosten verursachen.

  5. BigQuery-Autoscaling unterliegt der Kapazitätsverfügbarkeit. BigQuery versucht, den Kapazitätsbedarf der Kunden anhand ihrer bisherigen Nutzung zu decken. Zum Erreichen von Kapazitätsgarantien können Sie eine optionale Slot-Basis festlegen, die die Anzahl der garantierten Slots in einer Reservierung angibt. Mit Baselines sind Slots sofort verfügbar. Sie werden unabhängig davon von Ihnen bezahlt, ob Sie sie verwenden oder nicht. Wenden Sie sich einige Wochen im Voraus an das BigQuery-Team, damit die Kapazität für große, unorganische Anforderungen, z. B. an Feiertagen mit hohem Traffic, verfügbar ist.

  6. Für Baseline-Slots werden immer Gebühren berechnet. Wenn eine Kapazitätszusicherung abläuft, müssen Sie die Anzahl der Baseline-Slots in Ihren Reservierungen möglicherweise manuell anpassen, um unerwünschte Gebühren zu vermeiden. Sie haben beispielsweise eine einjährige Nutzungszusicherung mit 100 Slots und eine Reservierung mit 100 Baseline-Slots. Die Zusicherung läuft ab und hat keinen Verlängerungsplan. Nach Ablauf der Zusicherung zahlen Sie 100 Baseline-Slots zum Pay as you go-Preis.

Autoscaling überwachen

Wenn Sie die Slotnutzung mit administrativen Ressourcentabellen überwachen, sehen Sie möglicherweise deutlich mehr skalierte Slots als Ihre Slotnutzung, da die Tabellen die Anzahl der genutzten Slots über den Ausrichtungszeitraum glätten. Wenn Sie die Nutzung von Autoscaling-Slots mit detaillierteren Informationen aufrufen möchten, reduzieren Sie den Zeitraum. Dadurch wird der Ausrichtungszeitraum automatisch auf eine kleinere Schrittgröße aktualisiert.

Im folgenden Beispiel zeigt das Diagramm deutlich mehr skalierte Slots als die Arbeitslast erfordert.

Der Ausrichtungszeitraum wird auf ein Intervall von einer Minute festgelegt und die skalierten Slots erscheinen mehr, als die Slotnutzung erfordert.

Wenn Sie die Zeitraumoption jedoch so verkürzen, dass der Ausrichtungszeitraum zwei Sekunden beträgt, können Sie sehen, dass das Autoscaling auf die Arbeitslastnachfrage skaliert und präzisere Daten anzeigt. Sie können die Zeitraumoption anpassen, indem Sie den Start- und Endbereich der Zeitraumoption ziehen. Wählen Sie aus der Liste Messwert p90 oder p99 aus, um die genauesten Daten zur Arbeitslastnachfrage anzuzeigen

Der Ausrichtungszeitraum ist auf ein Intervall von zwei Sekunden festgelegt und die skalierten Slots sind für die Arbeitslastnachfrage geeignet.

Für eine genaue Ansicht der Autoscaling-Nutzung verwenden Sie einen Ausrichtungszeitraum zwischen 1 und 15 Sekunden. Weitere Informationen zum Ausrichtungszeitraum von administrativen Ressourcendiagrammen finden Sie unter Zeitraumoption.

Informationen zur Anzeige Ihrer Slot-Nutzung finden Sie unter Diagramme zu administrativen Ressourcen ansehen.

Autoscaling mit Informationsschema überwachen

Mit den folgenden SQL-Skripts können Sie die abgerechneten Slotsekunden für eine bestimmte Version prüfen. Sie müssen diese Skripts in demselben Projekt ausführen, in dem die Reservierungen erstellt wurden. Das erste Skript zeigt abgerechnete Slotsekunden, die von commitment_plan abgedeckt werden, während das zweite Skript abgerechnete Slotsekunden anzeigt, die nicht von einer Zusicherung abgedeckt sind.

Sie müssen nur den Wert von drei Variablen festlegen, um diese Skripts auszuführen:

  • start_time
  • end_time
  • edition_to_check

Diese Skripts unterliegen den folgenden Einschränkungen:

  • Gelöschte Reservierungen und Kapazitätszusicherungen werden am Ende der Datenaufbewahrungsdauer aus den Informationsschemaansichten entfernt. Geben Sie ein aktuelles Zeitfenster an, das keine gelöschten Reservierungen und Zusicherungen für korrekte Ergebnisse enthält.

  • Das Ergebnis der Skripts stimmt aufgrund kleiner Rundungsfehler möglicherweise nicht genau mit der Rechnung überein.

Das folgende Skript prüft die Slot-Nutzung, die durch Zusicherungen für eine bestimmte Version abgedeckt wird.

Maximieren, um das Skript für abgedeckte Szenarien aufzurufen

DECLARE start_time,end_time TIMESTAMP;

DECLARE
  edition_to_check STRING;

/* Google uses Pacific Time to calculate the billing period for all customers,
regardless of their time zone. Use the following format if you want to match the
billing report. Change the start_time and end_time values to match the desired
window. */

/* The following three variables (start_time, end_time, and edition_to_check)
are the only variables that you need to set in the script.

During daylight savings time, the start_time and end_time variables should
follow this format: 2024-02-20 00:00:00-08. */

SET start_time = "2023-07-20 00:00:00-07";
SET end_time = "2023-07-28 00:00:00-07";
SET edition_to_check = 'ENTERPRISE';

/* The following function returns the slot seconds for the time window between
two capacity changes. For example, if there are 100 slots between (2023-06-01
10:00:00, 2023-06-01 11:00:00), then during that window the total slot seconds
will be 100 * 3600.

This script calculates a specific window (based on the variables defined above),
which is why the following script includes script_start_timestamp_unix_millis
and script_end_timestamp_unix_millis. */

CREATE TEMP FUNCTION
GetSlotSecondsBetweenChanges(
  slots FLOAT64,
  range_begin_timestamp_unix_millis FLOAT64,
  range_end_timestamp_unix_millis FLOAT64,
  script_start_timestamp_unix_millis FLOAT64,
  script_end_timestamp_unix_millis FLOAT64)
RETURNS INT64
LANGUAGE js
AS r"""
    if (script_end_timestamp_unix_millis < range_begin_timestamp_unix_millis || script_start_timestamp_unix_millis > range_end_timestamp_unix_millis) {
      return 0;
    }
    var begin = Math.max(script_start_timestamp_unix_millis, range_begin_timestamp_unix_millis)
    var end = Math.min(script_end_timestamp_unix_millis, range_end_timestamp_unix_millis)
    return slots * Math.ceil((end - begin) / 1000.0)
""";

/*
Sample CAPACITY_COMMITMENT_CHANGES data (unrelated columns ignored):
+---------------------+------------------------+-----------------+--------+------------+--------+
|  change_timestamp   | capacity_commitment_id | commitment_plan | state  | slot_count | action |
+---------------------+------------------------+-----------------+--------+------------+--------+
| 2023-07-20 19:30:27 | 12954109101902401697   | ANNUAL          | ACTIVE |        100 | CREATE |
| 2023-07-27 22:29:21 | 11445583810276646822   | FLEX            | ACTIVE |        100 | CREATE |
| 2023-07-27 23:10:06 | 7341455530498381779    | MONTHLY         | ACTIVE |        100 | CREATE |
| 2023-07-27 23:11:06 | 7341455530498381779    | FLEX            | ACTIVE |        100 | UPDATE |

The last row indicates a special change from MONTHLY to FLEX, which happens
because of commercial migration.

*/

WITH
  /*
  Information containing which commitment might have plan
  updated (e.g. renewal or commercial migration). For example:
  +------------------------+------------------+--------------------+--------+------------+--------+-----------+----------------------------+
  |  change_timestamp   | capacity_commitment_id | commitment_plan | state  | slot_count | action | next_plan | next_plan_change_timestamp |
  +---------------------+------------------------+-----------------+--------+------------+--------+-----------+----------------------------+
  | 2023-07-20 19:30:27 | 12954109101902401697   | ANNUAL          | ACTIVE |        100 | CREATE | ANNUAL    |        2023-07-20 19:30:27 |
  | 2023-07-27 22:29:21 | 11445583810276646822   | FLEX            | ACTIVE |        100 | CREATE | FLEX      |        2023-07-27 22:29:21 |
  | 2023-07-27 23:10:06 | 7341455530498381779    | MONTHLY         | ACTIVE |        100 | CREATE | FLEX      |        2023-07-27 23:11:06 |
  | 2023-07-27 23:11:06 | 7341455530498381779    | FLEX            | ACTIVE |        100 | UPDATE | FLEX      |        2023-07-27 23:11:06 |
  */
  commitments_with_next_plan AS (
    SELECT
      *,
      IFNULL(
        LEAD(commitment_plan)
          OVER (
            PARTITION BY capacity_commitment_id ORDER BY change_timestamp ASC
          ),
        commitment_plan)
        next_plan,
      IFNULL(
        LEAD(change_timestamp)
          OVER (
            PARTITION BY capacity_commitment_id ORDER BY change_timestamp ASC
          ),
        change_timestamp)
        next_plan_change_timestamp
    FROM
      `region-us.INFORMATION_SCHEMA.CAPACITY_COMMITMENT_CHANGES_BY_PROJECT`
  ),

  /*
  Insert a 'DELETE' action for those with updated plans. The FLEX commitment
  '7341455530498381779' is has no 'CREATE' action, and is instead labeled as an
  'UPDATE' action.

  For example:
  +---------------------+------------------------+-----------------+--------+------------+--------+
  |  change_timestamp   | capacity_commitment_id | commitment_plan | state  | slot_count | action |
  +---------------------+------------------------+-----------------+--------+------------+--------+
  | 2023-07-20 19:30:27 | 12954109101902401697   | ANNUAL          | ACTIVE |        100 | CREATE |
  | 2023-07-27 22:29:21 | 11445583810276646822   | FLEX            | ACTIVE |        100 | CREATE |
  | 2023-07-27 23:10:06 | 7341455530498381779    | MONTHLY         | ACTIVE |        100 | CREATE |
  | 2023-07-27 23:11:06 | 7341455530498381779    | FLEX            | ACTIVE |        100 | UPDATE |
  | 2023-07-27 23:11:06 | 7341455530498381779    | MONTHLY         | ACTIVE |        100 | DELETE |
  */

  capacity_changes_with_additional_deleted_event_for_changed_plan AS (
    SELECT
      next_plan_change_timestamp AS change_timestamp,
      project_id,
      project_number,
      capacity_commitment_id,
      commitment_plan,
      state,
      slot_count,
      'DELETE' AS action,
      commitment_start_time,
      commitment_end_time,
      failure_status,
      renewal_plan,
      user_email,
      edition,
      is_flat_rate,
    FROM commitments_with_next_plan
    WHERE commitment_plan <> next_plan
    UNION ALL
    SELECT * FROM `region-us.INFORMATION_SCHEMA.CAPACITY_COMMITMENT_CHANGES_BY_PROJECT`
  ),

  /*
  The committed_slots change the history. For example:
  +---------------------+------------------------+------------------+-----------------+
  |  change_timestamp   | capacity_commitment_id | slot_count_delta | commitment_plan |
  +---------------------+------------------------+------------------+-----------------+
  | 2023-07-20 19:30:27 | 12954109101902401697   |              100 | ANNUAL          |
  | 2023-07-27 22:29:21 | 11445583810276646822   |              100 | FLEX            |
  | 2023-07-27 23:10:06 | 7341455530498381779    |              100 | MONTHLY         |
  | 2023-07-27 23:11:06 | 7341455530498381779    |             -100 | MONTHLY         |
  | 2023-07-27 23:11:06 | 7341455530498381779    |              100 | FLEX            |
  */

  capacity_commitment_slot_data AS (
    SELECT
      change_timestamp,
      capacity_commitment_id,
      CASE
        WHEN action = "CREATE" OR action = "UPDATE"
          THEN
            IFNULL(
              IF(
                LAG(action)
                  OVER (
                    PARTITION BY capacity_commitment_id ORDER BY change_timestamp ASC, action ASC
                  )
                  IN UNNEST(['CREATE', 'UPDATE']),
                slot_count - LAG(slot_count)
                  OVER (
                    PARTITION BY capacity_commitment_id ORDER BY change_timestamp ASC, action ASC
                  ),
                slot_count),
              slot_count)
        ELSE
          IF(
            LAG(action)
              OVER (PARTITION BY capacity_commitment_id ORDER BY change_timestamp ASC, action ASC)
              IN UNNEST(['CREATE', 'UPDATE']),
            -1 * slot_count,
            0)
        END
        AS slot_count_delta,
      commitment_plan
    FROM
      capacity_changes_with_additional_deleted_event_for_changed_plan
    WHERE
      state = "ACTIVE"
      AND edition = edition_to_check
      AND change_timestamp <= end_time
  ),

  /*
  The total_committed_slots history for each plan. For example:
  +---------------------+---------------+-----------------+
  |  change_timestamp   | capacity_slot | commitment_plan |
  +---------------------+---------------+-----------------+
  | 2023-07-20 19:30:27 |           100 | ANNUAL          |
  | 2023-07-27 22:29:21 |           100 | FLEX            |
  | 2023-07-27 23:10:06 |           100 | MONTHLY         |
  | 2023-07-27 23:11:06 |             0 | MONTHLY         |
  | 2023-07-27 23:11:06 |           200 | FLEX            |
  */

  running_capacity_commitment_slot_data AS (
    SELECT
      change_timestamp,
      SUM(slot_count_delta)
        OVER (
          PARTITION BY commitment_plan
          ORDER BY change_timestamp
          RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        )
        AS capacity_slot,
      commitment_plan,
    FROM
      capacity_commitment_slot_data
  ),

  /*

  The slot_seconds between each changes, partitioned by each plan. For example:
  +---------------------+--------------+-----------------+
  |  change_timestamp   | slot_seconds | commitment_plan |
  +---------------------+--------------+-----------------+
  | 2023-07-20 19:30:27 |     64617300 | ANNUAL          |
  | 2023-07-27 22:29:21 |       250500 | FLEX            |
  | 2023-07-27 23:10:06 |         6000 | MONTHLY         |
  | 2023-07-27 23:11:06 |            0 | MONTHLY         |
  | 2023-07-27 23:11:06 |      5626800 | FLEX            |
  */

  slot_seconds_data AS (
    SELECT
      change_timestamp,
      GetSlotSecondsBetweenChanges(
        capacity_slot,
        UNIX_MILLIS(change_timestamp),
        UNIX_MILLIS(
          IFNULL(
            LEAD(change_timestamp)
              OVER (PARTITION BY commitment_plan ORDER BY change_timestamp ASC),
            CURRENT_TIMESTAMP())),
        UNIX_MILLIS(start_time),
        UNIX_MILLIS(end_time)) AS slot_seconds,
      commitment_plan,
    FROM
      running_capacity_commitment_slot_data
    WHERE
      change_timestamp <= end_time
  )

/*

The final result is similar to the following:
+-----------------+--------------------+
| commitment_plan | total_slot_seconds |
+-----------------+--------------------+
| ANNUAL          |           64617300 |
| MONTHLY         |               6000 |
| FLEX            |            5877300 |
*/

SELECT
  commitment_plan,
  SUM(slot_seconds) AS total_slot_seconds
FROM
  slot_seconds_data
GROUP BY
  commitment_plan

Das folgende Skript prüft die Slot-Nutzung, die nicht durch Zusicherungen für eine bestimmte Version abgedeckt ist. Diese Nutzung enthält zwei Arten von Slots: skalierte Slots und Baseline-Slots, die nicht durch Zusicherungen abgedeckt sind.

Maximieren, um das Skript für nicht abgedeckte Szenarien aufzurufen

/*
This script has several parts:
1. Calculate the baseline and scaled slots for reservations
2. Calculate the committed slots
3. Join the two results above to calculate the baseline not covered by committed
   slots
4. Aggregate the number
*/

-- variables
DECLARE start_time, end_time TIMESTAMP;

DECLARE
  edition_to_check STRING;

/* Google uses Pacific Time to calculate the billing period for all customers,
regardless of their time zone. Use the following format if you want to match the
billing report. Change the start_time and end_time values to match the desired
window. */

/* The following three variables (start_time, end_time, and edition_to_check)
are the only variables that you need to set in the script.

During daylight savings time, the start_time and end_time variables should
follow this format: 2024-02-20 00:00:00-08. */

SET start_time = "2023-07-20 00:00:00-07";
SET end_time = "2023-07-28 00:00:00-07";
SET edition_to_check = 'ENTERPRISE';

/*
The following function returns the slot seconds for the time window between
two capacity changes. For example, if there are 100 slots between (2023-06-01
10:00:00, 2023-06-01 11:00:00), then during that window the total slot seconds
will be 100 * 3600.

This script calculates a specific window (based on the variables defined above),
which is why the following script includes script_start_timestamp_unix_millis
and script_end_timestamp_unix_millis. */

CREATE TEMP FUNCTION GetSlotSecondsBetweenChanges(
  slots FLOAT64,
  range_begin_timestamp_unix_millis FLOAT64,
  range_end_timestamp_unix_millis FLOAT64,
  script_start_timestamp_unix_millis FLOAT64,
  script_end_timestamp_unix_millis FLOAT64)
RETURNS INT64
LANGUAGE js
AS r"""
    if (script_end_timestamp_unix_millis < range_begin_timestamp_unix_millis || script_start_timestamp_unix_millis > range_end_timestamp_unix_millis) {
      return 0;
    }
    var begin = Math.max(script_start_timestamp_unix_millis, range_begin_timestamp_unix_millis)
    var end = Math.min(script_end_timestamp_unix_millis, range_end_timestamp_unix_millis)
    return slots * Math.ceil((end - begin) / 1000.0)
""";
/*
Sample RESERVATION_CHANGES data (unrelated columns ignored):
+---------------------+------------------+--------+---------------+---------------+
|  change_timestamp   | reservation_name | action | slot_capacity | current_slots |
+---------------------+------------------+--------+---------------+---------------+
| 2023-07-27 22:24:15 | res1             | CREATE |           300 |             0 |
| 2023-07-27 22:25:21 | res1             | UPDATE |           300 |           180 |
| 2023-07-27 22:39:14 | res1             | UPDATE |           300 |           100 |
| 2023-07-27 22:40:20 | res2             | CREATE |           300 |             0 |
| 2023-07-27 22:54:18 | res2             | UPDATE |           300 |           120 |
| 2023-07-27 22:55:23 | res1             | UPDATE |           300 |             0 |

Sample CAPACITY_COMMITMENT_CHANGES data (unrelated columns ignored):
+---------------------+------------------------+-----------------+--------+------------+--------+
|  change_timestamp   | capacity_commitment_id | commitment_plan | state  | slot_count | action |
+---------------------+------------------------+-----------------+--------+------------+--------+
| 2023-07-20 19:30:27 | 12954109101902401697   | ANNUAL          | ACTIVE |        100 | CREATE |
| 2023-07-27 22:29:21 | 11445583810276646822   | FLEX            | ACTIVE |        100 | CREATE |
| 2023-07-27 23:10:06 | 7341455530498381779    | MONTHLY         | ACTIVE |        100 | CREATE |
*/

WITH
  /*
  The scaled_slots & baseline change history:
  +---------------------+------------------+------------------------------+---------------------+
  |  change_timestamp   | reservation_name | autoscale_current_slot_delta | baseline_slot_delta |
  +---------------------+------------------+------------------------------+---------------------+
  | 2023-07-27 22:24:15 | res1             |                            0 |                 300 |
  | 2023-07-27 22:25:21 | res1             |                          180 |                   0 |
  | 2023-07-27 22:39:14 | res1             |                          -80 |                   0 |
  | 2023-07-27 22:40:20 | res2             |                            0 |                 300 |
  | 2023-07-27 22:54:18 | res2             |                          120 |                   0 |
  | 2023-07-27 22:55:23 | res1             |                         -100 |                   0 |
  */
  reservation_slot_data AS (
    SELECT
      change_timestamp,
      reservation_name,
      CASE action
        WHEN "CREATE" THEN autoscale.current_slots
        WHEN "UPDATE"
          THEN
            IFNULL(
              autoscale.current_slots - LAG(autoscale.current_slots)
                OVER (
                  PARTITION BY project_id, reservation_name
                  ORDER BY change_timestamp ASC, action ASC
                ),
              IFNULL(
                autoscale.current_slots,
                IFNULL(
                  -1 * LAG(autoscale.current_slots)
                    OVER (
                      PARTITION BY project_id, reservation_name
                      ORDER BY change_timestamp ASC, action ASC
                    ),
                  0)))
        WHEN "DELETE"
          THEN
            IF(
              LAG(action)
                OVER (
                  PARTITION BY project_id, reservation_name
                  ORDER BY change_timestamp ASC, action ASC
                )
                IN UNNEST(['CREATE', 'UPDATE']),
              -1 * autoscale.current_slots,
              0)
        END
        AS autoscale_current_slot_delta,
      CASE action
        WHEN "CREATE" THEN slot_capacity
        WHEN "UPDATE"
          THEN
            IFNULL(
              slot_capacity - LAG(slot_capacity)
                OVER (
                  PARTITION BY project_id, reservation_name
                  ORDER BY change_timestamp ASC, action ASC
                ),
              IFNULL(
                slot_capacity,
                IFNULL(
                  -1 * LAG(slot_capacity)
                    OVER (
                      PARTITION BY project_id, reservation_name
                      ORDER BY change_timestamp ASC, action ASC
                    ),
                  0)))
        WHEN "DELETE"
          THEN
            IF(
              LAG(action)
                OVER (
                  PARTITION BY project_id, reservation_name
                  ORDER BY change_timestamp ASC, action ASC
                )
                IN UNNEST(['CREATE', 'UPDATE']),
              -1 * slot_capacity,
              0)
        END
        AS baseline_slot_delta,
    FROM
      `region-us.INFORMATION_SCHEMA.RESERVATION_CHANGES`
    WHERE
      edition = edition_to_check
      AND change_timestamp <= end_time
  ),

  -- Convert the above to running total
  /*
  +---------------------+-------------------------+----------------+
  |  change_timestamp   | autoscale_current_slots | baseline_slots |
  +---------------------+-------------------------+----------------+
  | 2023-07-27 22:24:15 |                       0 |            300 |
  | 2023-07-27 22:25:21 |                     180 |            300 |
  | 2023-07-27 22:39:14 |                     100 |            300 |
  | 2023-07-27 22:40:20 |                     100 |            600 |
  | 2023-07-27 22:54:18 |                     220 |            600 |
  | 2023-07-27 22:55:23 |                     120 |            600 |
  */
  running_reservation_slot_data AS (
    SELECT
      change_timestamp,
      SUM(autoscale_current_slot_delta)
        OVER (ORDER BY change_timestamp RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
        AS autoscale_current_slots,
      SUM(baseline_slot_delta)
        OVER (ORDER BY change_timestamp RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
        AS baseline_slots,
    FROM
      reservation_slot_data
  ),

  /*
  The committed_slots change history. For example:
  +---------------------+------------------------+------------------+
  |  change_timestamp   | capacity_commitment_id | slot_count_delta |
  +---------------------+------------------------+------------------+
  | 2023-07-20 19:30:27 | 12954109101902401697   |              100 |
  | 2023-07-27 22:29:21 | 11445583810276646822   |              100 |
  | 2023-07-27 23:10:06 | 7341455530498381779    |              100 |
  */
  capacity_commitment_slot_data AS (
    SELECT
      change_timestamp,
      capacity_commitment_id,
      CASE
        WHEN action = "CREATE" OR action = "UPDATE"
          THEN
            IFNULL(
              IF(
                LAG(action)
                  OVER (
                    PARTITION BY capacity_commitment_id ORDER BY change_timestamp ASC, action ASC
                  )
                  IN UNNEST(['CREATE', 'UPDATE']),
                slot_count - LAG(slot_count)
                  OVER (
                    PARTITION BY capacity_commitment_id ORDER BY change_timestamp ASC, action ASC
                  ),
                slot_count),
              slot_count)
        ELSE
          IF(
            LAG(action)
              OVER (PARTITION BY capacity_commitment_id ORDER BY change_timestamp ASC, action ASC)
              IN UNNEST(['CREATE', 'UPDATE']),
            -1 * slot_count,
            0)
        END
        AS slot_count_delta
    FROM
      `region-us.INFORMATION_SCHEMA.CAPACITY_COMMITMENT_CHANGES_BY_PROJECT`
    WHERE
      state = "ACTIVE"
      AND edition = edition_to_check
      AND change_timestamp <= end_time
  ),

  /*
  The total_committed_slots history. For example:
  +---------------------+---------------+
  |  change_timestamp   | capacity_slot |
  +---------------------+---------------+
  | 2023-07-20 19:30:27 |           100 |
  | 2023-07-27 22:29:21 |           200 |
  | 2023-07-27 23:10:06 |           300 |
  */
  running_capacity_commitment_slot_data AS (
    SELECT
      change_timestamp,
      SUM(slot_count_delta)
        OVER (ORDER BY change_timestamp RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
        AS capacity_slot
    FROM
      capacity_commitment_slot_data
  ),

  /* Add next_change_timestamp to the above data,
   which will be used when joining with reservation data. For example:
  +---------------------+-----------------------+---------------+
  |  change_timestamp   | next_change_timestamp | capacity_slot |
  +---------------------+-----------------------+---------------+
  | 2023-07-20 19:30:27 |   2023-07-27 22:29:21 |           100 |
  | 2023-07-27 22:29:21 |   2023-07-27 23:10:06 |           200 |
  | 2023-07-27 23:10:06 |   2023-07-31 00:14:37 |           300 |
  */
  running_capacity_commitment_slot_data_with_next_change AS (
    SELECT
      change_timestamp,
      IFNULL(LEAD(change_timestamp) OVER (ORDER BY change_timestamp ASC), CURRENT_TIMESTAMP())
        AS next_change_timestamp,
      capacity_slot
    FROM
      running_capacity_commitment_slot_data
  ),

  /*
  Whenever we have a change in reservations or commitments,
  the scaled_slots_and_baseline_not_covered_by_commitments will be changed.
  Hence we get a collection of all the change_timestamp from both tables.
  +---------------------+
  |  change_timestamp   |
  +---------------------+
  | 2023-07-20 19:30:27 |
  | 2023-07-27 22:24:15 |
  | 2023-07-27 22:25:21 |
  | 2023-07-27 22:29:21 |
  | 2023-07-27 22:39:14 |
  | 2023-07-27 22:40:20 |
  | 2023-07-27 22:54:18 |
  | 2023-07-27 22:55:23 |
  | 2023-07-27 23:10:06 |
  */
  merged_timestamp AS (
    SELECT
      change_timestamp
    FROM
      running_reservation_slot_data
    UNION DISTINCT
    SELECT
      change_timestamp
    FROM
      running_capacity_commitment_slot_data
  ),

  /*
  Change running reservation-slots and make sure we have one row when commitment changes.
  +---------------------+-------------------------+----------------+
  |  change_timestamp   | autoscale_current_slots | baseline_slots |
  +---------------------+-------------------------+----------------+
  | 2023-07-20 19:30:27 |                       0 |              0 |
  | 2023-07-27 22:24:15 |                       0 |            300 |
  | 2023-07-27 22:25:21 |                     180 |            300 |
  | 2023-07-27 22:29:21 |                     180 |            300 |
  | 2023-07-27 22:39:14 |                     100 |            300 |
  | 2023-07-27 22:40:20 |                     100 |            600 |
  | 2023-07-27 22:54:18 |                     220 |            600 |
  | 2023-07-27 22:55:23 |                     120 |            600 |
  | 2023-07-27 23:10:06 |                     120 |            600 |
  */
  running_reservation_slot_data_with_merged_timestamp AS (
    SELECT
      change_timestamp,
      IFNULL(
        autoscale_current_slots,
        IFNULL(
          LAST_VALUE(autoscale_current_slots IGNORE NULLS) OVER (ORDER BY change_timestamp ASC), 0))
        AS autoscale_current_slots,
      IFNULL(
        baseline_slots,
        IFNULL(LAST_VALUE(baseline_slots IGNORE NULLS) OVER (ORDER BY change_timestamp ASC), 0))
        AS baseline_slots
    FROM
      running_reservation_slot_data
    RIGHT JOIN
      merged_timestamp
      USING (change_timestamp)
  ),

  /*
  Join the above, so that we will know the number for baseline not covered by commitments.
  +---------------------+-----------------------+-------------------------+------------------------------------+
  |  change_timestamp   | next_change_timestamp | autoscale_current_slots | baseline_not_covered_by_commitment |
  +---------------------+-----------------------+-------------------------+------------------------------------+
  | 2023-07-20 19:30:27 |   2023-07-27 22:24:15 |                       0 |                                  0 |
  | 2023-07-27 22:24:15 |   2023-07-27 22:25:21 |                       0 |                                200 |
  | 2023-07-27 22:25:21 |   2023-07-27 22:29:21 |                     180 |                                200 |
  | 2023-07-27 22:29:21 |   2023-07-27 22:39:14 |                     180 |                                100 |
  | 2023-07-27 22:39:14 |   2023-07-27 22:40:20 |                     100 |                                100 |
  | 2023-07-27 22:40:20 |   2023-07-27 22:54:18 |                     100 |                                400 |
  | 2023-07-27 22:54:18 |   2023-07-27 22:55:23 |                     220 |                                400 |
  | 2023-07-27 22:55:23 |   2023-07-27 23:10:06 |                     120 |                                400 |
  | 2023-07-27 23:10:06 |   2023-07-31 00:16:07 |                     120 |                                300 |
  */
  scaled_slots_and_baseline_not_covered_by_commitments AS (
    SELECT
      r.change_timestamp,
      IFNULL(LEAD(r.change_timestamp) OVER (ORDER BY r.change_timestamp ASC), CURRENT_TIMESTAMP())
        AS next_change_timestamp,
      r.autoscale_current_slots,
      IF(
        r.baseline_slots - IFNULL(c.capacity_slot, 0) > 0,
        r.baseline_slots - IFNULL(c.capacity_slot, 0),
        0) AS baseline_not_covered_by_commitment
    FROM
      running_reservation_slot_data_with_merged_timestamp r
    LEFT JOIN
      running_capacity_commitment_slot_data_with_next_change c
      ON
        r.change_timestamp >= c.change_timestamp
        AND r.change_timestamp < c.next_change_timestamp
  ),

  /*
  The slot_seconds between each changes. For example:
  +---------------------+--------------------+
  |  change_timestamp   | slot_seconds |
  +---------------------+--------------+
  | 2023-07-20 19:30:27 |            0 |
  | 2023-07-27 22:24:15 |        13400 |
  | 2023-07-27 22:25:21 |        91580 |
  | 2023-07-27 22:29:21 |       166320 |
  | 2023-07-27 22:39:14 |        13200 |
  | 2023-07-27 22:40:20 |       419500 |
  | 2023-07-27 22:54:18 |        40920 |
  | 2023-07-27 22:55:23 |       459160 |
  | 2023-07-27 23:10:06 |     11841480 |
  */
  slot_seconds_data AS (
    SELECT
      change_timestamp,
      GetSlotSecondsBetweenChanges(
        autoscale_current_slots + baseline_not_covered_by_commitment,
        UNIX_MILLIS(change_timestamp),
        UNIX_MILLIS(next_change_timestamp),
        UNIX_MILLIS(start_time),
        UNIX_MILLIS(end_time)) AS slot_seconds
    FROM
      scaled_slots_and_baseline_not_covered_by_commitments
    WHERE
      change_timestamp <= end_time AND next_change_timestamp > start_time
  )

/*
Final result for this example:
+--------------------+
| total_slot_seconds |
+--------------------+
|           13045560 |
*/
SELECT
  SUM(slot_seconds) AS total_slot_seconds
FROM
  slot_seconds_data

Kontingente

Die Summe Ihrer maximalen Reservierungsgröße sollte Ihr Slot-Kontingent nicht überschreiten.

Weitere Informationen zu Kontingenten finden Sie unter Kontingente und Limits.

Nächste Schritte