Acerca de los esquemas

En esta página, se analizan los esquemas y se presentan tablas intercaladas, que pueden mejorar el rendimiento de las consultas cuando se consultan tablas en una relación de superior y secundario.

Las bases de datos de Cloud Spanner contienen una o más tablas. Las tablas están estructuradas como filas y columnas. Una o más de las columnas se definen como la clave primaria de la tabla, que identifica de forma única cada fila. Las claves primarias siempre se indexan para la búsqueda rápida de filas y puedes definir índices secundarios en una o más columnas.

Los datos en Cloud Spanner están fuertemente escritos. Debes definir un esquema para cada base de datos, y ese esquema debe especificar el tipo de datos de cada columna de cada tabla. Los tipos de datos incluyen tipos escalares y complejos, que se describen en los tipos de datos en SQL estándar de Google para bases de datos de dialecto SQL de Google Standard y tipos de datos de PostgreSQL en bases de datos de dialecto PostgreSQL.

Relaciones entre tablas superiores y secundarias

Existen dos formas de definir las relaciones entre tablas primarias y secundarias en Cloud Spanner: intercalación de tablas y claves externas.

La intercalación de tablas de Cloud Spanner es una buena opción para muchas relaciones de elementos superiores y secundarios. Con la intercalación, Cloud Spanner ubica físicamente físicamente las filas secundarias con las filas superiores en el almacenamiento. La ubicación conjunta puede mejorar significativamente el rendimiento. Por ejemplo, si tienes una tabla Customers y una tabla Invoices, y tu aplicación recupera con frecuencia todas las facturas de un cliente, puedes definir Invoices como una tabla secundaria intercalada de Customers. Al hacerlo, declaras una relación de localidad de datos entre dos tablas independientes. Estás indicando a Cloud Spanner que almacene una o más filas de Invoices con una fila de Customers.

Asocias una tabla secundaria a una tabla superior con el uso de DDL, que declara la tabla secundaria como intercalada en el superior, y agrega la clave primaria de la tabla superior como la primera parte de la clave primaria compuesta de la tabla secundaria. Para obtener más información sobre intercalación, consulta Crea tablas intercaladas más adelante en este tema.

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.

Google recomienda que elijas representar las relaciones entre tablas primarias y secundarias como tablas intercaladas o como claves externas, pero no de ambas formas. Para obtener más información sobre las claves externas y su comparación con tablas intercaladas, consulta Descripción general de claves externas.

Claves primarias en tablas intercaladas

¿Cómo puedes indicarle a Cloud Spanner qué filas de Invoices y Customers deben almacenarse juntas? Para ello, usa la clave primaria de estas tablas. Para la intercalación, cada tabla debe tener una clave primaria. Si declaras que una tabla es un elemento secundario intercalado de otra tabla, la tabla debe tener una clave primaria compuesta que incluya todos los componentes de la clave primaria superior en el mismo orden y, por lo general, una o más columnas secundarias de tabla secundarias.

Cloud Spanner almacena las filas ordenadas por valores de clave primaria, con filas secundarias insertadas entre las filas superiores. Consulta una ilustración de filas intercaladas en la sección Crea tablas intercaladas de este tema.

En resumen, Cloud Spanner puede ubicar físicamente juntas las filas de las tablas relacionadas. Los ejemplos de esquema muestran cómo se ve este diseño físico.

Selecciona una clave principal.

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. Solo las bases de datos de SQL estándar de Google pueden tener tablas sin una clave primaria.

Es posible que tu aplicación ya tenga un campo que sirva naturalmente como clave primaria. Por ejemplo, para una tabla Customers, puede haber una CustomerId proporcionada por la aplicación que funcione bien como clave primaria. En otros casos, es posible que debas generar una clave primaria cuando insertes la fila. Por lo general, sería un valor entero único sin importancia empresarial (una clave primaria subrogada).

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.

Agrega índices secundarios según las claves primarias

En ciertas circunstancias, el uso de la base de datos puede beneficiarse si agregas índices secundarios basados en claves primarias. Esto sucede en particular si ejecutas consultas que requieren análisis en orden inverso de la clave primaria de una tabla.

Divisiones de bases de datos

Puedes definir jerarquías de relaciones superiores y secundarias intercaladas de hasta siete capas de profundidad, lo que significa que puedes ubicar juntas las filas de siete tablas independientes. Si el tamaño de los datos de las tablas es pequeño, es probable que un solo servidor de Cloud Spanner controle 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 la base de datos crece, Cloud Spanner divide los datos en fragmentos llamados divisiones. Las divisiones individuales pueden moverse de forma independiente respecto de las otras y asignarse a distintos servidores, que pueden estar en diferentes ubicaciones físicas. Una división contiene un rango de filas contiguas. Las claves de inicio y finalización de este rango se denominan “límites de división”. Cloud Spanner agrega y quita de forma automática los límites de división según el tamaño y 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 las 10 filas para que cada uno las administre un servidor diferente, en lugar de permitir que todas las lecturas de esas filas consuman los recursos de un solo servidor.

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 pocos minutos hasta que saturas los recursos de la instancia o se generen casos en los que no se pueden agregar límites de división nuevos (porque tienes una división que cubre solo una fila sin elementos secundarios intercalados).

