Consulta tablas particionadas

En este documento, se describen algunas consideraciones específicas para consultar tablas particionadas en BigQuery.

Para obtener información general sobre cómo ejecutar consultas en BigQuery, lee la sección Ejecuta consultas interactivas y por lotes.

Descripción general

Si una consulta usa un filtro apto en el valor de la columna de partición, BigQuery puede analizar las particiones que coinciden con el filtro y omitir las particiones restantes. Este proceso se llama reducción de particiones.

La reducción de las particiones es el mecanismo que utiliza BigQuery para eliminar las particiones innecesarias desde el análisis de entrada. Las particiones reducidas no se incluyen cuando se calculan los bytes analizados en la consulta. Por lo general, la reducción de la partición ayuda a reducir el costo de la consulta.

Los comportamientos de la reducción varían para los diferentes tipos de partición, por lo que puedes ver una diferencia en los bytes procesados cuando se consultan tablas particionadas de forma diferente, pero que son idénticas. Para estimar cuántos bytes procesará una consulta, realiza una ejecución de prueba.

Crea una tabla particionada por columnas de unidad de tiempo

Para reducir las particiones cuando consultas una tabla particionada por columnas de unidad de tiempo, incluye un filtro en la columna de partición.

En el siguiente ejemplo, supongamos que dataset.table está particionada en la columna transaction_date. La consulta de ejemplo reduce las fechas previas al 2016-01-01.

SELECT * FROM dataset.table
WHERE transaction_date >= '2016-01-01'

Consulta una tabla particionada por tiempo de transferencia

Las tablas particionadas por tiempo de transferencia contienen una seudocolumna llamada _PARTITIONTIME, que es la columna de partición. El valor de la columna es el tiempo de transferencia de UTC para cada fila, truncado al límite de partición (como por hora o por día), como un valor TIMESTAMP.

Por ejemplo, si agregas datos el 15 de abril de 2021 a las 08:15:00 UTC, la columna _PARTITIONTIME de esas filas contendrá los siguientes valores:

  • Tabla particionada por hora: TIMESTAMP("2021-04-15 08:00:00")
  • Tabla particionada por día: TIMESTAMP("2021-04-15")
  • Tabla particionada por mes: TIMESTAMP("2021-04-01")
  • Tabla particionada por año: TIMESTAMP("2021-01-01")

Si el nivel de detalle de la partición es diario, la tabla también contiene una seudocolumna llamada _PARTITIONDATE. El valor es igual a _PARTITIONTIME truncado a un valor DATE.

Ambos nombres de las seudocolumnas están reservados. No puedes crear una columna con esos nombres en ninguna de tus tablas.

Para reducir las particiones, filtra en cualquiera de estas columnas. Por ejemplo, la siguiente consulta analiza solo las particiones entre las fechas 1 de enero de 2016 y 2 de enero de 2016:

SELECT
  column
FROM
  dataset.table
WHERE
  _PARTITIONTIME BETWEEN TIMESTAMP('2016-01-01') AND TIMESTAMP('2016-01-02')

Para seleccionar la seudocolumna _PARTITIONTIME, debes usar un alias. Por ejemplo, la siguiente consulta selecciona _PARTITIONTIME mediante la asignación del alias pt a la seudocolumna:

SELECT
  _PARTITIONTIME AS pt, column
FROM
  dataset.table

Para las tablas particionadas por día, puedes seleccionar la seudocolumna _PARTITIONDATE de la misma manera:

SELECT
  _PARTITIONDATE AS pd, column
FROM
  dataset.table

Una declaración SELECT * no muestra las seudocolumnas _PARTITIONTIME ni _PARTITIONDATE. Debes seleccionarlas de manera explícita:

SELECT
  _PARTITIONTIME AS pt, *
FROM
  dataset.table

Controla zonas horarias en tablas particionadas por tiempo de transferencia

El valor de _PARTITIONTIME se basa en la fecha UTC cuando se propaga el campo. Si deseas consultar datos basados en una zona horaria distinta de UTC, elige una de las siguientes opciones:

  • Ajusta las diferencias de zona horaria en tus consultas en SQL.
  • Usa decoradores de partición para cargar datos en particiones por tiempo de transferencia específicas, según una zona horaria distinta de UTC.

