Recomendaciones sobre el diseño del esquema

En esta página, se proporciona información sobre el diseño de esquemas de Bigtable. Antes de leer esta página, debes familiarizarte con la descripción general de Bigtable. En esta página, se tratan los siguientes temas:

Conceptos generales

Diseñar un esquema de Bigtable es diferente a diseñar un esquema para una base de datos relacional. Un esquema de Bigtable se define por la lógica de la aplicación y no por un objeto o archivo de definición de esquema. Puedes agregar familias de columnas a una tabla cuando la creas o actualizas, pero los patrones de clave de fila y columnas se definen según los datos que escribes en la tabla.

En Bigtable, un esquema es un plano o modelo de una tabla que incluye la estructura de los siguientes componentes de la tabla:

  • clave(s) de fila
  • Familias de columnas, incluidas sus políticas de recolección de elementos no utilizados
  • Columnas

En Bigtable, el diseño del esquema se impulsa principalmente por las consultas o solicitudes de lectura que planeas enviar a la tabla. Dado que leer un rango de filas es la forma más rápida de leer tus datos de Bigtable, las recomendaciones de esta página están diseñadas para ayudarte a optimizar las lecturas de rangos de filas. En la mayoría de los casos, eso significa enviar una consulta según los prefijos de clave de fila.

Una consideración secundaria es evitar los hotspots. Para evitarlos, debes considerar los patrones de escritura y cómo puedes evitar el acceso a un espacio de claves pequeño en poco tiempo.

Los siguientes conceptos generales se aplican al diseño de esquemas de Bigtable:

  • Bigtable es un almacén de clave-valor, no un almacén relacional. No admite uniones, y las transacciones solo se admiten dentro de una misma fila.
  • Cada tabla tiene solo un índice: la clave de fila. No hay índices secundarios. Cada clave de fila debe ser única.
  • Las filas se ordenan lexicográficamente por clave de fila, desde la mayor string de bytes a la menor. Las claves de fila se ordenan con el orden de bytes big-endian (a veces llamado orden de bytes de red), el equivalente binario del orden alfabético.
  • Las familias de columnas no se almacenan en ningún orden específico.
  • Las columnas se agrupan por familia de columnas y se clasifican en orden lexicográfico dentro de la familia de columnas. Por ejemplo, en una familia de columnas llamada SysMonitor con calificadores de columna de ProcessName, User, %CPU, ID, Memory, DiskRead y Priority, Bigtable almacena las columnas en este orden:
SysMonitor
%CPU DiskRead ID Memoria Prioridad ProcessName Usuario
  • La intersección de una fila y una columna puede contener varias celdas con marca de tiempo. Cada celda contiene una versión única con marca de tiempo de los datos para esa fila y columna.
  • Las familias de columnas agregadas contienen celdas agregadas. Puedes crear familias de columnas que contengan solo celdas agregadas. Una agregación te permite combinar datos nuevos con datos que ya están en la celda.
  • Todas las operaciones son atómicas a nivel de fila. Una operación afecta a una fila completa o a ninguna.
  • Lo ideal es que las lecturas y escrituras se distribuyan de manera uniforme en el espacio de filas de una tabla.
  • Las tablas de Bigtable son dispersas. Una columna no ocupa ningún espacio en una fila que no use la columna.

prácticas recomendadas

Un buen esquema genera un excelente rendimiento y escalabilidad, mientras que uno mal diseñado puede provocar un rendimiento deficiente del sistema. Cada caso de uso es diferente y requiere su propio diseño, pero las siguientes prácticas recomendadas se aplican a la mayoría de los casos de uso. Se mencionan excepciones.

En las siguientes secciones, se describen las prácticas recomendadas para el diseño de esquemas desde el nivel de tabla hasta el nivel de clave de fila:

Todos los elementos de tabla, en especial las claves de fila, deben diseñarse teniendo en cuenta las solicitudes de lectura planificadas. Verifica las cuotas y los límites para conocer los límites de tamaño recomendados y estrictos para todos los elementos de tabla.

Debido a que todas las tablas de una instancia se almacenan en las mismas tablets, un diseño de esquema que genere hotspots en una tabla puede afectar la latencia de otras tablas en la misma instancia. Los hotspots se generan cuando se accede con frecuencia a una parte de la tabla en un período corto.

