Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Esquema y modelo de datos

Resumen del modelo de datos

Una base de datos de Cloud Spanner puede contener una o más tablas. Estas tablas son similares a las de las bases de datos relacionales, ya que están estructuradas con filas, columnas y valores, y contienen claves primarias. En Cloud Spanner, se aplican tipos estrictos de datos. Debes definir un esquema para cada base de datos, en el que se especifiquen los tipos de datos de todas las columnas de cada tabla. Entre los tipos de datos permitidos, se incluyen los escalares y de arreglo, que se explican con más detalle en este artículo. También puedes definir uno o más índices secundarios en una tabla.

Relaciones entre tablas superiores y secundarias

Hay dos formas de definir relaciones entre elementos superiores y secundarios en Cloud Spanner: intercalación de tabla y claves externas.

La intercalación de tablas de Cloud Spanner es una buena opción para muchas relaciones entre tablas principales y secundarias en las que la clave primaria de la tabla secundaria incluye las columnas de clave primaria de la tabla principal. La ubicación conjunta de las filas secundarias con sus filas principales puede mejorar significativamente el rendimiento. Por ejemplo, si tienes las tablas Customers y Invoices, y tu aplicación recupera con frecuencia todas las facturas de un cliente determinado, puedes definir Invoices como tabla secundaria de Customers. De esta manera, declaras una relación de localidad de datos entre dos tablas que son independientes en cuanto a lógica; es decir, le indicas a Cloud Spanner que almacene físicamente una o más filas de Invoices junto a una fila de Customers.

Para obtener un análisis más detallado sobre la intercalación, consulta Crea tablas intercaladas a continuación.

Las claves externas son una solución de elementos principales y secundarios más general y abordan casos prácticos adicionales. No están limitadas a las columnas de clave primaria, y las tablas pueden tener varias relaciones de clave exterior, tanto como un superior en algunas relaciones, y un elemento secundario en otras. Sin embargo, una relación de clave externa no implica la ubicación conjunta de las tablas en la capa de almacenamiento.

Para obtener más información sobre las claves externas y sus comparaciones con tablas intercaladas, consulta la descripción general de las claves forenses.

Claves primarias

¿Cómo puedes indicarle a Cloud Spanner qué filas de Invoices y Customers deben almacenarse juntas? Mediante la clave primaria de ambas tablas. Cada tabla debe tener una clave primaria, y esta clave puede estar compuesta por cero o más columnas de esa tabla. Si declaras que una tabla es la secundaria de otra, las columnas de clave primaria de la tabla superior deben ser el prefijo de la clave primaria de la tabla secundaria. Esto significa que si la clave primaria de una tabla superior está compuesta por N columnas, la clave primaria de cada una de sus tablas secundarias también debe estar compuesta por esas mismas N columnas, en el mismo orden y comenzando con la misma columna.

Cloud Spanner almacena las filas ordenadas por valores de clave primaria, con filas secundarias insertadas entre las filas superiores que comparten el mismo prefijo de clave primaria. Esta inserción de filas secundarias entre filas superiores a lo largo de la dimensión de la clave primaria se denomina intercalación, y las tablas secundarias también se denominan tablas intercaladas (consulta una ilustración de filas intercaladas en la sección Crea tablas intercaladas de más abajo).

En resumen, Cloud Spanner puede ubicar físicamente juntas las filas de las tablas relacionadas. En los ejemplos de esquema que aparecen más abajo, se ilustra esta disposición física.

Elige una clave primaria

La clave primaria identifica de manera única cada fila de una tabla. Si quieres actualizar o borrar las filas existentes de una tabla, esta debe tener una clave primaria compuesta por una o más columnas (una tabla sin columnas de clave primaria solo puede tener una fila). Es posible que tu aplicación ya tenga un campo que sirva naturalmente como clave primaria. En el ejemplo anterior de la tabla Customers, podría haber un CustomerId proporcionado por la aplicación que puede funcionar bien como clave primaria. En otros casos, es posible que debas generar una clave primaria cuando insertes la fila, como un valor INT64 único que generes.

