Recomendaciones sobre el diseño del esquema

Esta página contiene 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 abordan los siguientes temas:

Conceptos generales

Diseñar un esquema de Bigtable es diferente de diseñar un esquema para una base de datos relacional. Un esquema de Bigtable se define con la lógica de la aplicación en lugar de 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, incluida la estructura de los siguientes componentes de 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 basa principalmente en 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 realizar optimizaciones para las operaciones de lectura de rangos de filas. En la mayoría de los casos, eso significa enviar una consulta basada en los prefijos de clave de fila.

Una consideración secundaria es evitar los hotspots. Para ello, debes tener en cuenta los patrones de escritura y cómo evitar acceder 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 sistema big-endian, que es el orden de bytes, o 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 esa columna.
  • Las familias de columnas agregadas contienen celdas agregadas. Puedes crear familias de columnas que contengan solo celdas agregadas. Una función de 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 parte de ella.
  • Lo ideal es que las operaciones de lectura y escritura se distribuyan de manera uniforme en el espacio de filas de la 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 genera hotspots en una tabla puede afectar la latencia de otras tablas en la misma instancia. Los hotspots se producen cuando se accede con frecuencia a una parte de la tabla en un período breve.

Tablas

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 cada conjunto de datos, de modo que Bigtable almacene los datos relacionados en un rango contiguo de filas que puedas consultar por prefijo de clave de fila.

Bigtable tiene un límite de 1,000 tablas por instancia, pero te recomendamos que evites 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.
  • Crear más tablas no mejora el balanceo de cargas y puede aumentar la sobrecarga de administración.

Es lógico que desees una tabla separada para un caso de uso diferente que requiera un esquema distinto, pero no debes usar tablas separadas para datos similares. Por ejemplo, no debes crear una tabla nueva por un año nuevo o 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 tus 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 mantener la versión más reciente de un dato en particular, no la almacenes en una familia de columnas que esté configurada para almacenar 1,000 versiones de algo más. De lo contrario, pagarás para almacenar 999 celdas de datos que no necesitas.

Columnas

Crea tantas columnas como necesites en la tabla. Las tablas de Bigtable son 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 debe hacerlo. Algunos factores contribuyen a esta práctica recomendada:

  • Bigtable demora en procesar cada celda de una fila.
  • Cada celda agrega algo de sobrecarga a la cantidad de datos que se almacenan en tu tabla y que se envían por la red. Por ejemplo, si almacenas 1 KB (1,024 bytes) de datos, sería mucho más eficiente almacenarlos en una sola celda que dividirlos entre 1,024 celdas con 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.

De manera opcional, puedes tratar 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, pensemos en 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 de esa fila puede ser el círculo social en el que se encuentra el amigo. En este ejemplo, las filas podrían verse así:

Clave de fila Fred Gabriel Hiroshi Seo Yoon Jakob
José book-club trabajo tenis
Sofía trabajo school club de ajedrez

Compara este esquema con un esquema para los mismos datos que no trata los calificadores de columnas como datos y, en su lugar, tiene las mismas columnas en cada fila:

Clave de fila Amigo Palco
Jose#1 Fred book-club
Jose#2 Gabriel trabajo
Jose#3 Hiroshi tenis
Sofia#1 Hiroshi trabajo
Sofia#2 Seo Yoon school
Sofia#3 Jakob club de ajedrez

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.

Filas

Mantén el tamaño de todos los valores de una sola fila por debajo de los 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 necesites leer de forma atómica o todos a la vez, en más de una fila, a fin de 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 parte de una solicitud de escritura falla o se debe volver a enviar, esa información no quedará incompleta de forma 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 una 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.

Usa celdas agregadas para almacenar y actualizar datos agregados. Si solo te interesa 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 Cómo agregar valores en el momento de la escritura.

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 ocupan más memoria y almacenamiento, y aumentan el tiempo necesario para 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.

A menudo, 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 filas que se vean de la siguiente manera para que primero ordenen de forma automática por valores con cardinalidad más baja:

        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 agregas una marca de tiempo a una clave de fila, antepón un valor de cardinalidad alta como un ID de usuario para evitar la generación de hotspots.

Claves de fila que provocan que los datos relacionados no se agrupen. Evita las claves de fila que hacen que los datos relacionados se almacenen en rangos de filas no contiguos, ya que leerlos juntos es ineficiente.

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 debes usar una sola clave de fila para cada dispositivo que esté compuesto por el ID de dispositivo y la métrica que se almacena, como 4c410523#memusage, y actualizar la fila varias veces. Este tipo de operación sobrecarga la tablet que almacena la fila de uso frecuente. También puede causar que una fila exceda su límite de tamaño, porque 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 de fechas específico, mediante el cálculo de las claves de inicio y fin adecuadas.

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

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, agregar hash a los valores dificulta el uso de la herramienta Key Visualizer para solucionar problemas con 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

Si a menudo recuperas datos en función del momento en que se registraron, puedes incluir una marca de tiempo como parte de tu clave de fila.

Por ejemplo, es posible que tu aplicación registre datos relacionados con el rendimiento, como el uso de la CPU y la memoria, una vez por segundo para muchas máquinas. Tu clave de fila para estos datos podría combinar un identificador para 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.

Si incluyes marcas de tiempo en la clave de fila, no uses una marca de tiempo sola o al comienzo de una clave de fila. Este patrón hace que las escrituras secuenciales se envíen a un solo nodo, lo que crea un hotspot.

Si sueles recuperar los registros más recientes primero en tus consultas, un patrón que debes tener en cuenta es usar marcas de tiempo inversas en la clave de fila. Este patrón hace que las filas se ordenen de la más reciente a la menos reciente, de modo que los datos más recientes se muestran antes en la tabla. Al igual que con cualquier marca de tiempo, evita comenzar una clave de fila con una marca de tiempo invertida para no generar hotspots.

Si quieres obtener una marca de tiempo invertida, puedes quitarla del valor máximo del lenguaje de programación para números enteros largos (en Java, java.lang.Long.MAX_VALUE).

Para 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. El uso de una tabla para todas las instancias es la forma más eficaz de almacenar y acceder a los datos de varias instancias.

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 ellos, puedes descartar 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 requiera, evita usar información de identificación personal (PII) o datos de usuario en claves de fila o IDs de familia de columnas. Los valores de las claves de fila y las familias de columnas son datos del cliente y del servicio, y las aplicaciones que los usan, como la encriptación o el registro, pueden exponerlos accidentalmente a los usuarios que no deberían tener acceso a datos privados.

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

Nombres de dominio

Puedes almacenar nombres de dominio como datos de Bigtable.

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 en tu clúster y generar hotspots, o tus filas podrían crecer demasiado.

Consultas cambiantes o inciertas

Si no siempre ejecutas las mismas consultas en tus datos o no estás seguro de qué consultas harás, 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 facilita la extracción de los valores individuales más adelante, como json o el formato binario del búfer de protocolo.

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?