Estadísticas de reparto

En esta página se describe cómo detectar y depurar puntos de acceso en tu base de datos. Puedes acceder a estadísticas sobre los puntos de acceso en divisiones con GoogleSQL y PostgreSQL.

Spanner almacena tus datos como un espacio de claves contiguo, ordenado por las claves principales de tus tablas e índices. Una división es un intervalo de filas de un conjunto de tablas o un índice. El inicio de la división se denomina inicio de la división. El límite de división establece el final de la división. La división incluye el inicio de la división, pero no el límite de la división.

En Spanner, los puntos de acceso son situaciones en las que se envían demasiadas solicitudes al mismo servidor, lo que satura los recursos del servidor y puede provocar latencias altas. Los splits afectados por los hotspots se denominan splits calientes o splits templados.

La estadística de punto de acceso de una división (identificada en el sistema como CPU_USAGE_SCORE) es una medición de la carga de una división que está limitada por los recursos disponibles en el servidor. Esta medición se expresa como un porcentaje. Si más del 50% de la carga de una división está limitada por los recursos disponibles, se considera que la división es cálida. Si se limita el 100% de la carga de una división, se considera que la división está activa.

Spanner usa la división basada en la carga para distribuir de forma uniforme la carga de datos entre los servidores de la instancia. Las divisiones cálidas y activas se pueden mover entre servidores para equilibrar la carga o se pueden dividir en divisiones más pequeñas. Sin embargo, es posible que Spanner no pueda equilibrar la carga, incluso después de varios intentos de división, debido a antipatrones en la aplicación. Por lo tanto, es posible que los puntos de acceso persistentes que duren al menos 10 minutos necesiten más pasos para solucionar los problemas y posibles cambios en la aplicación.

Las estadísticas de divisiones activas de Spanner te ayudan a identificar las divisiones en las que se producen puntos de acceso. Después, puedes hacer los cambios que necesites en tu aplicación o esquema. Puede obtener estas estadísticas de las tablas de sistema SPANNER_SYS.SPLIT_STATS_TOP_MINUTE mediante instrucciones SQL.

Acceder a las estadísticas de la división en caliente

Spanner proporciona las estadísticas de divisiones activas en el esquema SPANNER_SYS. Los datos de SPANNER_SYS solo están disponibles a través de las interfaces de GoogleSQL y PostgreSQL. Puedes acceder a estos datos de las siguientes formas:

Los siguientes métodos de lectura única que proporciona Spanner no admiten SPANNER_SYS:

  • Realizar una lectura fuerte desde una sola fila o varias filas en una tabla.
  • Realizar una lectura inactiva de una sola fila o varias filas en una tabla.
  • Leer desde una sola fila o varias filas en un índice secundario.

Estadísticas de división de tiempo

Usa la siguiente tabla para monitorizar las divisiones en caliente:

  • SPANNER_SYS.SPLIT_STATS_TOP_MINUTE: muestra los parciales que están activos durante intervalos de 1 minuto.

Estas tablas tienen las siguientes propiedades:

  • Cada tabla contiene datos de intervalos de tiempo no superpuestos de la duración que se especifica en el nombre de la tabla.
  • Los intervalos se basan en la hora del reloj:

    • Los intervalos de 1 minuto terminan en el minuto.
  • Después de cada intervalo, Spanner recoge datos de todos los servidores y, poco después, los pone a disposición en las tablas SPANNER_SYS.

    Por ejemplo, a las 11:59:30, los intervalos más recientes disponibles para las consultas SQL son los siguientes:

    • 1 minuto: 11:58:00-11:58:59
  • Spanner agrupa las estadísticas por divisiones.

  • Cada fila contiene un porcentaje que indica la intensidad de un split, por cada split del que Spanner registra estadísticas durante el intervalo especificado.

  • Si menos del 50% de la carga de una división está limitada por los recursos disponibles, Spanner no registra la estadística. Si Spanner no puede almacenar todas las divisiones activas durante el intervalo, el sistema prioriza las divisiones con el porcentaje de CPU_USAGE_SCORE más alto durante el intervalo especificado. Si no se devuelve ninguna división, significa que no hay puntos de acceso.