Tables

Almacena conjuntos de datos con esquemas similares en la misma tabla, en lugar de hacerlo en tablas separadas.

En otros sistemas de bases de datos, puedes elegir almacenar datos en varias tablas según el asunto y la cantidad de columnas. En Bigtable, sin embargo, suele ser mejor almacenar todos tus datos en una tabla. Puedes asignar un prefijo de clave de fila único para usar en cada conjunto de datos, de modo que Bigtable almacene los datos relacionados en un rango contiguo de filas que luego puedes consultar por prefijo de clave de fila.

Bigtable tiene un límite de 1,000 tablas por instancia, pero, por lo general, deberías tener muchas menos tablas. Evita crear una gran cantidad de tablas por los siguientes motivos:

  • El envío de solicitudes a muchas tablas diferentes puede aumentar la sobrecarga de la conexión de backend, lo que aumenta la latencia final.
  • Tener varias tablas de diferentes tamaños puede interrumpir el balanceo de cargas tras bambalinas que hace que Bigtable funcione.

Es justificable que quieras una tabla separada para un caso práctico diferente que requiera un esquema diferente, pero no debes usar tablas separadas para datos similares. Por ejemplo, no debes crear una tabla nueva porque es un año nuevo o tienes un cliente nuevo.

Familias de columnas

Coloca las columnas relacionadas en la misma familia de columnas. Cuando una fila contiene varios valores relacionados entre sí, se recomienda agrupar las columnas que contienen esos valores en la misma familia de columnas. Agrupa los datos lo más cerca posible, a fin de evitar la necesidad de diseñar filtros complejos y obtener solo la información que necesitas, pero no más, en tus solicitudes de lectura más frecuentes.

Crea hasta 100 familias de columnas por tabla. Crear más de 100 familias de columnas puede degradar el rendimiento.

Elige nombres cortos para las familias de columnas. Los nombres se incluyen en los datos que se transfieren para cada solicitud.

Coloca columnas que tengan diferentes necesidades de retención de datos en diferentes familias de columnas. Esta práctica es importante si deseas limitar los costos de almacenamiento. Las políticas de recolección de elementos no utilizados se establecen en el nivel de familia de columnas, no en el nivel de columna. Por ejemplo, si solo necesitas conservar la versión más reciente de un dato en particular, no lo almacenes en una familia de columnas configurada para almacenar 1,000 versiones de otro elemento. De lo contrario, pagas para almacenar 999 celdas de datos que no necesitas.

Columnas

(Opcional) Trata los calificadores de columnas como datos. Dado que tienes que almacenar un calificador de columna para cada columna, puedes ahorrar espacio nombrando la columna con un valor. Como ejemplo, considera una tabla que almacena datos sobre amistades en una familia de columnas Friends. Cada fila representa a una persona y todas sus amistades. Cada calificador de columna puede ser el ID de un amigo. Luego, el valor de cada columna en esa fila puede ser el círculo social en el que se encuentra el amigo. En este ejemplo, las filas podrían verse de la siguiente manera:

Clave de fila Calificador de columna:valor Calificador de columna:valor Calificador de columna:valor
José Fred:club de lectura Gabriel:trabajo Hiroshi:tenis
Sofía Hiroshi:trabajo Seo Yoon:escuela Jakob:club de ajedrez

Compara este esquema con un esquema para los mismos datos que no trate a los calificadores de columna como datos y, en su lugar, tenga las mismas columnas en todas las filas:

Clave de fila Calificador de columna:valor Calificador de columna:valor
Jose#1 Amigo:Fred Círculo: club de lectura
Jose#2 Amigo:Gabriel Círculo:trabajo
Jose#3 Amigo:Hiroshi Círculo:tenis
Sofia#1 Amigo:Hiroshi Círculo:trabajo
Sofia#2 Amigo:Seo Yoon Círculo:escuela
Sofía#3 Amigo:Jakob Círculo:club de lectura

El segundo diseño de esquema hace que la tabla crezca mucho más rápido.

Si usas calificadores de columna para almacenar datos, otorga nombres cortos pero significativos a las columnas. Este enfoque te permite reducir la cantidad de datos que se transfieren para cada solicitud. El tamaño máximo es de 16 KB.