En todos los casos, debes tener cuidado de no crear hotspots con la clave primaria que elijas. Por ejemplo, si insertas registros con una clave que es un número entero que aumenta monótonamente, siempre se insertará al final del espacio de claves. Esta opción es poco recomendable, ya que Cloud Spanner divide los datos entre servidores según los intervalos de claves. Esto significa que las inserciones se dirigirán a un solo servidor y se creará un hotspot. Existen técnicas que pueden distribuir la carga entre varios servidores y evitar los hotspots:

  • Genera un hash de la clave y almacénalo en una columna. Usa la columna de hash (o la columna de hash más la columna de la clave única) como clave primaria.
  • Cambia el orden de las columnas en la clave primaria.
  • Usa un identificador único universal (UUID). Se recomienda usar un UUID de versión 4, ya que esta utiliza valores aleatorios en los bits de orden superior. No uses un algoritmo de UUID (como uno de versión 1) que almacene la marca de tiempo en los bits de orden superior.
  • Revierte los bits de los valores secuenciales.

Divisiones de bases de datos

Puedes definir jerarquías de relaciones superiores y secundarias entre tablas de hasta siete capas de profundidad, lo que significa que puedes ubicar juntas las filas de siete tablas independientes en cuanto a lógica. Si el tamaño de los datos de las tablas es pequeño, es probable que un solo servidor de Cloud Spanner administre tu base de datos. Pero ¿qué sucede cuando crecen las tablas relacionadas y comienzan a alcanzar los límites de recursos de un servidor individual? Cloud Spanner es una base de datos distribuida, lo que significa que, a medida que crecen las bases de datos, Cloud Spanner las divide en fragmentos llamados “divisiones”. Cada división se puede mover de forma independiente y asignarse a diferentes servidores, que pueden encontrarse en ubicaciones físicas distintas. Una división tiene un rango de filas contiguas. Las claves de inicio y fin de este rango se denominan “límites de división”. Cloud Spanner agrega y quita automáticamente estos límites de división según el tamaño o la carga, lo que cambia la cantidad de divisiones de la base de datos.

División basada en la carga

Veamos un ejemplo de cómo Cloud Spanner realiza la división basada en la carga para mitigar los hotspots de lectura. Supongamos que tienes una base de datos que contiene una tabla con 10 filas que se leen con más frecuencia que el resto. Cloud Spanner puede agregar límites de división entre cada una de esas 10 filas para que un servidor diferente las administre cada una, en lugar de permitir que todas las lecturas de esas filas consuman los recursos de un solo servidor. las rutas "a GCP".

Como regla general, si sigues las prácticas recomendadas para el diseño de esquemas, Cloud Spanner puede mitigar los hotspots de modo que la capacidad de procesamiento de lectura deba mejorar cada algunos minutos hasta saturar los recursos en tu instancia. o se generan casos en los que no se pueden agregar nuevos límites de división (porque tienes una división que abarca solo una fila sin elementos secundarios intercalados)

Ejemplos de esquemas

En los siguientes ejemplos de esquema, se muestra cómo crear tablas de Cloud Spanner con y sin relaciones jerárquicas y se ilustran las disposiciones físicas correspondientes de los datos.

Crea una tabla

Supongamos que quieres crear una aplicación de música y necesitas una tabla simple que almacene filas de datos de cantantes:

Tabla de cantantes con 5 filas y 4 columnas

Vista lógica de las filas de una tabla sencilla llamada Singers. La columna de la clave primaria aparece a la izquierda de la línea en negrita.

Ten en cuenta que la tabla contiene una columna de clave primaria, SingerId, que aparece a la izquierda de la línea en negrita, y que las tablas están organizadas por filas, columnas y valores.

Puedes definir la tabla con un esquema de Cloud Spanner como este:

CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);

Ten en cuenta lo siguiente sobre el esquema de ejemplo:

  • Singers es una tabla que se encuentra en la raíz de la jerarquía de la base de datos (porque no está definida como secundaria de otra tabla).
  • Las columnas de clave primaria suelen tener la anotación NOT NULL (aunque puedes omitirla si deseas permitir valores NULL en columnas de clave. Obtén más información en Columnas de clave).
  • Las columnas que no se incluyen en la clave primaria se denominan columnas sin clave y pueden tener una anotación NOT NULL opcional.
  • Las columnas que usan los tipos STRING o BYTES deben definirse con una longitud, que representa la cantidad máxima de caracteres Unicode que se pueden almacenar en el campo (obtén más detalles en la sección sobre los tipos de datos escalares).

¿Cómo es la disposición física de las filas de la tabla Singers? En el siguiente diagrama, se muestran las filas de la tabla Singers almacenadas por clave primaria contigua (o sea, ordenadas según ese valor). Es decir, “Singers(1)”, luego “Singers(2)”, y así sucesivamente, en donde “Singers(1)” representa la fila de la tabla Singers que tiene la clave 1.

