Spanner te permite hacer actualizaciones de esquemas sin que se produzcan periodos inactivos. Puede actualizar el esquema de una base de datos de varias formas:
En la Google Cloud consola
Envía un comando
ALTER TABLE
en la página Spanner Studio.Para acceder a la página Spanner Studio, haz clic en Spanner Studio en la página de descripción general de la base de datos o de la tabla.
Usar la herramienta de línea de comandos
gcloud spanner
Envía un comando
ALTER TABLE
mediante el comandogcloud spanner databases ddl update
.Usar las bibliotecas de cliente
Usar la API REST de
projects.instances.databases.updateDdl
Usar la API RPC
UpdateDatabaseDdl
Actualizar esquemas compatibles
Spanner admite las siguientes actualizaciones de esquemas de una base de datos:
- Añade o elimina un esquema con nombre.
- Crea una tabla. Las columnas de las tablas nuevas pueden ser
NOT NULL
. - Eliminar una tabla si no hay ninguna otra tabla intercalada en ella y no tiene índices secundarios.
- Crea o elimina una tabla con una clave externa.
- Añadir o quitar una clave externa de una tabla disponible.
- Añade una columna que no sea clave a cualquier tabla. No se pueden crear columnas que no sean de clave.
NOT NULL
- Eliminar una columna que no sea clave de cualquier tabla, a menos que la use un índice secundario, una clave externa, una columna generada almacenada o una restricción de comprobación.
- Añade
NOT NULL
a una columna que no sea clave, excepto a las columnasARRAY
. - Quitar
NOT NULL
de una columna que no sea clave. - Cambiar una columna
STRING
por una columnaBYTES
o una columnaBYTES
por una columnaSTRING
. - Cambiar una columna
PROTO
por una columnaBYTES
o una columnaBYTES
por una columnaPROTO
. - Cambia el tipo de mensaje proto de una columna
PROTO
. - Añade valores a una definición de
ENUM
y cambia el nombre de los valores que ya tengas conALTER PROTO BUNDLE
. - Cambiar los mensajes definidos en un
PROTO BUNDLE
de forma arbitraria, siempre que los campos modificados de esos mensajes no se utilicen como claves en ninguna tabla y que los datos existentes cumplan las nuevas restricciones. - Aumentar o reducir el límite de longitud de un tipo
STRING
oBYTES
(incluidoMAX
), a menos que sea una columna de clave principal heredada por una o varias tablas secundarias. - Aumenta o reduce el límite de longitud de una columna
ARRAY<STRING>
,ARRAY<BYTES>
oARRAY<PROTO>
hasta el máximo permitido. - Habilita o inhabilita las marcas de tiempo de confirmación en las columnas de valor y de clave principal.
- Añade o elimina un índice secundario.
- Añadir o quitar una restricción CHECK de una tabla.
- Añadir o quitar una columna generada almacenada de una tabla.
- Crea un paquete de estadísticas del optimizador.
- Crea y gestiona vistas.
- Crea y gestiona secuencias.
- Crea roles de base de datos y concede privilegios.
- Definir, cambiar o eliminar el valor predeterminado de una columna.
- Cambia las opciones de la base de datos (
default_leader
oversion_retention_period
, por ejemplo). - Crear y gestionar flujos de cambios.
- Crea y gestiona modelos de aprendizaje automático.
Actualizaciones de esquemas no admitidas
Spanner no admite las siguientes actualizaciones de esquema de una base de datos:
- Si hay un campo
PROTO
de tipoENUM
al que hace referencia una clave de tabla o de índice, no puede quitar valoresENUM
de las enumeraciones proto. Se admite la eliminación de valoresENUM
de las enumeraciones que usan las columnasENUM<>
(también cuando esas columnas se usan como claves).
Rendimiento de la actualización del esquema
Las actualizaciones de esquemas en Spanner no requieren tiempo de inactividad. Cuando emites un lote de instrucciones DDL a una base de datos de Spanner, puedes seguir escribiendo y leyendo desde la base de datos sin interrupciones mientras Spanner aplica la actualización como una operación de larga duración.
El tiempo necesario para ejecutar una declaración DDL depende de si esa actualización necesita validar los datos o reponer cualquier información. Por ejemplo, si añade la anotación NOT NULL
a una columna, Spanner debe leer todos los valores de la columna para asegurarse de que no contiene ningún valor NULL
. Este paso puede tardar mucho tiempo si hay que validar una gran cantidad de datos. Otro ejemplo es cuando se añade un índice a una base de datos:
Spanner rellena el índice con los datos que ya existen, y ese proceso puede
llevar mucho tiempo en función de la definición del índice y del tamaño de la
tabla base correspondiente. Sin embargo, si añades una columna a una tabla, no hay datos que validar, por lo que Spanner puede hacer la actualización más rápido.
En resumen, las actualizaciones de esquemas que no requieren que Spanner valide los datos ya existentes pueden completarse en cuestión de minutos. Las actualizaciones de esquemas que requieren validación pueden tardar más tiempo, en función de la cantidad de datos que haya que validar, pero la validación de datos se lleva a cabo en segundo plano y tiene menos prioridad que el tráfico de producción. Las actualizaciones de esquemas que requieren validación de datos se explican con más detalle en la siguiente sección.
Actualizaciones del esquema validadas con las definiciones de la vista
Cuando haces una actualización del esquema, Spanner valida que la actualización no invalide las consultas utilizadas para definir las vistas. Si la validación se realiza correctamente, la actualización del esquema se lleva a cabo. Si la validación no se completa correctamente, la actualización del esquema falla. Consulte las prácticas recomendadas para crear vistas para obtener más información.
Actualizaciones de esquemas que requieren validación de datos
Puede hacer actualizaciones de esquemas que requieran validar que los datos cumplen las nuevas restricciones. Cuando una actualización de esquema requiere validación de datos, Spanner no permite actualizaciones de esquema conflictivas en las entidades de esquema afectadas y valida los datos en segundo plano. Si la validación se realiza correctamente, el esquema se actualiza. Si la validación no se realiza correctamente, la actualización del esquema no se completará. Las operaciones de validación se ejecutan como operaciones de larga duración. Puede consultar el estado de estas operaciones para determinar si se han completado correctamente o no.
Por ejemplo, supongamos que has definido el siguiente archivo music.proto
con un enum RecordLabel
y un mensaje de protocolo Songwriter
:
enum RecordLabel {
COOL_MUSIC_INC = 0;
PACIFIC_ENTERTAINMENT = 1;
XYZ_RECORDS = 2;
}
message Songwriter {
required string nationality = 1;
optional int64 year_of_birth = 2;
}
Para añadir una tabla Songwriters
a tu esquema, sigue estos pasos:
GoogleSQL
CREATE PROTO BUNDLE (
googlesql.example.music.Songwriter,
googlesql.example.music.RecordLabel,
);
CREATE TABLE Songwriters (
Id INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
Nickname STRING(MAX),
OpaqueData BYTES(MAX),
SongWriter googlesql.example.music.Songwriter
) PRIMARY KEY (Id);
CREATE TABLE Albums (
SongwriterId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX),
Label INT32
) PRIMARY KEY (SongwriterId, AlbumId);
Se permiten las siguientes actualizaciones de esquema, pero requieren validación y pueden tardar más en completarse, en función de la cantidad de datos que ya haya:
Añadir la anotación
NOT NULL
a una columna que no sea clave. Por ejemplo:ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL;
Reducir la longitud de una columna. Por ejemplo:
ALTER TABLE Songwriters ALTER COLUMN FirstName STRING(10);
Cambio de
BYTES
aSTRING
. Por ejemplo:ALTER TABLE Songwriters ALTER COLUMN OpaqueData STRING(MAX);
Cambio de
INT64/INT32
aENUM
. Por ejemplo:ALTER TABLE Albums ALTER COLUMN Label googlesql.example.music.RecordLabel;
Se han quitado valores de la definición de la enumeración
RecordLabel
.Habilitar marcas de tiempo de confirmación en una columna
TIMESTAMP
. Por ejemplo:ALTER TABLE Albums ALTER COLUMN LastUpdateTime SET OPTIONS (allow_commit_timestamp = true);
Añadir una restricción CHECK a una tabla disponible.
Añadir una columna generada almacenada a una tabla.
Crear una tabla con una clave externa.
Añadir una clave externa a una tabla disponible.
Estas actualizaciones de esquema fallan si los datos subyacentes no cumplen las nuevas restricciones. Por ejemplo, la instrucción ALTER TABLE Songwriters ALTER COLUMN Nickname
STRING(MAX) NOT NULL
falla si algún valor de la columna Nickname
es NULL
, porque los datos no cumplen la restricción NOT NULL
de la nueva definición.
La validación de datos puede tardar desde varios minutos hasta muchas horas. El tiempo para completar la validación de datos depende de estos aspectos:
- El tamaño del conjunto de datos
- La capacidad de computación de la instancia
- La carga de la instancia
Algunas actualizaciones del esquema pueden cambiar el comportamiento de las solicitudes a la base de datos antes de que se completen. Por ejemplo, si añades NOT NULL
a una columna, Spanner empieza casi inmediatamente a rechazar las escrituras de las nuevas solicitudes que usan NULL
para la columna. Si la nueva actualización del esquema falla en última instancia en la validación de datos, habrá transcurrido un periodo en el que se habrán bloqueado las escrituras, aunque el esquema antiguo las hubiera aceptado.
Puedes cancelar una operación de validación de datos de larga duración con el método
projects.instances.databases.operations.cancel
o con
gcloud spanner operations
.
Orden de ejecución de las instrucciones en lotes
Si usas la CLI de Google Cloud, la API REST o la API RPC, puedes emitir un lote de una o varias CREATE
, ALTER
o DROP
instrucciones.
Spanner aplica las instrucciones del mismo lote en orden y se detiene en el primer error. Si al aplicar una instrucción se produce un error, se revierte esa instrucción. Los resultados de las instrucciones aplicadas anteriormente en el lote no se revierten. Esta aplicación de instrucciones ordenadas significa que, si quieres que determinadas instrucciones se ejecuten en paralelo (por ejemplo, los rellenos de índices, que pueden tardar mucho), debes enviar esas instrucciones en lotes independientes.
Spanner puede combinar y reordenar instrucciones de diferentes lotes, y puede mezclar instrucciones de diferentes lotes en un cambio atómico que se aplica a la base de datos. En cada cambio atómico, las instrucciones de diferentes
lotes se producen en un orden arbitrario. Por ejemplo, si un lote de instrucciones contiene ALTER TABLE MyTable ALTER COLUMN MyColumn STRING(50)
y otro lote de instrucciones contiene ALTER TABLE MyTable ALTER COLUMN MyColumn
STRING(20)
, Spanner dejará esa columna en uno de esos dos estados, pero no se especifica cuál.
Versiones del esquema creadas durante las actualizaciones del esquema
Spanner usa el control de versiones de esquemas para que no haya periodos de inactividad durante una actualización de esquemas en una base de datos grande. Spanner mantiene la versión anterior del esquema para admitir lecturas mientras se procesa la actualización del esquema. A continuación, Spanner crea una o varias versiones nuevas del esquema para procesar la actualización del esquema. Cada versión contiene el resultado de una colección de instrucciones en un único cambio atómico.
Las versiones del esquema no se corresponden necesariamente con lotes de instrucciones DDL ni con instrucciones DDL concretas. Algunas instrucciones DDL individuales, como la creación de índices para tablas base o instrucciones que requieren validación de datos, dan como resultado varias versiones del esquema. En otros casos, se pueden agrupar varias instrucciones DDL en una sola versión. Las versiones antiguas del esquema pueden consumir una cantidad significativa de recursos del servidor y de almacenamiento, y se conservan hasta que caducan (es decir, hasta que ya no se necesitan para atender las lecturas de versiones anteriores de los datos).
En la siguiente tabla se muestra cuánto tiempo tarda Spanner en actualizar un esquema.
Operación de esquema | Duración estimada |
---|---|
CREATE TABLE |
Minutos |
CREATE INDEX |
De minutos a horas, si la tabla base se crea antes del índice. Minutos, si la instrucción se ejecuta al mismo tiempo que la instrucción |
DROP TABLE |
Minutos |
DROP INDEX |
Minutos |
ALTER TABLE ... ADD COLUMN |
Minutos |
ALTER TABLE ... ALTER COLUMN |
De minutos a horas, si se requiere la validación en segundo plano. Minutos, si no se requiere la validación en segundo plano. |
ALTER TABLE ... DROP COLUMN |
Minutos |
ANALYZE |
De minutos a horas, en función del tamaño de la base de datos. |
Cambios en los tipos de datos y en los flujos de cambios
Si cambia el tipo de datos de una columna que monitoriza un flujo de cambios, el campo column_types
de los registros del flujo de cambios posteriores pertinentes reflejará su nuevo tipo, al igual que los datos JSON old_values
del campo mods
de los registros.
El new_values
del campo mods
de un registro de flujo de cambios siempre coincide con el tipo actual de una columna. Cambiar el tipo de datos de una columna monitorizada no afecta a ningún registro de flujo de cambios anterior a ese cambio.
En el caso concreto de un cambio de BYTES
a STRING
, Spanner valida los valores antiguos de la columna como parte de la actualización del esquema.
Por lo tanto, Spanner habrá decodificado de forma segura los valores del tipo antiguo BYTES
en cadenas cuando escriba los registros de flujo de cambios posteriores.
Prácticas recomendadas para las actualizaciones de esquemas
En las siguientes secciones se describen las prácticas recomendadas para actualizar los esquemas.
Procedimientos que debes seguir antes de publicar la actualización del esquema
Antes de emitir una actualización de esquema, sigue estos pasos:
Comprueba que todos los datos que estás cambiando y que se encuentran en la base de datos cumplen las restricciones que está imponiendo la actualización del esquema. Como el éxito de algunos tipos de actualizaciones de esquemas depende de los datos de la base de datos y no solo de su esquema actual, una actualización de esquema correcta de una base de datos de prueba no garantiza que la actualización de esquema de una base de datos de producción también se realice correctamente. A continuación, se indican algunos ejemplos habituales:
- Si vas a añadir una anotación
NOT NULL
a una columna, comprueba que no contenga ningún valorNULL
. - Si vas a reducir la longitud permitida de una columna
STRING
oBYTES
, comprueba que todos los valores de esa columna cumplan la restricción de longitud.
- Si vas a añadir una anotación
Si escribes en una columna, tabla o índice que está experimentando una actualización del esquema, asegúrate de que los valores que escribes cumplen las nuevas restricciones.
Si eliminas una columna, tabla o índice, asegúrate de que no sigues escribiendo ni leyendo en él.
Limitar la frecuencia de las actualizaciones de esquemas
Si realizas demasiadas actualizaciones de esquemas en un breve periodo, Spanner puede throttle
el procesamiento de las actualizaciones de esquemas en cola. Esto se debe a que Spanner limita la cantidad de espacio para almacenar versiones de esquemas. Es posible que se limite la velocidad de actualización del esquema si hay demasiadas versiones antiguas del esquema dentro del periodo de conservación. La tasa máxima de cambios en el esquema depende de muchos factores, uno de ellos es el número total de columnas de la base de datos. Por ejemplo, una base de datos con 2000 columnas (aproximadamente 2000 filas en INFORMATION_SCHEMA.COLUMNS
) puede realizar como máximo 1500 cambios de esquema (menos si el cambio de esquema requiere varias versiones) durante el periodo de conservación. Para ver el estado de las actualizaciones de esquema en curso, usa el comando gcloud spanner operations list
y filtra por operaciones de tipo DATABASE_UPDATE_DDL
. Para cancelar una actualización de esquema en curso, usa el comando gcloud spanner operations cancel
y especifica el ID de operación.
La forma en que se agrupan las instrucciones DDL y el orden de estas en cada lote pueden afectar al número de versiones de esquema que se obtienen. Para maximizar el número de actualizaciones de esquema que puedes realizar en un periodo determinado, debes usar el procesamiento por lotes, que minimiza el número de versiones del esquema. Algunas reglas generales se describen en actualizaciones grandes.
Como se describe en Versiones de esquema, algunas instrucciones DDL crearán varias versiones de esquema, que son importantes a la hora de tener en cuenta la creación de lotes y el orden dentro de cada lote. Hay dos tipos principales de instrucciones que pueden crear varias versiones de un esquema:
- Instrucciones que pueden necesitar rellenar datos de índice, como
CREATE INDEX
- Instrucciones que pueden necesitar validar datos, como añadir
NOT NULL
Sin embargo, estos tipos de instrucciones no siempre crean varias versiones del esquema. Spanner intentará detectar cuándo se pueden optimizar estos tipos de instrucciones para evitar el uso de varias versiones de esquema, lo que depende de la creación de lotes.
Por ejemplo, una instrucción CREATE INDEX
que se produce en el mismo lote que una instrucción CREATE TABLE
para la tabla base del índice, sin ninguna instrucción intermedia para otras tablas, puede evitar tener que rellenar los datos del índice, ya que Spanner puede garantizar que la tabla base esté vacía en el momento en que se cree el índice. En la sección Actualizaciones grandes se describe cómo usar esta propiedad para crear muchos índices de forma eficiente.
Si no puedes agrupar tus instrucciones DDL para evitar crear muchas versiones de esquema, debes limitar el número de actualizaciones de esquema al esquema de una sola base de datos durante su periodo de conservación. Aumenta el periodo durante el que haces actualizaciones de esquema para permitir que Spanner elimine versiones anteriores del esquema antes de crear las versiones nuevas.
- En algunos sistemas de gestión de bases de datos relacionales, hay paquetes de software que hacen una larga serie de actualizaciones de esquemas de actualización y de versiones anteriores de la base de datos en cada implementación de producción. No se recomienda usar estos tipos de procesos en Spanner.
- Spanner está optimizado para usar claves principales con el fin de particionar datos para soluciones multiinquilino. Las soluciones multiempresa que usan tablas independientes para cada cliente pueden generar una gran acumulación de operaciones de actualización de esquemas que tardan mucho tiempo en completarse.
- Las actualizaciones de esquemas que requieren validación o relleno de índices usan más recursos del servidor porque cada instrucción crea varias versiones del esquema internamente.
Opciones para actualizaciones de esquemas grandes
La mejor forma de crear una tabla y un gran número de índices en esa tabla es crear todos los elementos al mismo tiempo, de modo que solo se cree una versión del esquema. Es recomendable crear los índices inmediatamente después de la tabla en la lista de instrucciones DDL. Puedes crear la tabla y sus índices al crear la base de datos o en un único lote grande de instrucciones. Si necesitas crear muchas tablas, cada una con muchos índices, puedes incluir todas las instrucciones en un solo lote. Puedes incluir varios miles de instrucciones en un solo lote cuando todas las instrucciones se puedan ejecutar juntas con una sola versión del esquema.
Cuando una instrucción requiere rellenar datos de índice o realizar una validación de datos, no se puede ejecutar en una sola versión del esquema. Esto ocurre con las instrucciones CREATE INDEX
cuando la tabla base del índice ya existe (ya sea porque se creó en un lote anterior de instrucciones DDL o porque había una instrucción en el lote entre las instrucciones CREATE TABLE
y CREATE INDEX
que requería varias versiones del esquema). Spanner requiere que no haya más de 10 declaraciones de este tipo en un solo lote. La creación de índices que requiere rellenado, en concreto, usa varias versiones de esquema por índice, por lo que es recomendable no crear más de 3 índices nuevos que requieran rellenado al día (independientemente de cómo se agrupen, a menos que se pueda evitar el rellenado).
Por ejemplo, este lote de instrucciones usará una sola versión del esquema:
GoogleSQL
CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), ) PRIMARY KEY (SingerId); CREATE INDEX SingersByFirstName ON Singers(FirstName); CREATE INDEX SingersByLastName ON Singers(LastName); CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), ) PRIMARY KEY (SingerId, AlbumId); CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);
Por el contrario, este lote usará muchas versiones de esquema, ya que UnrelatedIndex
requiere un relleno retroactivo (porque su tabla base ya debe existir), y eso
obliga a todos los índices siguientes a requerir también un relleno retroactivo (aunque
estén en el mismo lote que sus tablas base):
GoogleSQL
CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), ) PRIMARY KEY (SingerId); CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), ) PRIMARY KEY (SingerId, AlbumId); CREATE INDEX UnrelatedIndex ON UnrelatedTable(UnrelatedIndexKey); CREATE INDEX SingersByFirstName ON Singers(FirstName); CREATE INDEX SingersByLastName ON Singers(LastName); CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);
Sería mejor mover la creación de UnrelatedIndex
al final del lote o a otro lote para minimizar las versiones del esquema.
Esperar a que se completen las solicitudes a la API
Cuando hagas solicitudes projects.instances.databases.updateDdl
(API REST) o UpdateDatabaseDdl
(API RPC), usa projects.instances.databases.operations.get
(API REST) o GetOperation
(API RPC), respectivamente, para esperar a que se complete cada solicitud antes de iniciar una nueva. Si esperas a que se complete cada solicitud, tu aplicación podrá monitorizar el progreso de las actualizaciones de tu esquema. También mantiene el registro de actualizaciones de esquemas pendientes en un tamaño gestionable.
Carga en bloque
Si cargas los datos en lote a las tablas después de crearlas, es más eficiente crear índices después de que los datos se hayan cargado. Si vas a añadir varios índices, puede que sea más eficiente crear la base de datos con todas las tablas e índices en el esquema inicial, tal como se describe en las opciones para grandes actualizaciones.