Crea tantas columnas como necesites en la tabla. Las tablas de Bigtable están dispersas y no hay penalización de espacio para una columna que no se usa en una fila. Puedes tener millones de columnas en una tabla, siempre que ninguna fila exceda el límite máximo de 256 MB por fila.

Evita usar demasiadas columnas en una sola fila. Aunque una tabla puede tener millones de columnas, una fila no debería tenerla. Algunos factores contribuyen a esta práctica recomendada:

  • Bigtable demora en procesar cada celda de una fila.
  • Cada celda agrega sobrecarga a la cantidad de datos que se almacenan en la tabla y se envían por la red. Por ejemplo, si almacenas 1 KB (1,024 bytes) de datos, es mucho más eficiente en términos de espacio almacenarlos en una sola celda, en lugar de distribuirlos entre 1,024 celdas que contienen 1 byte cada una.

Si tu conjunto de datos requiere de forma lógica más columnas por fila de las que Bigtable puede procesar de manera eficiente, considera almacenar los datos como un protobuf en una sola columna.

Filas

Mantén el tamaño de todos los valores de una sola fila por debajo de 100 MB. Asegúrate de que los datos de una sola fila no superen los 256 MB. Las filas que exceden este límite pueden reducir el rendimiento de lectura.

Mantén toda la información de una entidad en una sola fila. En la mayoría de los casos de uso, evita almacenar datos que debas leer de forma atómica o todos a la vez en más de una fila para evitar incoherencias. Por ejemplo, si actualizas dos filas de una tabla, es posible que una fila se actualice correctamente y la otra actualización falle. Asegúrate de que tu esquema no necesite que se actualice más de una fila a la vez para que los datos relacionados sean precisos. Esta práctica garantiza que, si falla parte de una solicitud de escritura o debe volver a enviarse, ese dato no esté incompleto de manera temporal.

Excepción: Si mantener una entidad en una sola fila genera filas de cientos de MB, debes dividir los datos entre varias filas.

Almacena entidades relacionadas en filas adyacentes para que las lecturas sean más eficientes.

celdas

No almacenes más de 10 MB de datos en una sola celda. Recuerda que una celda son los datos almacenados para una fila y columna determinadas con una marca de tiempo única, y que se pueden almacenar varias celdas en la intersección de esa fila y columna. La cantidad de celdas retenidas en una columna se rige por la política de recolección de elementos no utilizados que estableces para la familia de columnas que contiene la columna.

Usar celdas agregadas para almacenar y actualizar datos agregados Si solo te importa el valor agregado de los eventos de una entidad, como la suma mensual de las ventas por empleado en una tienda minorista, puedes usar los agregados. Para obtener más información, consulta Valores agregados en el momento de la escritura (Vista previa).

clave(s) de fila

Diseña tu clave de fila según las consultas que usarás para recuperar los datos. Las claves de fila bien diseñadas logran el mejor rendimiento de Bigtable. Las consultas de Bigtable más eficientes recuperan los datos mediante una de las siguientes opciones:

  • Clave de fila
  • Prefijo de la clave de fila
  • Rango de filas definido por las claves de fila inicial y final

Otros tipos de consultas activan un análisis completo de la tabla, lo que es mucho menos eficiente. Si eliges la clave de fila correcta, te ahorrarás un proceso de migración de datos agotador en el futuro

Usa claves de fila cortas. Una clave de fila debe ser de 4 KB o menos. Las claves de fila largas consumen memoria y almacenamiento adicionales y aumentan el tiempo que se tarda en obtener respuestas del servidor de Bigtable.

Almacena varios valores delimitados en cada clave de fila. A menudo, es útil que incluyas varios identificadores en tu clave de fila, debido a que la mejor forma de realizar consultas eficaces en Bigtable es a través de la clave de fila. Es especialmente importante comprender en profundidad cómo usas tus datos cuando tu clave de fila incluye varios valores.

Los segmentos de clave de fila suelen estar separados por un delimitador, como un carácter de hash, dos puntos o barra. El primer segmento o conjunto de segmentos contiguos es el prefijo de la clave de fila, y el último segmento o conjunto de segmentos contiguos es el sufijo de la clave de fila.

Clave de fila de muestra