Esquema de tabla

En la siguiente tabla se muestra el esquema de la tabla de las siguientes estadísticas:

  • SPANNER_SYS.SPLIT_STATS_TOP_MINUTE
Nombre de la columna Tipo Descripción
INTERVAL_END TIMESTAMP Fin del intervalo de tiempo durante el que la división ha estado activa.
SPLIT_START STRING Clave inicial del intervalo de filas de la división. El inicio de la división también puede ser <begin>, lo que indica el principio del espacio de la clave.
SPLIT_LIMIT STRING Clave límite del intervalo de filas de la división. El límite: key también puede ser <end>, lo que indica el final del espacio de la clave|
CPU_USAGE_SCORE INT64 El CPU_USAGE_SCORE % de las divisiones. Un porcentaje de A CPU_USAGE_SCORE del 50% indica la presencia de divisiones | cálidas o calientes |
AFFECTED_TABLES STRING ARRAY Las tablas cuyas filas pueden estar en la división

Claves de inicio y límite de división

Una división es un intervalo de filas contiguo de una base de datos y se define por sus claves inicial y límite. Una división puede ser una sola fila, un intervalo de filas estrecho o un intervalo de filas amplio, y puede incluir varias tablas o índices.

Las columnas SPLIT_START y SPLIT_LIMIT identifican las claves principales de una división activa o semiactiva.

Ejemplo de esquema

El siguiente esquema es una tabla de ejemplo de los temas de esta página.

GoogleSQL

CREATE TABLE Users (
  UserId INT64 NOT NULL,
  FirstName STRING(MAX),
  LastName STRING(MAX),
) PRIMARY KEY(UserId);

CREATE INDEX UsersByFirstName ON Users(FirstName DESC);

CREATE TABLE Threads (
  UserId INT64 NOT NULL,
  ThreadId INT64 NOT NULL,
  Starred BOOL,
) PRIMARY KEY(UserId, ThreadId),
  INTERLEAVE IN PARENT Users ON DELETE CASCADE;

CREATE TABLE Messages (
  UserId INT64 NOT NULL,
  ThreadId INT64 NOT NULL,
  MessageId INT64 NOT NULL,
  Subject STRING(MAX),
  Body STRING(MAX),
) PRIMARY KEY(UserId, ThreadId, MessageId),
  INTERLEAVE IN PARENT Threads ON DELETE CASCADE;

CREATE INDEX MessagesIdx ON Messages(UserId, ThreadId, Subject),
INTERLEAVE IN Threads;

PostgreSQL

CREATE TABLE users
(
   userid    BIGINT NOT NULL PRIMARY KEY,-- INT64 to BIGINT
   firstname VARCHAR(max),-- STRING(MAX) to VARCHAR(MAX)
   lastname  VARCHAR(max)
);

CREATE INDEX usersbyfirstname
  ON users(firstname DESC);

CREATE TABLE threads
  (
    userid   BIGINT NOT NULL,
    threadid BIGINT NOT NULL,
    starred  BOOLEAN, -- BOOL to BOOLEAN
    PRIMARY KEY (userid, threadid),
    CONSTRAINT fk_threads_user FOREIGN KEY (userid) REFERENCES users(userid) ON
    DELETE CASCADE -- Interleave to Foreign Key constraint
  );

CREATE TABLE messages
  (
    userid    BIGINT NOT NULL,
    threadid  BIGINT NOT NULL,
    messageid BIGINT NOT NULL PRIMARY KEY,
    subject   VARCHAR(max),
    body      VARCHAR(max),
    CONSTRAINT fk_messages_thread FOREIGN KEY (userid, threadid) REFERENCES
    threads(userid, threadid) ON DELETE CASCADE
  -- Interleave to Foreign Key constraint
  );

CREATE INDEX messagesidx ON messages(userid, threadid, subject), REFERENCES
threads(userid, threadid);

Supongamos que tu espacio de claves tiene este aspecto:

CLAVE PRINCIPAL
<begin>
Users()
Threads()
Users(2)
Users(3)
Threads(3)
Threads(3,"a")
Messages(3,"a",1)
Messages(3,"a",2)
Threads(3, "aa")
Users(9)
Users(10)
Threads(10)
UsersByFirstName("abc")
UsersByFirstName("abcd")
<end>