Mejor rendimiento con seudocolumnas

Para mejorar el rendimiento de las consultas, usa la seudocolumna _PARTITIONTIME sola en el lado izquierdo de la comparación.

Por ejemplo, las dos consultas siguientes son equivalentes. Según el tamaño de la tabla, la segunda consulta podría tener un mejor rendimiento, ya que coloca _PARTITIONTIME por sí solo en el lado izquierdo del operador >. Ambas consultas procesan la misma cantidad de datos.

-- Might be slower.
SELECT
  field1
FROM
  dataset.table1
WHERE
  TIMESTAMP_ADD(_PARTITIONTIME, INTERVAL 5 DAY) > TIMESTAMP("2016-04-15");

-- Often performs better.
SELECT
  field1
FROM
  dataset.table1
WHERE
  _PARTITIONTIME > TIMESTAMP_SUB(TIMESTAMP('2016-04-15'), INTERVAL 5 DAY);

Para limitar las particiones que se analizan en una consulta, usa una expresión constante en tu filtro. La siguiente consulta limita las particiones que se reducen según la primera condición de filtro en la cláusula WHERE. Sin embargo, la segunda condición de filtro no limita las particiones analizadas, ya que usa valores de tabla, que son dinámicos.

SELECT
  column
FROM
  dataset.table2
WHERE
  -- This filter condition limits the scanned partitions:
  _PARTITIONTIME BETWEEN TIMESTAMP('2017-01-01') AND TIMESTAMP('2017-03-01')
  -- This one doesn't, because it uses dynamic table values:
  AND _PARTITIONTIME = (SELECT MAX(timestamp) from dataset.table1)

Para limitar las particiones analizadas, no incluyas ninguna otra columna en un filtro _PARTITIONTIME. Por ejemplo, la consulta siguiente no limita las particiones analizadas, ya que field1 es una columna de la tabla.

-- Scans all partitions of table2. No pruning.
SELECT
  field1
FROM
  dataset.table2
WHERE
  _PARTITIONTIME + field1 = TIMESTAMP('2016-03-28');

Si a menudo consultas un rango de veces en particular, considera crear una vista que filtre la seudocolumna _PARTITIONTIME. Por ejemplo, la siguiente declaración crea una vista que incluye solo los últimos siete días de datos de una tabla llamada dataset.partitioned_table:

-- This view provides pruning.
CREATE VIEW dataset.past_week AS
  SELECT *
  FROM
    dataset.partitioned_table
  WHERE _PARTITIONTIME BETWEEN
    TIMESTAMP_TRUNC(TIMESTAMP_SUB(CURRENT_TIMESTAMP, INTERVAL 7 * 24 HOUR), DAY)
    AND TIMESTAMP_TRUNC(CURRENT_TIMESTAMP, DAY);

Para obtener información sobre cómo crear vistas, consulta Crea vistas.

Consulta una tabla particionada por rango de números enteros

Para reducir las particiones cuando consultas una tabla particionada por rango de números enteros, incluye un filtro en la columna de partición por números enteros.

En el siguiente ejemplo, supongamos que dataset.table es una tabla particionada por rango de números enteros con una especificación de partición de customer_id:0:100:10. La consulta de ejemplo analiza las tres particiones que comienzan con 30, 40 y 50.

SELECT * FROM dataset.table
WHERE customer_id BETWEEN 30 AND 50

+-------------+-------+
| customer_id | value |
+-------------+-------+
|          40 |    41 |
|          45 |    46 |
|          30 |    31 |
|          35 |    36 |
|          50 |    51 |
+-------------+-------+

No se admite la reducción de particiones para funciones de más de una columna particionada por rango de números enteros. Por ejemplo, la siguiente consulta analiza la tabla completa.

SELECT * FROM dataset.table
WHERE customer_id + 1 BETWEEN 30 AND 50

Usa SQL heredado para consultar tablas particionadas por rango de números enteros

No puedes usar SQL heredado para realizar consultas en una tabla particionada por rango de números enteros. En su lugar, la consulta muestra un error como el siguiente:

Querying tables partitioned on a field is not supported in Legacy SQL

Sin embargo, SQL heredado admite el uso de decoradores de tabla para abordar una partición específica en una tabla particionada por rango de números enteros. La clave para dirigirse a una partición de rango es el inicio del rango.

El siguiente ejemplo consulta la partición de rango que comienza con 30:

SELECT * FROM dataset.table$30

Consulta datos en el almacenamiento optimizado para escritura

La partición __UNPARTITIONED__ almacena de forma temporal los datos que se transmiten a una tabla particionada mientras esta se encuentra en el almacenamiento optimizado para escritura. Los datos que se transmiten de forma directa a una partición específica de una tabla particionada no usan la partición __UNPARTITIONED__. En su lugar, los datos se envían a la partición de forma directa.

Los datos en el almacenamiento optimizado para escritura tienen valores NULL en las columnas _PARTITIONTIME y _PARTITIONDATE.

Para consultar datos en la partición __UNPARTITIONED__, usa la pseudocolumna _PARTITIONTIME con el valor NULL. Por ejemplo:

SELECT
  column
FROM dataset.table
WHERE
  _PARTITIONTIME IS NULL

Para obtener más información, consulta Transmite a tablas particionadas.

Prácticas recomendadas para la reducción de particiones

Usa una expresión de filtro constante

Para limitar las particiones que se analizan en una consulta, usa una expresión constante en tu filtro. Si usas expresiones dinámicas en tu filtro de consultas, BigQuery deberá analizar todas las particiones.

Por ejemplo, la siguiente consulta reduce particiones porque el filtro contiene una expresión constante:

SELECT
  t1.name,
  t2.category
FROM
  table1 AS t1
INNER JOIN
  table2 AS t2
ON t1.id_field = t2.field2
WHERE
  t1.ts = CURRENT_TIMESTAMP()

Sin embargo, la siguiente consulta no reduce las particiones, ya que el filtro WHERE t1.ts = (SELECT timestamp from table where key = 2) no es una expresión constante, sino que depende de los valores dinámicos de los campos timestamp y key:

SELECT
  t1.name,
  t2.category
FROM
  table1 AS t1
INNER JOIN
  table2 AS t2
ON
  t1.id_field = t2.field2
WHERE
  t1.ts = (SELECT timestamp from table3 where key = 2)

Aísla la columna de la partición en tu filtro

Aísla la columna de partición cuando expresa un filtro. Los filtros que requieren datos de varios campos para el procesamiento no reducirán las particiones. Por ejemplo, una consulta con una comparación de fecha con la columna de partición y un segundo campo, o las consultas que contienen algunas concatenaciones de campo no reducirán las particiones.

Por ejemplo, el siguiente filtro no reduce las particiones, ya que requiere un procesamiento basado en el campo de partición ts y un segundo campo ts2:

WHERE TIMESTAMP_ADD(ts, INTERVAL 6 HOUR) > ts2

Exige un filtro de partición en las consultas

Cuando creas una tabla particionada, puedes exigir el uso de filtros predicados si habilitas la opción Exigir filtro de partición. Cuando se aplica esta opción, los intentos de consultar la tabla particionada sin especificar una cláusula WHERE producen el siguiente error: .

Cannot query over table 'project_id.dataset.table' without a filter that can be used for partition elimination

Debe haber al menos un predicado que solo haga referencia a una columna de partición a fin de que el filtro se considere apto para eliminar particiones. Por ejemplo, para una tabla particionada en una columna partition_id con una columna adicional f en su esquema, las siguientes cláusulas WHERE cumplen con el requisito:

WHERE partition_id = "20221231"
WHERE partition_id = "20221231" AND f = "20221130"

Sin embargo, WHERE (partition_id = "20221231" OR f = "20221130") no es suficiente.

Para las tablas particionadas por tiempo de transferencia, usa la seudocolumna _PARTITIONTIME o _PARTITIONDATE.

Para obtener más información sobre cómo agregar la opción Exigir filtro de partición cuando creas una tabla particionada, consulta Crea tablas particionadas. También puedes actualizar esta configuración en una tabla existente.

¿Qué sigue?