Los prefijos de clave de fila bien planificados te permiten aprovechar el orden de clasificación de Bigtable para almacenar datos relacionados en filas contiguas. El almacenamiento de datos relacionados en filas contiguas te permite acceder a datos relacionados como un rango de filas, en lugar de ejecutar análisis ineficientes de las tablas.

Si tus datos incluyen números enteros que deseas almacenar u ordenar de forma numérica, rellena los números enteros con ceros a la izquierda. Bigtable almacena los datos lexicográficamente. Por ejemplo, lexicográficamente, 3 > 20, pero 20 > 03. Rellenar el 3 con un cero inicial garantiza que los números se ordenen de forma numérica. Esta táctica es importante para las marcas de tiempo en las que se usan consultas basadas en rangos.

Es importante crear una clave de fila que permita recuperar un rango de filas bien definido. De lo contrario, tu consulta requiere un análisis de la tabla, que es mucho más lento que recuperar filas específicas.

Por ejemplo, si tu aplicación realiza un seguimiento de los datos del dispositivo móvil, puedes tener una clave de fila que contenga el tipo de dispositivo, el ID del dispositivo y el día en que se registran los datos. Las claves de fila para estos datos podrían verse así:

        phone#4c410523#20200501
        phone#4c410523#20200502
        tablet#a0b81f74#20200501
        tablet#a0b81f74#20200502

Este diseño de clave de fila te permite recuperar datos con una sola solicitud para lo siguiente:

  • Un tipo de dispositivo
  • Una combinación del tipo de dispositivo y el ID del dispositivo

Este diseño de clave de fila no sería óptimo si deseas recuperar todos los datos de un día determinado. Debido a que el día se almacena en el tercer segmento o en el sufijo de la clave de fila, no puedes solicitar un rango de filas según el sufijo o un segmento medio de la clave de fila. En su lugar, debes enviar una solicitud de lectura con un filtro que analice toda la tabla en busca del valor del día.

Usa valores de string legibles en tus claves de fila siempre que sea posible. Esta práctica facilita el uso de la herramienta Key Visualizer para solucionar problemas con Bigtable.

Por lo general, debes diseñar claves de fila que comiencen con un valor común y terminen con un valor detallado. Por ejemplo, si tu clave de fila incluye un continente, un país y una ciudad, puedes crear claves de fila que se vean de la siguiente manera para que se ordenen automáticamente primero por valores con menor cardinalidad:

        asia#india#bangalore
        asia#india#mumbai
        asia#japan#osaka
        asia#japan#sapporo
        southamerica#bolivia#cochabamba
        southamerica#bolivia#lapaz
        southamerica#chile#santiago
        southamerica#chile#temuco

Claves de fila que debes evitar

Algunos tipos de claves de fila pueden dificultar la consulta de tus datos y algunos dan como resultado un rendimiento deficiente. En esta sección, se describen algunos tipos de claves de fila que debes evitar usar en Bigtable.

Claves de fila que comienzan con una marca de tiempo. Este patrón hace que las escrituras secuenciales se envíen a un solo nodo, creando un hotspot. Si pones una marca de tiempo en una clave de fila, antepón un valor de alta cardinalidad, como un ID de usuario, para evitar hotspots.

Claves de fila que provocan que los datos relacionados no se agrupen. Evita las claves de fila que hagan que los datos relacionados se almacenen en rangos de filas no contiguas, que son ineficientes para leer en conjunto.

ID numéricos secuenciales. Imagina que tu sistema asigna un ID numérico a cada uno de los usuarios de tu aplicación. Es posible que te parezca una buena idea usar el ID numérico del usuario como clave de fila en tu tabla. Sin embargo, debido a que es más probable que los usuarios nuevos sean usuarios activos, es posible que este enfoque envíe la mayor parte de tu tráfico a una pequeña cantidad de nodos.

Un enfoque más seguro es usar una versión invertida del ID numérico del usuario, que distribuye el tráfico de manera más uniforme en todos los nodos de tu tabla de Bigtable.

Identificadores que se actualizan con frecuencia. Evita usar una sola clave de fila para identificar un valor que debe actualizarse con frecuencia. Por ejemplo, si almacenas datos de uso de memoria de varios dispositivos una vez por segundo, no uses una sola clave de fila para cada dispositivo compuesta por el ID de dispositivo y la métrica que se almacene, como 4c410523#memusage, y actualices la fila repetidamente. Este tipo de operación sobrecarga la tablet que almacena la fila de uso frecuente. También puede hacer que una fila exceda su límite de tamaño debido a que los valores anteriores de una columna ocupan espacio hasta que las celdas se quitan durante la recolección de elementos no utilizados.