Ejemplos de esquemas

En los siguientes ejemplos de esquema, se muestra cómo crear tablas superiores y secundarias con y sin intercalación, y se ilustran los diseños físicos correspondientes de los datos.

Cómo crear una tabla superior

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 SingerID es la primera columna.

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 se organizan por filas y columnas.

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

SQL estándar de Google

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

PostgreSQL

CREATE TABLE singers (
singer_id   BIGINT PRIMARY KEY,
first_name  VARCHAR(1024),
last_name   VARCHAR(1024),
singer_info BYTEA
);

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 se define como secundaria de otra tabla).
  • En el caso de las bases de datos de dialecto SQL estándar de Google, las columnas de clave primaria suelen anotarse con NOT NULL (aunque puedes omitir esta anotación si deseas permitir valores NULL en las columnas de clave). Para obtener más información, consulta Columnas 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 en SQL estándar de Google se deben definir con una longitud, que representa la cantidad máxima de caracteres Unicode que se pueden almacenar en el campo. La especificación de longitud es opcional para los tipos varchar y character varying de PostgreSQL. Si desea obtener más información, consulte Tipos de datos escalares para bases de datos de dialecto de SQL estándar de Google y Tipos de datos de PostgreSQL para bases de datos de dialecto de PostgreSQL.

¿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 la clave primaria (&ingt;Singers(1)" luego "Singers(2)" y así sucesivamente, donde &Sters;1)(Singers) representa la fila de la tabla Singers, que tiene la clave 1.

Filas de ejemplo de una tabla almacenada en orden de clave primaria. Hay una línea punteada que indica un límite dividido entre las teclas 3 y 4.

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), y los datos de las divisiones resultantes se asignan a diferentes servidores. A medida que crece esta tabla, es posible que las filas de datos de Singers se almacenen en diferentes ubicaciones.

Cómo crear tablas superiores y secundarias

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

Tabla de álbumes con 5 filas y 3 columnas. Las columnas de clave primaria se encuentran a la izquierda.

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)

SQL estándar de Google

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);

PostgreSQL

CREATE TABLE singers (
singer_id   BIGINT PRIMARY KEY,
first_name  VARCHAR(1024),
last_name   VARCHAR(1024),
singer_info BYTEA
);

CREATE TABLE albums (
singer_id     BIGINT,
album_id      BIGINT,
album_title   VARCHAR,
PRIMARY KEY (singer_id, album_id)
);

El diseño físico de las filas de Singers y Albums se parece al siguiente diagrama, en el que las filas de la tabla Albums se almacenan por clave primaria contigua y, luego, se almacenan según las filas de Singers clave primaria contigua:

Diseño físico de las filas Las claves primarias se muestran en la columna de la izquierda.
    Por ejemplo, Álbumes(2,1), Álbumes(2,2), y así sucesivamente.

Una nota importante sobre el esquema es que Cloud Spanner no supone ninguna relación de localidad de datos entre las tablas Singers y Albums, porque son tablas de nivel superior. A medida que la base de datos crece, Cloud Spanner puede agregar límites de división entre cualquiera de las filas. 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, esto puede generar una penalización de rendimiento debido a la necesidad de coordinar lecturas y actualizaciones entre recursos distintos. Si tu aplicación a menudo necesita recuperar información sobre todos los álbumes de un cantante en particular, debes crear Albums como una tabla secundaria intercalada de Singers, que ubica juntas las filas de las dos tablas en la dimensión de clave primaria. En el siguiente ejemplo, se explica esto con más detalle.

Crear tablas intercaladas

Una tabla intercalada es una tabla que declaras como secundaria de otra tabla porque deseas que las filas de la tabla secundaria se almacenen físicamente con la fila superior asociada. Como se mencionó con anterioridad, la clave primaria de la tabla superior debe ser la primera parte de la clave primaria compuesta de la tabla secundaria.

Cuando diseñas tu aplicación de música, supongamos que te das cuenta de que la app necesita acceder con frecuencia a las filas secundarias desde la tabla Albums cuando accede a una fila Singers. Por ejemplo, cuando accedes a la fila Singers(1), también debes acceder a las filas Albums(1, 1) y Albums(1, 2). En este caso, Singers y Albums deben tener una relación de localidad de datos sólida. Para declarar esta relación de localidad de datos, crea Albums como una tabla secundaria intercalada de Singers.

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)

SQL estándar de Google

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;

PostgreSQL

CREATE TABLE singers (
 singer_id   BIGINT PRIMARY KEY,
 first_name  VARCHAR(1024),
 last_name   VARCHAR(1024),
 singer_info BYTEA
 );