Filas de ejemplo de una tabla almacenada en orden de clave contigua

Disposición física de las filas de la tabla Singers, con un límite de división de ejemplo que causa que distintos servidores administren las divisiones

En el diagrama anterior, se ilustra un límite de división de ejemplo entre las filas con las claves Singers(3) y Singers(4), que causa que se asignen a distintos servidores los datos de las divisiones creadas. Esto significa que a, medida que aumenta esta tabla, es posible que se almacenen en diferentes ubicaciones las filas de datos de Singers.

Crea varias tablas

Supongamos que ahora quieres agregar algunos datos básicos sobre los álbumes de cada cantante a la aplicación de música:

Tabla Albums con 5 filas y 3 columnas

Vista lógica de las filas de la tabla Albums. Las columnas de claves primarias aparecen a la izquierda de la línea en negrita.

Ten en cuenta que la clave primaria de Albums se compone de dos columnas: SingerId y AlbumId. Esto permite asociar cada álbum con su cantante. En el siguiente esquema de ejemplo, se definen las tablas Albums y Singers en la raíz de la jerarquía de la base de datos, lo que las convierte en tablas del mismo nivel:

-- Schema hierarchy:
-- + Singers (sibling table of Albums)
-- + Albums (sibling table of Singers)
CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
  SingerId     INT64 NOT NULL,
  AlbumId      INT64 NOT NULL,
  AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId);

La disposición física de las filas Singers y Albums es similar al diagrama. Las filas de la tabla Albums se almacenan por clave primaria contigua y, luego, se almacenan de la misma manera las filas de Singers:

Disposición física de las filas: Las filas de Albums y Singers se almacenan según el valor de la clave

Disposición física de las filas de las tablas Singers y Albums, ambas ubicadas en la raíz de la jerarquía de la base de datos

Un detalle importante sobre el esquema anterior es que Cloud Spanner no supone ninguna relación de localidad de datos entre las tablas Singers y Albums, ya que son tablas de nivel superior. A medida que crece la base de datos, Cloud Spanner puede agregar límites de división entre cualquiera de las filas que se muestran arriba. Esto significa que las filas de la tabla Albums podrían terminar en una división distinta a las de las filas de la tabla Singers, y ambas divisiones podrían moverse independientemente una de otra.

Según las necesidades de la aplicación, podría ser aceptable permitir que los datos de Albums se ubiquen en divisiones diferentes a las de los datos de Singers. Sin embargo, si en la aplicación necesitas recuperar frecuentemente datos sobre todos los álbumes de un cantante determinado, debes crear la tabla Albums como secundaria de Singers, lo que ubica juntas las filas de ambas tablas con la dimensión de la clave primaria. En el siguiente ejemplo, se explica esta situación de forma más detallada.

Crea tablas intercaladas

Supongamos que, mientras diseñas la aplicación de música, te das cuenta de que necesitas acceder con frecuencia a las filas de las tablas Singers y Albums para obtener una clave primaria determinada (p. ej., cada vez que accedes a la fila Singers(1), también debes acceder a Albums(1, 1) y Albums(1, 2)). En otras palabras, Singers y Albums deben tener una relación estrecha de localidad de datos.

Para declarar esta relación de localidad de datos, crea Albums como tabla secundaria o “intercalada” de Singers. Como se mencionó en Claves primarias, una tabla intercalada es una tabla que declaras como secundaria de otra para que sus filas se almacenen físicamente juntas con la fila superior asociada. Además, el prefijo de la clave primaria de una tabla secundaria debe ser la clave primaria de la tabla superior.

La línea en negrita del esquema que aparece a continuación es un ejemplo de cómo crear Albums como tabla intercalada de Singers.

-- Schema hierarchy:
-- + Singers
--   + Albums (interleaved table, child table of Singers)
CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
  SingerId     INT64 NOT NULL,
  AlbumId      INT64 NOT NULL,
  AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