Ejemplo de divisiones

A continuación, se muestran algunos ejemplos de divisiones para que sepas cómo son.

SPLIT_START y SPLIT_LIMIT pueden indicar la fila de una tabla o un índice, o bien pueden ser <begin> y <end>, que representan los límites del espacio de claves de la base de datos. SPLIT_START y SPLIT_LIMIT también pueden contener claves truncadas, que son claves que preceden a cualquier clave completa de la tabla. Por ejemplo, Threads(10) es un prefijo de cualquier fila Threads intercalada en Users(10).

SPLIT_START SPLIT_LIMIT AFFECTED_TABLES EXPLICACIÓN
Users(3) Users(10) UsersByFirstName, Users, Threads, Messages y MessagesIdx La división empieza en la fila con UserId=3 y termina en la fila anterior a la fila con UserId = 10. La división contiene las filas de la tabla Users y todas sus filas de tablas intercaladas de UserId=3 a 10.
Messages(3,"a",1) Threads(3,"aa") Threads, Messages, MessagesIdx La división empieza en la fila con UserId=3, ThreadId="a" y MessageId=1, y termina en la fila anterior a la fila con la clave de UserId=3 y ThreadsId = "aa". La división contiene todas las tablas entre Messages(3,"a",1) y Threads(3,"aa"). Como split_start y split_limit están intercalados en la misma fila de la tabla de nivel superior, la división contiene las filas de las tablas intercaladas entre el inicio y el límite. Consulta la descripción general de los esquemas para saber cómo se colocan las tablas intercaladas.
Messages(3,"a",1) <end> UsersByFirstName, Users, Threads, Messages y MessagesIdx La división empieza en la tabla de mensajes en la fila con la clave UserId=3, ThreadId="a" y MessageId=1. La división contiene todas las filas de split_start a <end>, el final del espacio de claves de la base de datos. Todas las filas de las tablas que siguen a split_start, como Users(4), se incluyen en la división.
<begin> Users(9) UsersByFirstName, Users, Threads, Messages y MessagesIdx La división empieza en <begin>, el principio del espacio de claves de la base de datos, y termina en la fila anterior a la fila Users con UserId=9. Por lo tanto, la división tiene todas las filas de la tabla anteriores a Users, todas las filas de la tabla Users anteriores a UserId=9 y las filas de sus tablas intercaladas.
Messages(3,"a",1) Threads(10) UsersByFirstName, Users, Threads, Messages y MessagesIdx La división empieza en Messages(3,"a", 1) intercalada en Users(3) y termina en la fila anterior a Threads(10). Threads(10) es una clave dividida truncada que es un prefijo de cualquier clave de la tabla Threads intercalada en Users(10).
Users() <end> UsersByFirstName, Users, Threads, Messages y MessagesIdx La división empieza en la clave de división truncada de Users(), que precede a cualquier clave completa de la tabla Users. La división se extiende hasta el final del espacio de claves posible en la base de datos. Por lo tanto, affected_tables cubre la tabla Users, sus tablas e índices intercalados y todas las tablas que puedan aparecer después de los usuarios.
Threads(10) UsersByFirstName("abc") UsersByFirstName, Users, Threads, Messages y MessagesIdx La división empieza en la fila Threads con UserId = 10 y termina en el índice UsersByFirstName de la clave anterior a "abc".

Consultas de ejemplo para encontrar divisiones de tiempo

En el siguiente ejemplo se muestra una instrucción SQL que puede usar para obtener las estadísticas de divisiones activas. Puedes ejecutar estas instrucciones SQL mediante las bibliotecas de cliente, gcloud o la Google Cloud consola.

GoogleSQL

SELECT t.split_start,
       t.split_limit,
       t.cpu_usage_score,
       t.affected_tables,
FROM   SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE  t.interval_end =
  (SELECT MAX(interval_end)
  FROM    SPANNER_SYS.SPLIT_STATS_TOP_MINUTE)
ORDER BY  t.cpu_usage_score DESC;

PostgreSQL

