En este documento, 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:
Asegúrate de que todos los datos existentes en la base de datos cumplan con las restricciones que introduce la actualización del esquema. Dado que algunas actualizaciones del esquema dependen de los datos reales, no solo del esquema actual, una actualización correcta en una base de datos de prueba no garantiza el éxito en una base de datos de producción. A continuación, hay algunos ejemplos comunes:
- Si agregas una anotación
NOT NULLa una columna existente, comprueba que la columna no contenga ningún valorNULLexistente. - Si acortas la longitud permitida de una columna
STRINGoBYTES, verifica que todos los valores existentes en esa columna cumplan con la restricción de longitud.
- 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 del esquema.
Si realizas demasiadas actualizaciones del esquema en un período breve,
es posible que Spanner
throttle el
procesamiento de las actualizaciones del esquema en cola. Esto se debe a que Spanner limita la cantidad de espacio para almacenar versiones de esquema. Es posible que se limite la actualización del esquema si hay demasiadas versiones de esquema anteriores en el período de retención. La frecuencia máxima de cambios de esquema depende de muchos
factores, uno de ellos es la cantidad total
de columnas en la base de datos. Por ejemplo, una base de datos con 2,000 columnas
(aproximadamente 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. Para ver el estado de
las actualizaciones del esquema en curso, usa el gcloud spanner operations
list comando y filtra por
operaciones de tipo DATABASE_UPDATE_DDL. Para cancelar una actualización del esquema en curso,
usa el comando gcloud spanner operations
cancel y especifica
el ID de la operación.
La forma en que se agrupan en lotes tus declaraciones DDL y su orden dentro de cada lote pueden afectar la cantidad de versiones de esquema que resultan. Para maximizar la cantidad de actualizaciones del esquema que puedes realizar durante un período determinado, debes usar la agrupación en lotes que minimice la cantidad de versiones de esquema. Algunos lineamientos se describen en las actualizaciones grandes.
Como se describe en versiones de esquema, algunas declaraciones DDL crearán varias versiones de esquema, y estas son importantes cuando se considera la agrupación en lotes y el orden dentro de cada lote. Existen dos tipos principales de declaraciones que podrían crear varias versiones de esquema:
- Declaraciones que podrían necesitar propagar datos de índice, como
CREATE INDEX. - Declaraciones que obligan a Spanner a validar los datos existentes, como agregar
NOT NULLo restricciones de longitud.
Sin embargo, estos tipos de declaraciones no siempre crean varias versiones de esquema. Spanner intentará detectar cuándo se pueden optimizar estos tipos de declaraciones para evitar el uso de varias versiones de esquema, lo que depende de la agrupación en lotes. Por ejemplo, una declaración CREATE INDEX que ocurre en el mismo lote que una declaración CREATE TABLE para la tabla base del índice, sin ninguna declaración intermedia para otras tablas, puede evitar la necesidad de propagar los datos del índice porque Spanner puede garantizar que la tabla base esté vacía en el momento en que se crea el índice. En la sección de 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 una sola base de datos dentro de su período de retención. Aumenta el tiempo 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 base de datos relacional, 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. No se recomiendan estos tipos de procesos para Spanner.
- Spanner está optimizado para usar claves primarias en los datos de partición para soluciones de multiusuario. Si usas una solución de multiusuario que usa tablas separadas para cada cliente, ten en cuenta que las actualizaciones del esquema en muchos clientes a la vez pueden generar una gran acumulación de operaciones de actualización del esquema que tardan mucho en completarse.
- Las actualizaciones del esquema que requieren validación o propagación de índice usan más recursos del servidor porque cada declaración crea varias versiones del esquema de forma interna.
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 lote
de una o más CREATE, ALTER, o DROP declaraciones.
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. Esta aplicación de declaración en orden significa que, si deseas que las declaraciones que requieren una propagación inevitable se ejecuten en paralelo (como crear varios índices en tablas grandes existentes), debes enviar esas declaraciones en lotes separados, ya que cada propagación podría tardar mucho tiempo. Si creas una tabla nueva con índices, por otro lado, la práctica recomendada es colocarlos juntos (CREATE TABLE seguido de CREATE INDEX) en un solo lote para evitar la propagación por completo.
Spanner puede combinar y reordenar declaraciones de diferentes lotes, por lo que podría combinar declaraciones 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 table_name ALTER COLUMN column_name STRING(50)
y otro lote de declaraciones contiene ALTER TABLE table_name ALTER COLUMN
column_name STRING(20), Spanner dejará esa columna en uno de
esos dos estados, pero el estado en el que se deja no es determinista.
Opciones para actualizaciones del esquema grandes
La mejor manera de crear una tabla y una gran cantidad de índices en esa tabla es crearlos todos al mismo tiempo, de modo que solo se cree una versión de esquema. La práctica recomendada es crear los índices inmediatamente después de la tabla en la lista de declaraciones DDL. Puedes crear la tabla y sus índices cuando creas la base de datos o en un solo lote grande de declaraciones. Si necesitas crear muchas tablas, cada una con muchos índices, puedes incluir todas las declaraciones en un solo lote. Puedes incluir varios miles de declaraciones en un solo lote cuando todas las declaraciones se pueden ejecutar juntas con una sola versión de esquema.
Cuando una declaración requiere propagar datos de índice o realizar la validación de datos, no se puede ejecutar en una sola versión de esquema. Esto sucede para las declaraciones CREATE INDEX cuando la tabla base del índice ya existe (ya sea porque se creó en un lote anterior de declaraciones DDL o porque había una declaración en el lote entre las declaraciones CREATE TABLE y CREATE INDEX que requería varias versiones de 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 propagación, en particular, usa varias versiones de esquema por índice, por lo que es una buena regla general no crear más de 3 índices nuevos que requieran propagación por día (sin importar cómo se agrupen en lotes, a menos que dicha agrupación pueda evitar la propagación).
Por ejemplo, este lote de declaraciones 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 de 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
Cuando cargas datos de forma masiva en una tabla nueva, puedes crear índices secundarios antes o después de cargar los datos. La carga de datos es más rápida si creas índices después de la carga, pero esto significa que los índices deben propagarse.
Si cargas datos primero y, luego, creas índices, la transferencia de datos es más rápida porque solo se escribe en la tabla, y las propagaciones de índice posteriores pueden escribir los datos del índice en lotes optimizados que son más eficientes que escribir los datos del índice junto con los datos de la tabla. Sin embargo, la propagación de índices requiere varias versiones de esquema y tiene límites; como se indica en las opciones para actualizaciones grandes, no debes crear más de 10 índices que requieran propagación en un solo lote, y es mejor no crear más de 3 índices de este tipo por día.
Como alternativa, puedes crear tablas e índices en el mismo lote, como se describe en opciones para actualizaciones grandes. Esto evita la propagación de índices, pero la carga masiva de datos será más lenta porque cada índice debe actualizarse a medida que se cargan los datos.
La mejor opción en una situación determinada depende de la cantidad de datos que se cargarán, las claves específicas de la tabla y el índice, la cantidad de índices necesarios y la frecuencia con la que se requerirán las operaciones de carga masiva en la misma base de datos. Una regla general es que es mejor crear los índices por separado si se debe cargar una gran cantidad de datos en cada tabla y solo se requieren algunos índices.