Notas sobre este esquema:

  • SingerId, que es el prefijo de la clave primaria de la tabla secundaria Albums, también es la clave primaria de su tabla superior Singers. Esto no es necesario si Singers y Albums están en el mismo nivel de jerarquía, pero es necesario en este esquema porque Albums se declara como tabla secundaria de Singers.
  • La anotación ON DELETE CASCADE indica que, cuando se borra una fila de la tabla superior, también se borran automáticamente las filas secundarias de esta tabla (es decir, todas las filas que comienzan con la misma clave primaria). Si una tabla secundaria no la incluye (o si agregas la anotación ON DELETE NO ACTION), debes borrar manualmente las filas secundarias para borrar la fila superior.
  • Las filas intercaladas se ordenan primero según las filas de la tabla superior y, luego, según las filas contiguas de la tabla secundaria que comparten la clave primaria de la tabla superior, es decir, “Singers(1)”, seguida de “Albums(1, 1)”, “Albums(1, 2)” y así sucesivamente.
  • Si se dividiera esta base de datos, se conservarían la relación de localidad de datos de cada cantante y los datos de sus álbumes, siempre que el tamaño de una fila de cantante y todas sus filas de Albums permanezcan por debajo de los 4 GB. sin hotspot en ninguna de estas filas de Albums.
  • La fila superior debe existir antes de que puedas insertar filas secundarias. La fila superior puede ya existir en la base de datos o puede insertarse antes de la inserción de las filas secundarias en la misma transacción.

Disposición física de las filas: Las filas de Albums se intercalan entre las filas de Singers

Disposición física de las filas de la tabla Singers y su tabla secundaria Albums

Crea una jerarquía de tablas intercaladas

La relación de superior y secundaria entre Singers y Albums se puede extender a más tablas descendientes. Por ejemplo, puedes crear una tabla intercalada llamada Songs como secundaria de Albums para almacenar la lista de pistas de cada álbum:

Tabla Songs con 6 filas y 4 columnas

Vista lógica de las filas de la tabla Songs. Las columnas de claves primarias aparecen a la izquierda de la línea en negrita.

Songs debe tener una clave primaria compuesta por todas las claves primarias de las tablas que se encuentran en niveles superiores de la jerarquía, es decir, SingerId y AlbumId.

-- Schema hierarchy:
-- + Singers
--   + Albums (interleaved table, child table of Singers)
--     + Songs (interleaved table, child table of Albums)
CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
  SingerId     INT64 NOT NULL,
  AlbumId      INT64 NOT NULL,
  AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

CREATE TABLE Songs (
  SingerId     INT64 NOT NULL,
  AlbumId      INT64 NOT NULL,
  TrackId      INT64 NOT NULL,
  SongName     STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId, TrackId),
  INTERLEAVE IN PARENT Albums ON DELETE CASCADE;

En el siguiente diagrama, se representa una vista física de las filas intercaladas. En este ejemplo, a medida que crece la cantidad de cantantes, Cloud Spanner agrega límites de división entre los cantantes para preservar la localidad de los datos entre un cantante y los datos de sus álbumes y canciones. Sin embargo, si el tamaño de una fila de cantante y sus filas secundarias supera el límite de 4 GB, o se detecta un hotspot en las filas secundarias, Cloud Spanner intentará agregar límites de división a _intercalado.mesas para aislar esa fila del hotspot junto con todas las filas secundarias debajo.

A continuación, se muestra una vista física de las filas intercaladas. A menos que el tamaño de una sola fila de cantante y todas sus filas secundarias superen el límite de 4 GB, o se detecte un hotspot en las filas secundarias, Cloud Spanner prefiere agregar límites de división entre los cantantes para conservar los datos. La localidad entre un cantante y sus datos de álbumes y canciones.

Vistas físicas de las filas: Los datos de Songs se intercalan entre los de Albums, que, a su vez, se intercalan entre los datos de Singers.

Disposición física de las filas de las tablas Singers, Albums y Songs, que forman una jerarquía de tablas intercaladas

En resumen, una tabla superior junto con todas sus tablas secundarias y descendientes forman una jerarquía de tablas en el esquema. Si bien cada tabla de la jerarquía es independiente en cuanto a lógica, intercalarlas físicamente de esta manera puede mejorar el rendimiento, ya que las tablas se unen de forma previa, lo que te permite acceder a filas relacionadas al mismo tiempo y minimizar los accesos al disco.

Si es posible, une los datos de las tablas intercaladas por clave primaria. Dado que cada fila intercalada generalmente se almacena de manera física en la misma división que su fila superior, Cloud Spanner puede realizar uniones localmente según la clave primaria, lo que minimiza el acceso al disco y el tráfico de red. En el siguiente ejemplo, Singers y Albums se unen según la clave primaria, SingerId:

SELECT s.FirstName, a.AlbumTitle
FROM Singers AS s JOIN Albums AS a ON s.SingerId = a.SingerId;