En su lugar, almacena cada lectura nueva en una fila nueva. En el ejemplo de uso de memoria, cada clave de fila puede contener el ID de dispositivo, el tipo de métrica y una marca de tiempo, de modo que las claves de fila sean similares a 4c410523#memusage#1423523569918. Esta estrategia es eficiente porque, en Bigtable, crear una fila nueva no lleva más tiempo que crear una celda nueva. Además, esta estrategia te permite leer rápidamente los datos de un período específico mediante el cálculo de las claves de inicio y finalización adecuadas.

Para valores que cambian con frecuencia, como un contador que se actualiza cientos de veces por minuto, es mejor mantener los datos en la memoria, en la capa de aplicación, y escribir filas nuevas en Bigtable de forma periódica.

Valores con hash. Agregar hash a una clave de fila te impide aprovechar el orden natural de Bigtable, lo que hace imposible almacenar las filas de manera óptima para realizar consultas. Por el mismo motivo, los valores de hash hacen que sea difícil usar la herramienta Key Visualizer para solucionar problemas de Bigtable. Usa valores legibles en lugar de valores con hash.

Valores expresados como bytes sin procesar, en lugar de strings legibles. Los bytes sin procesar son adecuados para los valores de columnas. Sin embargo, para la legibilidad y la solución de problemas, es mejor usar valores de string en las claves de fila.

Casos de uso especiales

Es posible que tengas un conjunto de datos único que requiera una consideración especial cuando diseñas un esquema para almacenarlo en Bigtable. En esta sección, se describen algunos tipos de datos de Bigtable, pero no todos, y algunas tácticas sugeridas para almacenarlos de la manera más óptima.

Datos basados en el tiempo

Incluye una marca de tiempo como parte de tu clave de fila si a menudo recuperas datos en función del momento en que se registraron.