CREATE TABLE albums (
 singer_id     BIGINT,
 album_id      BIGINT,
 album_title   VARCHAR,
 PRIMARY KEY (singer_id, album_id)
 )
 INTERLEAVE IN PARENT singers ON DELETE CASCADE;

Notas sobre este esquema:

  • SingerId, que es la primera parte de la clave primaria de la tabla secundaria Albums, también es la clave primaria de la 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 se declara que Albums es una tabla secundaria intercalada 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 sus filas secundarias. Si una tabla secundaria no tiene esta anotación, o la anotación es ON DELETE NO ACTION, debes borrar las filas secundarias antes de 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 superior. Por ejemplo, "Cantantes(1)", luego Álbumes(1, 1), "Álbumes(1, 2), etc.", y así sucesivamente.
  • La relación de localidad de datos de cada cantante y los datos de sus álbumes se conserva si esta base de datos se divide, siempre que el tamaño de una fila de Singers y todas sus filas de Albums se mantengan por debajo del límite de tamaño de división y que no haya un 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

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 de canciones con 6 filas y 4 columnas. Las tres columnas más a la izquierda comprenden la clave primaria.

Songs debe tener una clave primaria que incluya todas las claves primarias de las tablas que se encuentran por encima de ella en 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)

SQL estándar de Google

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;

PostgreSQL

CREATE TABLE singers (
 singer_id   BIGINT PRIMARY KEY,
 first_name  VARCHAR(1024),
 last_name   VARCHAR(1024),
 singer_info BYTEA
 );

CREATE TABLE albums (
 singer_id     BIGINT,
 album_id      BIGINT,
 album_title   VARCHAR,
 PRIMARY KEY (singer_id, album_id)
 )
 INTERLEAVE IN PARENT singers ON DELETE CASCADE;

CREATE TABLE songs (
 singer_id     BIGINT,
 album_id      BIGINT,
 track_id      BIGINT,
 song_name     VARCHAR,
 PRIMARY KEY (singer_id, album_id, track_id)
 )
 INTERLEAVE IN PARENT albums ON DELETE CASCADE;

En el siguiente diagrama, se muestra una vista física de las filas intercaladas.

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.

En este ejemplo, a medida que aumenta la cantidad de cantantes, Cloud Spanner agrega límites de división entre los cantantes para conservar la localidad de datos entre un cantante y sus datos de álbum y canción. Sin embargo, si el tamaño de una fila de cantante y sus filas secundarias superan el límite de tamaño de división, o se detecta un hotspot en las filas secundarias, Cloud Spanner intenta agregar límites de división para aislar esa fila del hotspot junto con todas las filas secundarias debajo de él.

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 de forma lógica, intercalarlas físicamente de esta manera puede mejorar el rendimiento, ya que las tablas se unen de forma previa y te permiten acceder a las filas relacionadas a la vez que minimizan los accesos de almacenamiento.

Se une con tablas intercaladas

Si es posible, une los datos de las tablas intercaladas por clave primaria. Debido a que cada fila intercalada generalmente se almacena físicamente 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 almacenamiento y el tráfico de red. En el siguiente ejemplo, Singers y Albums se unen en la clave primaria SingerId.

SQL estándar de Google

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

PostgreSQL

SELECT s.first_name, a.album_title
FROM singers AS s JOIN albums AS a ON s.singer_id = a.singer_id;

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

En SQL estándar de Google, si deseas almacenar NULL en una columna de clave primaria, omite la cláusula NOT NULL para esa columna en el esquema. (Las bases de datos de dialecto de PostgreSQL no admiten objetos NULL en una columna de clave primaria).

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 arquitecturas 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 quiera almacenar el contenido de 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
1AliciaTrentor
2GabrielWright
Base de datos 3: Eagan Records
SingerId FirstName LastName
1BenjamínMartínez
2HannahHarris

Multiusuario administrado con esquema

Otra forma de diseñar para multiusuario en Cloud Spanner es tener todos los clientes en una sola tabla en una base de datos única y usar un valor de clave primaria diferente para cada cliente. Por ejemplo, puedes incluir una columna de clave CustomerId en tus tablas. Si defines CustomerId como primera columna de clave, los datos de cada cliente tendrán una buena localidad. Cloud Spanner puede usar divisiones de bases de datos de forma eficaz para maximizar el rendimiento según el tamaño de los datos y los patrones de carga. En el siguiente ejemplo, hay una sola tabla Singers para todos los clientes:

Base de datos de multiusuario de Cloud Spanner
CustomerId SingerId FirstName LastName
11MarcRichards
12CatalinaSmith
21AliciaTrentor
22GabrielWright
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 índices y tablas por instancia. Según la cantidad de clientes, es posible que no sea posible tener bases de datos o 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.

Si deseas obtener más información sobre otros patrones de administración de datos y el diseño de aplicaciones para multiusuario, consulta Implementa instancias múltiples en Cloud Spanner.