SELECT t.split_start,
       t.split_limit,
       t.cpu_usage_score,
       t.affected_tables
FROM   SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE  t.interval_end = (
  SELECT MAX(interval_end)
  FROM   SPANNER_SYS.SPLIT_STATS_TOP_MINUTE
)
ORDER BY t.cpu_usage_score DESC;

El resultado de la consulta tiene este aspecto:

SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE AFFECTED_TABLES
Users(13) Users(76) 82 Messages,Users,Threads
Users(101) Users(102) 90 Messages,Users,Threads
Threads(10, "a") Threads(10, "aa") 100 Messages,Threads
Messages(631, "abc", 1) Messages(631, "abc", 3) 100 Messages
Threads(12, "zebra") Users(14) 76 Messages,Users,Threads
Users(620) <end> 100 Messages,Users,Threads

Conservación de datos de las estadísticas de división activa

Como mínimo, Spanner conserva los datos de cada tabla durante el siguiente periodo:

  • SPANNER_SYS.SPLIT_STATS_TOP_MINUTE: intervalos que abarcan las 6 horas anteriores.

Solucionar problemas de puntos conflictivos con estadísticas de división en caliente

En esta sección se describe cómo detectar y solucionar problemas de puntos de acceso.

Seleccionar un periodo para investigar

Consulta las métricas de latencia de tu base de datos de Spanner para encontrar el periodo en el que tu aplicación experimentó una latencia y un uso de CPU altos. Por ejemplo, puede mostrarte que un problema empezó alrededor de las 22:50 del 18 de mayo del 2024.

Buscar hotspotting persistente

Como Spanner equilibra la carga con la división basada en la carga, te recomendamos que investigues si el hotspotting ha continuado durante más de 10 minutos. Para ello, puedes consultar la tabla SPANNER_SYS.SPLIT_STATS_TOP_MINUTE, como se muestra en el siguiente ejemplo:

GoogleSQL

SELECT Count(DISTINCT t.interval_end)
FROM   SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE  t.cpu_usage_score >= 50
  AND  t.interval_end >= "interval_end_date_time"
  AND  t.interval_end <= "interval_end_date_time";

Sustituye interval_end_date_time por la fecha y la hora del intervalo, con el formato 2024-05-18T17:40:00Z.

PostgreSQL

SELECT COUNT(DISTINCT t.interval_end)
FROM   SPLIT_STATS_TOP_MINUTE t
WHERE  t.cpu_usage_score >= 50
  AND  t.interval_end >= 'interval_end_date_time'::timestamptz
  AND  t.interval_end <= 'interval_end_date_time'::timestamptz;

Sustituye interval_end_date_time por la fecha y la hora del intervalo, con el formato 2024-05-18T17:40:00Z.

Si el resultado de la consulta anterior es igual a 10, significa que tu base de datos está experimentando un punto de acceso que puede requerir más depuración.

Busca las divisiones con el nivel de CPU_USAGE_SCORE más alto

En este ejemplo, ejecutamos el siguiente SQL para encontrar los intervalos de filas con el nivel de CPU_USAGE_SCORE más alto:

GoogleSQL

SELECT t.split_start,
       t.split_limit,
       t.affected_tables,
       t.cpu_usage_score
FROM   SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE  t.cpu_usage_score >= 50
  AND  t.interval_end = "interval_end_date_time";

Sustituye interval_end_date_time por la fecha y la hora del intervalo, con el formato 2024-05-18T17:40:00Z.

PostgreSQL

SELECT t.split_start,
       t.split_limit,
       t.affected_tables,
       t.cpu_usage_score
FROM   SPLIT_STATS_TOP_MINUTE t
WHERE  t.cpu_usage_score = 100
  AND  t.interval_end = 'interval_end_date_time'::timestamptz;

Sustituye interval_end_date_time por la fecha y la hora del intervalo, con el formato 2024-05-18T17:40:00Z.

El SQL anterior genera el siguiente resultado:

SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE AFFECTED_TABLES
Users(180) <end> 85 Messages,Users,Threads
Users(24) Users(76) 76 Messages,Users,Threads