Por ejemplo, tu aplicación puede registrar datos relacionados con el rendimiento, como el uso de memoria y CPU, una vez por segundo en muchas máquinas. Tu clave de fila para estos datos podría combinar un identificador de la máquina con una marca de tiempo para los datos (por ejemplo, machine_4223421#1425330757685). Ten en cuenta que las claves de fila se ordenan de manera lexicográfica.

No uses una marca de tiempo sola o al comienzo de una clave de fila, ya que esto provocará que las escrituras secuenciales se envíen a un solo nodo y creará un hotspot. En este caso, debes considerar los patrones de escritura y de lectura.

Si por lo general recuperas primero los registros más recientes, puedes usar una marca de tiempo invertida en la clave de fila restando la marca de tiempo del valor máximo de tu lenguaje de programación para números enteros largos (en Java, java.lang.Long.MAX_VALUE). Con una marca de tiempo invertida, los registros se ordenarán del más reciente al menos recientes.

Si deseas obtener información específica sobre cómo trabajar con datos de series temporales, consulta Diseño de esquemas para datos de series temporales.

Multiusuario

Los prefijos de clave de fila proporcionan una solución escalable para los casos prácticos de “instancias múltiples”, lo que ocurre cuando almacenas datos similares, con el uso del mismo modelo de datos, en nombre de varios clientes. Usar una tabla para todos los usuarios es la forma más eficiente de almacenar datos de múltiples usuarios y acceder a ellos.

Por ejemplo, supongamos que almacenas y realizas un seguimiento de los historiales de compra en nombre de muchas empresas. Puedes usar tu ID único para cada empresa como prefijo de clave de fila. Todos los datos de un usuario se almacenan en filas contiguas en la misma tabla, y puedes buscarlos o filtrarlos mediante el prefijo de la clave de fila. Luego, cuando una empresa ya no sea tu cliente y necesites borrar los datos del historial de compras que almacenabas para ella, puedes quitar el rango de filas que usan el prefijo de clave de fila de ese cliente.

Por ejemplo, si almacenas los datos de dispositivos móviles para los clientes altostrat y examplepetstore, puedes crear claves de filas como las que se muestran a continuación: Luego, si altostrat ya no es tu cliente, descartas todas las filas con el prefijo de clave de fila altostrat.

        altostrat#phone#4c410523#20190501
        altostrat#phone#4c410523#20190502
        altostrat#tablet#a0b41f74#20190501
        examplepetstore#phone#4c410523#20190502
        examplepetstore#tablet#a6b81f79#20190501
        examplepetstore#tablet#a0b81f79#20190502

En cambio, si almacenas datos en nombre de cada empresa en su propia tabla, puedes experimentar problemas de escalabilidad y rendimiento. También es muy probable que, sin darte cuenta, alcances el límite de 1,000 tablas por instancia de Bigtable. Después de que una instancia alcanza este límite, Bigtable evita que crees más tablas en la instancia.

Privacidad

A menos que tu caso de uso lo exija, evita usar información de identificación personal (PII) o datos del usuario en claves de fila o IDs de familia de columnas. Los valores en las claves de fila y las familias de columnas son datos del cliente y datos de servicio, y las aplicaciones que los usan, como la encriptación o el registro, pueden exponerlos de forma inadvertida a usuarios que no deberían tener acceso a datos privados.

Para obtener más información sobre cómo se manejan los datos del servicio, consulta el Aviso de Privacidad de Google Cloud.

Nombres de dominio

Amplia gama de nombres de dominio

Si almacenas datos sobre entidades que pueden representarse como nombres de dominio, considera usar un nombre de dominio inverso (por ejemplo, com.company.product) como la clave de fila. El uso de un nombre de dominio inverso es ideal si los datos de cada fila tienden a superponerse con las filas adyacentes. En este caso, en Bigtable se pueden comprimir tus datos de manera más eficiente.

En cambio, los nombres de dominio estándar que no se revierten pueden hacer que las filas se ordenen de tal manera que los datos relacionados no se agrupen en un solo lugar, lo que puede generar una compresión menos eficiente y lecturas menos eficientes.

Este enfoque funciona mejor cuando tus datos se distribuyen a través de muchos nombres de dominio inversos diferentes.

Para ilustrar este punto, considera los siguientes nombres de dominio, que Bigtable ordena de forma automática en orden lexicográfico:

      drive.google.com
      en.wikipedia.org
      maps.google.com

Esto no es recomendable para el caso de uso en el que deseas consultar todas las filas de google.com. Por el contrario, considera las mismas filas en las que se revirtieron los nombres de dominio:

      com.google.drive
      com.google.maps
      org.wikipedia.en

En el segundo ejemplo, las filas relacionadas se ordenan de forma automática de manera tal que facilita su recuperación como un rango de filas.

Pocos nombres de dominio

Si esperas almacenar una gran cantidad de datos para una pequeña cantidad de nombres de dominio o solo uno, considera otros valores para tu clave de fila. De lo contrario, podrías enviar escrituras a un solo nodo del clúster, lo que podría generar hotspots, o bien tus filas podrían ser demasiado grandes.

Consultas cambiantes o inciertas

Si no siempre ejecutas las mismas consultas en tus datos o no estás seguro de cuáles serán tus consultas, una opción es almacenar todos los datos de una fila en una columna en lugar de varias columnas. Con este enfoque, usas un formato que dificulta la extracción de los valores individuales más adelante, como el formato binario del búfer de protocolo o un archivo JSON.

La clave de fila aún está diseñada con cuidado para garantizar que puedas recuperar los datos que necesitas, pero cada fila suele tener solo una columna que contiene todos los datos de la fila en un solo protobuf.

Almacenar datos como un mensaje protobuf en una sola columna en lugar de distribuirlos en varias columnas tiene ventajas y desventajas. Estas son algunas ventajas:

  • Los datos ocupan menos espacio, por lo que te cuesta menos almacenarlos.
  • Puedes mantener una cierta flexibilidad, ya que no te comprometes con familias de columnas ni calificadores de columnas.
  • La aplicación de lectura no necesita "saber" cuál es el esquema de tu tabla.

Estas son algunas desventajas:

  • Debes deserializar los mensajes protobuf después de que se leen desde Bigtable.
  • Se pierde la opción de consultar los datos en mensajes protobuf mediante filtros.
  • No puedes usar BigQuery para ejecutar consultas federadas en campos dentro de mensajes protobuf después de leerlos desde Bigtable.

¿Qué sigue?