Spanner te permite realizar actualizaciones del esquema sin tiempo de inactividad. Puedes actualizar el esquema de una base de datos existente de varias maneras:
En la consola de Google Cloud
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 Descripción general de la base de datos o Descripción general de la tabla.
Usa la herramienta de línea de comandos de
gcloud spanner
Envía un comando
ALTER TABLE
con el elementogcloud spanner databases ddl update
.Con las bibliotecas cliente
Con la API de REST
projects.instances.databases.updateDdl
Con la API de RPC
UpdateDatabaseDdl
Actualizaciones del esquema compatibles
Spanner admite las siguientes actualizaciones del esquema de una base de datos existente:
- Agrega o descarta un esquema con nombre.
- Crear una tabla nueva Las columnas de las tablas nuevas pueden ser
NOT NULL
- Borrar una tabla, si la tabla no tiene otras intercaladas ni índices secundarios
- Crea o borra una tabla con una clave externa.
- Agrega o quita una clave externa de una tabla existente.
- Agregar una columna sin clave a una tabla. Las nuevas columnas sin clave no se pueden
NOT NULL
- Descartar una columna sin clave de cualquier tabla, a menos que la use un índice secundario, clave externa, almacenada generada o una restricción de verificación.
- Agregar
NOT NULL
a una columna sin clave, excepto las columnasARRAY
- Quitar
NOT NULL
de una columna sin 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 de proto de una columna
PROTO
. - Agrega valores nuevos a una definición de
ENUM
y cambia el nombre de los valores existentes conALTER PROTO BUNDLE
- Cambia los mensajes definidos en una
PROTO BUNDLE
de maneras arbitrarias, siempre y cuando que los campos modificados de esos mensajes no se usen como claves en ninguna tabla y que los datos existentes satisfacen las restricciones nuevas. - Aumentar o disminuir el límite de longitud para un tipo
STRING
oBYTES
(incluidoMAX
), a menos que sea una columna de clave primaria que heredada por una o más tablas secundarias - Aumentar o disminuir el límite de longitud de una columna
ARRAY<STRING>
,ARRAY<BYTES>
oARRAY<PROTO>
hasta el máximo permitido - Habilitar o inhabilitar marcas de tiempo de confirmación en las columnas de valor y clave primaria
- Agregar o quitar un índice secundario
- Agrega o quita una restricción de verificación de una tabla existente.
- Agrega o quita una columna generada almacenada de una tabla existente.
- Crea un nuevo paquete de estadísticas del optimizador.
- Crear y administrar vistas.
- Crear y administrar secuencias
- Crear roles de base de datos y otorgar privilegios
- Configura, cambia o descarta el valor predeterminado de una columna.
- Cambia las opciones de la base de datos (
default_leader
oversion_retention_period
, por ejemplo). - Crear y administrar transmisiones de cambios
- Crear y administrar modelos de AA
Actualizaciones de esquemas no compatibles
Spanner no admite las siguientes actualizaciones de esquema de un base de datos:
- Si hay un campo
PROTO
del tipoENUM
al que hace referencia una tabla o una clave de índice, no puedes quitar los valoresENUM
de las enums de proto. (Se admite la eliminación de valoresENUM
de las enums que usan las columnasENUM<>
, incluso cuando esas columnas se usan como claves).
Rendimiento de la actualización del esquema
Las actualizaciones de esquema en Spanner no requieren tiempo de inactividad. Cuando emites un lote de declaraciones DDL a una base de datos de Spanner, puedes continuar escribiendo en la base de datos y leyendo desde ella sin interrupciones mientras Spanner aplica la actualización como operación de larga duración.
El tiempo que tarda ejecutar una declaración DDL está sujeto a si la actualización requiere la validación de los datos existentes o el reabastecimiento de algún dato. Por ejemplo:
si agregas la anotación NOT NULL
a una columna existente, Spanner debe
lee todos los valores en la columna para asegurarte de que esta no contenga
cualquier valor NULL
. Este paso puede demorar bastante si hay muchos datos para validar. Otro ejemplo es si agregas un índice a una base de datos: Spanner reabastece el índice con datos existentes; ese proceso puede tardar mucho tiempo según la definición del índice y el tamaño de la tabla base correspondiente. Sin embargo, si agregas una columna nueva a una tabla, no hay datos que validar, por lo que Spanner puede realizar la actualización con más rapidez.
En resumen, las actualizaciones del esquema que no requieren que Spanner valide los datos existentes pueden completarse en minutos. Las actualizaciones del esquema que requieren validación pueden tardar más, según la cantidad de datos existentes que deban validarse. Sin embargo, la validación de datos ocurre en segundo plano con una prioridad menor que el tráfico de producción. Las actualizaciones del esquema que requieren validación de datos se analizan con más detalle en la sección siguiente.
Actualizaciones del esquema validadas en función de las definiciones de vistas
Cuando realizas una actualización de esquema, Spanner valida que la actualización no invalide las consultas que se usan para definir las vistas existentes. Si la validación no falla, se realizará de forma correcta la actualización del esquema. Si la validación no se realiza correctamente, el falla la actualización del esquema. Cheque Prácticas recomendadas para crear vistas para más detalles.
Actualizaciones del esquema que requieren validación de datos
Puedes realizar actualizaciones del esquema que requieran validar que los datos existentes cumplan con las restricciones nuevas. Cuando una actualización del esquema requiere la validación de datos, Spanner no permite actualizaciones del esquema en conflicto para las entidades del esquema afectadas y valida los datos en segundo plano. Si la validación no falla, se realizará de forma correcta la actualización del esquema. Si la validación falla, la actualización del esquema no se realizará de forma correcta. Las operaciones de validación se ejecutan como operaciones de larga duración. Puedes verificar el estado de estas operaciones para determinar si se realizaron de forma correcta o no.
Por ejemplo, supongamos que definiste el siguiente archivo music.proto
con un
Enumeración RecordLabel
y 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 agregar una tabla Songwriters
en 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 del esquema, pero requieren validación y pueden tardar más en completarse, según la cantidad de datos existentes:
Agregar la anotación
NOT NULL
a una columna sin 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);
Cambiar
BYTES
porSTRING
. Por ejemplo:ALTER TABLE Songwriters ALTER COLUMN OpaqueData STRING(MAX);
Cambiar
INT64/INT32
porENUM
. Por ejemplo:ALTER TABLE Albums ALTER COLUMN Label googlesql.example.music.RecordLabel;
Se quitaron los valores existentes de la definición de enum
RecordLabel
.Habilitar marcas de tiempo de confirmación en una columna
TIMESTAMP
existente. Por ejemplo:ALTER TABLE Albums ALTER COLUMN LastUpdateTime SET OPTIONS (allow_commit_timestamp = true);
Agrega una restricción de verificación a una tabla existente.
Agregar una columna generada almacenada a una tabla existente
Crear una tabla nueva con una clave externa.
Agregar una clave externa a una tabla existente
Estas actualizaciones del esquema fallan si los datos subyacentes no cumplen con las restricciones nuevas. Por ejemplo, la sentencia ALTER TABLE Songwriters ALTER COLUMN Nickname
STRING(MAX) NOT NULL
falla si algún valor de la columna Nickname
es NULL
, porque los datos existentes no cumplen con la restricción NOT NULL
de la definición nueva.
La validación de datos puede tardar varios minutos o varias horas. El tiempo para completar la validación de los datos depende de lo siguiente:
- El tamaño del conjunto de datos
- La capacidad de procesamiento 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 complete la actualización del esquema. Por ejemplo, si agregas NOT NULL
a una
Spanner casi de inmediato comienza a rechazar escrituras de trabajos nuevos
las solicitudes que usan NULL
para la columna. Si la actualización del esquema nuevo al final falla para la validación de datos, habrá un período en el que se bloquearon las escrituras, incluso si el esquema anterior 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 declaraciones en lotes
Si usas Google Cloud CLI, la API de REST o la API de RPC, puedes emitir un
de una o más sentencias CREATE
, ALTER
o DROP
Spanner aplica declaraciones del mismo lote en orden y se detiene en el primer error. Si aplicar una declaración da como resultado un error, esa declaración se revierte. Los resultados de las declaraciones aplicadas antes en el lote no se revierten.
Spanner puede combinar y reordenar instrucciones de lotes diferentes
mezclar sentencias de diferentes lotes en un cambio atómico que
se aplica a la base de datos. Dentro de cada cambio atómico, las declaraciones de diferentes lotes ocurren en un orden arbitrario. Por ejemplo, si un lote de declaraciones
contiene ALTER TABLE MyTable ALTER COLUMN MyColumn STRING(50)
y otra
lote de sentencias 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 de esquema creadas durante las actualizaciones del esquema
Spanner usa el control de versiones de esquemas para que no haya tiempo de inactividad durante del esquema a una base de datos grande. Spanner mantiene la versión anterior del esquema para admitir las lecturas mientras se procesa la actualización del esquema. Spanner Luego, crea una o más versiones nuevas del esquema para procesarlo actualización. Cada versión contiene el resultado de una colección de sentencias en una único cambio atómico.
No es necesario que las versiones de esquema se correspondan uno a uno con lotes de declaraciones DDL ni con declaraciones DDL individuales. Algunas declaraciones DDL individuales, como la creación de índices para tablas base existentes o instrucciones que requieren datos y validaciones de datos, generan varias versiones del esquema. En otros casos, varias declaraciones DDL se pueden agrupar en una sola versión. Las versiones de esquema antiguas pueden consumen una cantidad significativa de recursos de servidores y almacenamiento, y se retienen caducan (ya no son necesarios para entregar lecturas de versiones anteriores de datos).
En la siguiente tabla, se muestra el tiempo que le toma a Spanner actualizar un esquema.
Operación de esquema | Duración estimada |
---|---|
CREATE TABLE |
Minutos |
CREATE INDEX |
Minutos a horas, si la tabla base se creó antes del índice Minutos, si la declaración se ejecuta al mismo tiempo que la declaración |
DROP TABLE |
Minutos |
DROP INDEX |
Minutos |
ALTER TABLE ... ADD COLUMN |
Minutos |
ALTER TABLE ... ALTER COLUMN |
Minutos a horas, si se requiere validación en segundo plano Minutos, si la validación en segundo plano no es necesaria |
ALTER TABLE ... DROP COLUMN |
Minutos |
ANALYZE |
Minutos a horas, según el tamaño de la base de datos. |
Cambios de tipo de datos y flujos de cambios
Si cambias el tipo de datos de una columna que cambia
transmisiones, el campo column_types
de flujos de cambios relevantes posteriores
registros
refleja su nuevo tipo, al igual que los datos JSON de old_values
récords mods
.
El new_values
del campo mods
de un registro de flujos de cambios siempre coincide
el tipo actual de una columna. Cambiar el tipo de datos
de una columna observada
afectará los registros del flujo de cambios anteriores a ese cambio.
En el caso particular de un cambio de BYTES
a STRING
, Spanner valida los valores anteriores de la columna como parte de la actualización del esquema.
Como resultado, Spanner decodificó de forma segura los valores antiguos de tipo BYTES
en cadenas para el momento en que escribe los registros de flujo de cambios posteriores.
Prácticas recomendadas para las actualizaciones del esquema
En las siguientes secciones, se describen las prácticas recomendadas para actualizar esquemas.
Procedimientos previos a la actualización del esquema
Antes de emitir una actualización del esquema, realiza los siguientes pasos:
Verifica que todos los datos existentes en la base de datos que deseas modificar cumplan con las restricciones que impone la actualización del esquema. Como el éxito de algunos tipos de actualizaciones del esquema depende de los datos de la base de datos y no solo del esquema actual, una actualización del esquema correcta de una base de datos de prueba no garantiza una actualización del esquema correcta de una base de datos de producción. A continuación, hay algunos ejemplos comunes:
- Si agregas una anotación
NOT NULL
a una columna existente, comprueba que la columna no contenga ningún valorNULL
existente. - Si reduces la longitud permitida de una columna
STRING
oBYTES
, verifica que todos los valores existentes en esa columna cumplan con la longitud “compute.vmExternalIpAccess”.
- Si agregas una anotación
Si escribes en una columna, tabla o índice que experimenta una actualización del esquema, asegúrate de que los valores que escribes cumplan con las restricciones nuevas.
Si eliminas una columna, una tabla o un índice, asegúrate de no estar escribiendo datos allí ni leyéndolos.
Limita la frecuencia de las actualizaciones de esquemas
Si realizas demasiadas actualizaciones del esquema en un período breve,
puede throttle
el
el procesamiento de las actualizaciones de esquema en cola. Esto se debe a que Spanner limita la cantidad de espacio para almacenar versiones de esquemas. Es posible que se limite la actualización de tu esquema si hay demasiadas versiones de esquema antiguas dentro del período de retención. La tasa máxima de cambios de esquema depende de muchos factores, uno de los cuales es la cantidad total de columnas en la base de datos. Por ejemplo, una base de datos con 2,000 columnas (alrededor de 2,000 filas en INFORMATION_SCHEMA.COLUMNS
) puede realizar como máximo 1,500 cambios de esquema (menos si el cambio de esquema requiere varias versiones) dentro del período de retención. Cómo ver el estado
de actualizaciones de esquema en curso, usa el
gcloud spanner operations list
comando y filtra por operaciones de tipo DATABASE_UPDATE_DDL
. Para cancelar un
actualización continua del esquema, usa el
gcloud spanner operations cancel
y especifica el ID de operación.
La forma en que tus declaraciones DDL se agrupan en lotes y su orden dentro de cada lote afectar la cantidad de versiones de esquema resultantes. Para maximizar la cantidad de actualizaciones de esquema que puedes realizar en un período determinado, deberías usar por lotes que minimice el número de versiones de esquema. Algunas reglas generales se describen en Actualizaciones grandes.
Como se describe en las versiones de esquema, algunas declaraciones DDL se crear múltiples versiones de esquema, y estas son importantes al momento de considerar el procesamiento por lotes y el orden dentro de cada lote. Hay dos tipos principales de declaraciones que podría crear varias versiones de esquema:
- Declaraciones que podrían necesitar reabastecer datos de índice, como
CREATE INDEX
- Declaraciones que podrían necesitar validar datos existentes, como agregar
NOT NULL
Sin embargo, estos tipos de instrucciones no siempre crean varias versiones de esquemas. Spanner intentará detectar cuándo se pueden
para evitar el uso de múltiples versiones de esquema, lo que depende del procesamiento por lotes.
Por ejemplo, una sentencia CREATE INDEX
que ocurra en el mismo lote que una
Declaración CREATE TABLE
para la tabla base del índice, sin ninguna intervención
para otras tablas, puedes evitar la necesidad de reabastecer los datos de los índices
ya que Spanner puede garantizar que la tabla base esté vacía en ese momento
se crea el índice. En la sección Actualizaciones grandes, se describe cómo usar esta propiedad para crear muchos índices de manera eficiente.
Si no puedes agrupar en lotes tus declaraciones DDL para evitar crear muchas versiones de esquema, Debes limitar la cantidad de actualizaciones del esquema al esquema de un solo esquema de base de datos. dentro de su período de retención. Aumenta el período en el que realizas actualizaciones del esquema para permitir que Spanner quite las versiones anteriores del esquema antes de que se creen versiones nuevas.
- Para algunos sistemas de administración de bases de datos relacionales, hay paquetes de software que realizan varias series de actualizaciones del esquema a una versión inferior o una posterior en la base de datos en cada implementación de producción. Estos tipos de procesos no se recomiendan para Spanner
- Spanner está optimizado para usar claves primarias en los datos de partición de las soluciones de multiusuario. Las soluciones de multiusuario que usan tablas separadas para cada cliente pueden generar una gran acumulación de operaciones de actualización del esquema que tardan mucho en completarse.
- Las actualizaciones de esquema que requieren validación o reabastecimiento de índices usan más servidores recursos porque cada instrucción crea varias versiones del esquema internamente.
Opciones para actualizaciones del esquema grandes
La mejor manera de crear una tabla y una gran cantidad de índices en ella es crearlos todos al mismo tiempo, de modo que haya un solo esquema versión creada. Se recomienda crear los índices inmediatamente después de la tabla de la lista de instrucciones de DDL. Puedes crear la tabla y sus índices cuando creas la base de datos o en un solo lote grande de instrucciones. Si necesitas crear muchas tablas, cada una con muchos índices, puedes incluir todas las declaraciones en un solo lote. Puedes incluir varios miles de instrucciones en un solo lote cuando todas las instrucciones se pueden ejecutar juntas con una sola versión de esquema.
Cuando una instrucción requiere reabastecer los datos del índice o realizar la validación de los datos,
no se puede ejecutar
en una sola versión de esquema. Esto sucede para CREATE INDEX
cuando la tabla base del índice ya existe (ya sea porque se
en un lote anterior de declaraciones DDL o porque había una
en el lote entre las sentencias CREATE TABLE
y CREATE INDEX
que
requerían varias versiones de esquema). Spanner requiere que no haya más de 10 declaraciones de este tipo en un solo lote. Creación de índices que requieren
el reabastecimiento de datos usa varias versiones de esquema por índice, por lo que
una buena regla general para crear no más de 3
que requieren un reabastecimiento por día (sin importar cómo se agrupen, a menos que
este procesamiento por lotes puede evitar el reabastecimiento).
Por ejemplo, este lote de instrucciones usará una sola versión de 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);
En cambio, este lote usará muchas versiones de esquema, porque UnrelatedIndex
requiere el reabastecimiento (ya que su tabla base ya debe existir) y que obliga a todos los siguientes índices a requerir el reabastecimiento (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 un lote diferente para minimizar las versiones del esquema.
Espera a que se completen las solicitudes a la API
Cuando realices solicitudes projects.instances.databases.updateDdl
(API de REST) o UpdateDatabaseDdl
(API de RPC), usa projects.instances.databases.operations.get
(API de REST) o GetOperation
(API de RPC), respectivamente, para esperar a que se complete cada solicitud antes de iniciar una solicitud nueva. Esperar a que se complete cada solicitud permite que tu aplicación realice un seguimiento del progreso de las actualizaciones del esquema. También mantiene la acumulación de actualizaciones del esquema pendientes en un tamaño administrable.
Carga masiva
Si cargas datos de forma masiva en tus tablas después de crearlas, suele ser más eficaz crear índices después de cargar los datos. Si agregas varios índices, podría ser más eficaz crear la base de datos con todas las tablas y los índices en el esquema inicial, como se describe en las opciones para actualizaciones grandes.