Se recomienda intercalar tablas en Cloud Spanner para acceder a los datos relacionados de uno a varios a los que se accede con frecuencia.

Columnas de clave

No es posible modificar las claves de una tabla. Es decir, no puedes agregar una columna de clave a una tabla existente ni quitar una columna de clave que ya exista.

Almacena valores NULL

Las columnas de clave primaria se pueden definir para almacenar valores NULL. Si quieres almacenar valores NULL en una columna de clave primaria, omite la cláusula NOT NULL para esa columna en el esquema.

Este es un ejemplo de omisión de la cláusula NOT NULL en la columna de clave primaria SingerId. Ten presente que, como SingerId es la clave primaria, solo puede haber una fila como máximo en la tabla Singers que almacene valores NULL en esa columna.

CREATE TABLE Singers (
  SingerId   INT64,
  FirstName  STRING(1024),
  LastName   STRING(1024),
) PRIMARY KEY (SingerId);

La propiedad para admitir valores NULL de la columna de clave primaria debe coincidir entre las declaraciones de las tablas superior y secundaria. En este ejemplo, no se permite usar Albums.SingerId INT64 NOT NULL. La declaración de clave debe omitir la cláusula NOT NULL porque también se omite en Singers.SingerId.

CREATE TABLE Singers (
  SingerId   INT64,
  FirstName  STRING(1024),
  LastName   STRING(1024),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
  SingerId     INT64 NOT NULL,  -- NOT ALLOWED!
  AlbumId      INT64 NOT NULL,
  AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

Tipos no permitidos

Estas columnas no pueden ser de tipo ARRAY:

  • Las columnas de clave de una tabla
  • Las columnas de clave de un índice

Diseña para multiusuario

Si almacenas datos que pertenecen a diferentes clientes, te recomendamos que proporciones la opción de multiusuario. Por ejemplo, es posible que un servicio de música requiera almacenar cada sello discográfico por separado.

Multiusuario clásico

La forma clásica de diseñar para multiusuario es crear una base de datos independiente para cada cliente. En este ejemplo, cada base de datos tiene su propia tabla Singers:

Base de datos 1: Ackworth Records
SingerId FirstName LastName
1MarcRichards
2CatalinaSmith
Base de datos 2: Cama Records
SingerId FirstName LastName
3MarcRichards
4GabrielWright
Base de datos 3: Eagan Records
SingerId FirstName LastName
1BenjamínMartínez
2HannahHarris

Usa un patrón de administración de datos de esquema para los usuarios multiusuario de Cloud Spanner

Otra forma de diseñar para multiusuario en Cloud Spanner es usar un valor de clave primaria distinto para cada cliente. Debes incluir una clave CustomerId o una similar en las tablas. Si defines CustomerId como primera columna de clave, los datos de cada cliente tendrán una buena localidad. Cloud Spanner divide automáticamente los datos en los nodos según el tamaño y los patrones de carga. En este ejemplo, existe una única tabla Singers para todos los clientes:

Base de datos de multiusuario de Cloud Spanner
CustomerId SingerId FirstName LastName
11MarcRichards
12CatalinaSmith
23MarcRichards
24GabrielWright
31BenjamínMartínez
32HannahHarris

Existen restricciones que debes tener en cuenta en caso de que debas tener bases de datos separadas para cada usuario:

  • Existen límites para la cantidad de bases de datos por instancia y de tablas por base de datos. Según la cantidad de clientes, es posible que no puedas tener bases de datos ni tablas separadas.
  • Agregar nuevos índices no entrelazados y tablas puede tomar mucho tiempo. Es posible que no puedas conseguir el rendimiento que deseas si el diseño del esquema depende de agregar nuevos índices y tablas.

Si quieres crear bases de datos independientes, podrías tener más éxito si distribuyes las tablas en bases de datos de manera que cada base tenga una cantidad baja de cambios de esquema por semana.

Si creas índices y tablas separadas para cada cliente de tu aplicación, no pongas todos los índices y tablas en la misma base de datos. En su lugar, repártelos en muchas bases de datos para mitigar los problemas de rendimiento que se producen por la creación de una gran cantidad de índices. También existen límites para la cantidad de índices y tablas por base de datos.

A fin de obtener más información sobre otros patrones de administración de datos y el diseño de aplicaciones para instancias múltiples, consulta Cómo implementar instancias múltiples en Cloud Spanner.