En esta tabla de resultados, podemos ver que se han producido puntos de acceso en dos divisiones. La división basada en la carga de Spanner puede intentar resolver los puntos de acceso en estas divisiones. Sin embargo, es posible que no pueda hacerlo si hay patrones problemáticos en el esquema o en la carga de trabajo. Para detectar si hay divisiones que requieren tu intervención, te recomendamos que monitorices las divisiones durante al menos 10 minutos. Por ejemplo, la siguiente consulta SQL monitoriza la primera división de los últimos diez minutos.

GoogleSQL

SELECT t.interval_end,
       t.split_start,
       t.split_limit,
       t.cpu_usage_score
FROM   SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE  t.split_start = "users(180)"
  AND  t.split_limit = "<end>"
  AND  t.interval_end >= "interval_end_date_time"
  AND  t.interval_end <= "interval_end_date_time";

Sustituye interval_end_date_time por la fecha y la hora del intervalo, con el formato 2024-05-18T17:40:00Z.

PostgreSQL

SELECT t.interval_end,
       t.split_start,
       t.split_limit,
       t.cpu_usage_score
FROM   SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE  t.split_start = 'users(180)'
  AND  t.split_limit = ''
  AND  t.interval_end >= 'interval_end_date_time'::timestamptz
  AND  t.interval_end <= 'interval_end_date_time'::timestamptz;

Sustituye interval_end_date_time por la fecha y la hora del intervalo, con el formato 2024-05-18T17:40:00Z.

El SQL anterior genera el siguiente resultado:

INTERVAL_END SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE
2024-05-18T17:46:00Z Users(180) <end> 85
2024-05-18T17:47:00Z Users(180) <end> 85
2024-05-18T17:48:00Z Users(180) <end> 85
2024-05-18T17:49:00Z Users(180) <end> 85
2024-05-18T17:50:00Z Users(180) <end> 85

Parece que la división ha estado activa durante los últimos minutos. Puedes observar la división durante más tiempo para determinar que la división basada en la carga de Spanner mitiga el punto de acceso. Puede haber casos en los que Spanner no pueda equilibrar la carga más.

Por ejemplo, consulta la tabla SPANNER_SYS.SPLIT_STATS_TOP_MINUTE. Consulta los siguientes ejemplos.

GoogleSQL

SELECT t.interval_end,
      t.split_start,
      t.split_limit,
      t.cpu_usage_score
FROM  SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE t.interval_end >= "interval_end_date_time"
      AND t.interval_end <= "interval_end_date_time";

Sustituye interval_end_date_time por la fecha y la hora del intervalo, con el formato 2024-05-18T17:40:00Z.

PostgreSQL

SELECT t.interval_end,
       t.split_start,
       t.split_limit,
       t._cpu_usage
FROM   SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE  t.interval_end >= 'interval_end_date_time'::timestamptz
  AND  t.interval_end <= 'interval_end_date_time'::timestamptz;

Sustituye interval_end_date_time por la fecha y la hora del intervalo, con el formato 2024-05-18T17:40:00Z.

Fila activa única

En el siguiente ejemplo, parece que Threads(10,"spanner") está en una fila dividida que ha permanecido activa durante más de 10 minutos. Esto puede ocurrir cuando hay una carga persistente en una fila popular.

INTERVAL_END SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE
2024-05-16T20:40:00Z Threads(10,"spanner") Threads(10,"spanner1") 62
2024-05-16T20:41:00Z Threads(10,"spanner") Threads(10,"spanner1") 62
2024-05-16T20:42:00Z Threads(10,"spanner") Threads(10,"spanner1") 62
2024-05-16T20:43:00Z Threads(10,"spanner") Threads(10,"spanner1") 62
2024-05-16T20:44:00Z Threads(10,"spanner") Threads(10,"spanner1") 62
2024-05-16T20:45:00Z Threads(10,"spanner") Threads(10,"spanner1") 62
2024-05-16T20:46:00Z Threads(10,"spanner") Threads(10,"spanner1") 80
2024-05-16T20:47:00Z Threads(10,"spanner") Threads(10,"spanner1") 80
2024-05-16T20:48:00Z Threads(10,"spanner") Threads(10,"spanner1") 80
2024-05-16T20:49:00Z Threads(10,"spanner") Threads(10,"spanner1") 100
2024-05-16T20:50:00Z Threads(10,"spanner") Threads(10,"spanner1") 100

Spanner no puede equilibrar la carga de esta clave única porque no se puede dividir más.

Punto de acceso móvil

En el siguiente ejemplo, la carga se desplaza por divisiones contiguas a lo largo del tiempo y pasa a una nueva división en intervalos de tiempo.

INTERVAL_END SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE
2024-05-16T20:40:00Z Threads(1,"a") Threads(1,"aa") 100
2024-05-16T20:41:00Z Threads(1,"aa") Threads(1,"ab") 100
2024-05-16T20:42:00Z Threads(1,"ab") Threads(1,"c") 100
2024-05-16T20:43:00Z Threads(1,"c") Threads(1,"ca") 100

Esto puede ocurrir, por ejemplo, debido a una carga de trabajo que lee o escribe claves en orden creciente monotónico. Spanner no puede equilibrar la carga para mitigar los efectos de este comportamiento de la aplicación.

Balanceo de carga normal

Spanner intenta equilibrar la carga añadiendo más divisiones o moviendo las divisiones. En el siguiente ejemplo se muestra cómo podría ser.

INTERVAL_END SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE
2024-05-16T20:40:00Z Threads(1000,"zebra") <end> 82
2024-05-16T20:41:00Z Threads(1000,"zebra") <end> 90
2024-05-16T20:42:00Z Threads(1000,"zebra") <end> 100
2024-05-16T20:43:00Z Threads(1000,"zebra") Threads(2000,"spanner") 100
2024-05-16T20:44:00Z Threads(1200,"c") Threads(2000) 92
2024-05-16T20:45:00Z Threads(1500,"c") Threads(1700,"zach") 76
2024-05-16T20:46:00Z Threads(1700) Threads(1700,"c") 76
2024-05-16T20:47:00Z Threads(1700) Threads(1700,"c") 50
2024-05-16T20:48:00Z Threads(1700) Threads(1700,"c") 39

En este caso, la división más grande del 16 de mayo del 2024 a las 17:40:00 (GMT) se dividió en otra más pequeña y, como resultado, la estadística CPU_USAGE_SCORE disminuyó. Es posible que Spanner no cree divisiones en filas individuales. Las divisiones reflejan la carga de trabajo que provoca la estadística CPU_USAGE_SCORE alta.

Si has observado un split caliente persistente durante más de 10 minutos, consulta las prácticas recomendadas para mitigar los puntos calientes.

Prácticas recomendadas para mitigar los puntos de acceso

Si el balanceo de carga no reduce la latencia, el siguiente paso es identificar la causa de los puntos de acceso. Después, tienes dos opciones: reducir la carga de trabajo de los puntos de acceso o optimizar el esquema y la lógica de la aplicación para evitar los puntos de acceso.

Identificar la causa

  • Usa Estadísticas de bloqueos y transacciones para buscar transacciones que tengan un tiempo de espera de bloqueo alto en las que la clave de inicio del intervalo de filas esté dentro de la división activa.

  • Usa Estadísticas de consultas para buscar consultas que lean de la tabla que contiene la división activa y que hayan aumentado recientemente la latencia o tengan una relación de latencia a CPU más alta.

  • Usa Consultas activas más antiguas para buscar consultas que lean de la tabla que contiene la división activa y que tengan una latencia superior a la esperada.

Algunos casos especiales que debes tener en cuenta:

  • Comprueba si el tiempo de vida (TTL) se ha habilitado recientemente. Si hay muchas divisiones de datos antiguos, el TTL puede aumentar los niveles de CPU_USAGE_SCORE durante las eliminaciones masivas. En este caso, el problema debería resolverse por sí solo una vez que se completen las eliminaciones iniciales.

Optimizar la carga de trabajo

  • Sigue las prácticas recomendadas de SQL. Considera la posibilidad de usar lecturas obsoletas, escrituras que no realicen lecturas primero o añadir índices.
  • Sigue las prácticas recomendadas de Schema. Asegúrate de que tu esquema esté diseñado para gestionar el equilibrio de carga y evitar los puntos de acceso.

Siguientes pasos