En una tabla distribuida de PolarDB-X, las consultas que no incluyen la clave de partición provocan un escaneo completo en todos los nodos de datos. Esto reduce el rendimiento al límite de un solo nodo y elimina el escalado lineal. Un índice secundario global (GSI) evita los escaneos completos de particiones porque permite definir un esquema de particionamiento independiente para un índice. De esta manera, cualquier columna se convierte en una ruta de consulta eficiente.
Funcionamiento de los GSI
PolarDB-X almacena los datos de las tablas en varios nodos de datos y los particiona mediante una clave designada. Las consultas que incluyen la clave de partición se enrutan directamente a la partición correspondiente. Si no la incluyen, se distribuyen a todas las particiones.
Cuando un sistema tiene N nodos de datos, una consulta con clave de partición genera una carga promedio de 1/N en cada nodo. Un escaneo completo de particiones impone una carga de 1 en cada uno. Por lo tanto, el límite de rendimiento disminuye al de un solo nodo y el sistema pierde el escalado lineal.
Un GSI resuelve este problema porque actúa como una tabla particionada especial que duplica columnas específicas de la tabla principal. Se particiona horizontalmente con una clave definida por el usuario, distinta de la clave de partición de la tabla principal. Cuando una consulta coincide con la clave de partición del GSI, PolarDB-X la enruta a la partición correspondiente del GSI y recupera las filas coincidentes. Después, obtiene las columnas adicionales de la tabla principal. Este proceso evita el escaneo completo de particiones.
PolarDB-X utiliza transacciones distribuidas para mantener una coherencia de datos sólida entre la tabla principal y sus GSI.
Los GSI también admiten:
DDL en línea: cree, modifique y elimine GSI sin bloquear la tabla.
Columnas de cobertura personalizadas: almacene columnas adicionales en el GSI para reducir o eliminar las búsquedas en la tabla principal.
Índices invisibles: pruebe el efecto de un GSI en los planes de consulta sin exponerlo al optimizador de consultas. Así podrá validar el rendimiento del índice antes de habilitarlo en producción.
Tipos de GSI
GSI
Un GSI estándar particiona los datos del índice mediante una columna distinta a la clave de partición de la tabla principal. Cuando una consulta coincide con la clave de partición del GSI, PolarDB-X la enruta a la partición correspondiente y busca las columnas restantes en la tabla principal.
Example: La tabla user está particionada por user_id. Para admitir consultas eficientes por name, cree un GSI en name.
CREATE TABLE user(
user_id bigint,
name varchar(10),
addr varchar(30),
GLOBAL INDEX `g_i_name` (name) PARTITION BY HASH(name),
PRIMARY KEY(user_id)
) PARTITION BY KEY(user_id);
Con g_i_name configurado, una consulta que filtra por name se enruta a la partición correspondiente del índice en lugar de escanear todas las particiones de user.
UGSI
Un índice secundario global único (UGSI) tiene todas las propiedades de un GSI estándar. Además, aplica una restricción UNIQUE global en toda la tabla distribuida.
Ejemplo: La tabla user2 está particionada por user_id. Para garantizar que phone sea único de forma global en todas las particiones, cree un UGSI en phone.
CREATE TABLE user2(
user_id bigint,
phone varchar(20),
addr varchar(30),
UNIQUE GLOBAL INDEX `g_i_phone`(phone) PARTITION BY HASH(phone),
PRIMARY KEY(user_id)
) PARTITION BY KEY(user_id);
GSI agrupado
De forma predeterminada, un GSI agrupado almacena todas las columnas de la tabla principal, no solo la clave del índice y las columnas de cobertura. Como el índice contiene todas las columnas, las consultas nunca necesitan buscar en la tabla principal. Esto elimina por completo la sobrecarga de búsqueda.
La desventaja es que un GSI agrupado ocupa la misma cantidad de espacio en disco que la tabla principal.
Ejemplo: La tabla order_tbl está particionada por order_id. Para admitir consultas rápidas por user_id sin búsquedas en la tabla principal, cree un GSI agrupado en user_id.
CREATE TABLE order_tbl(
order_id bigint,
user_id bigint,
addr varchar(30),
info text,
create_time datetime,
CLUSTERED INDEX `cg_i_user`(user_id) PARTITION BY HASH(user_id),
PRIMARY KEY(order_id)
) PARTITION BY KEY(order_id);
Al consultar por user_id, PolarDB-X enruta la consulta a la partición correspondiente de cg_i_user y lee todos los datos necesarios directamente desde el índice.
Cuándo usar cada tipo
|
Escenario |
Tipo recomendado |
|
Consultas por una columna que no es clave de partición, donde se acepta la búsqueda en la tabla principal |
GSI |
|
Consultas por una columna que no es clave de partición, cuando la columna debe ser única de forma global |
UGSI |
|
Consultas por una columna que no es clave de partición, si eliminar la sobrecarga de búsqueda es prioritario |
GSI agrupado |
Rendimiento
Los GSI mejoran el rendimiento de lectura y reducen el de escritura. A continuación se muestran pruebas de referencia de Sysbench que ilustran el impacto a gran escala.
Rendimiento de lectura
| Tabla | Hilos | QPS de select_random_ranges | Latencia promedio (ms) | Percentil 95 (ms) | QPS de select_random_points | Latencia promedio (ms) | Percentil 95 (ms) |
|---|---|---|---|---|---|---|---|
| Tabla particionada | 128 | 2,769.17 | 46.21 | 99.33 | 5,226.99 | 24.48 | 42.61 |
| 256 | 3,415.64 | 144.97 | 144.97 | 5,476.76 | 46.73 | 82.96 | |
| 512 | 3,272.46 | 156.31 | 257.95 | 5,290.67 | 96.72 | 179.94 | |
| 1024 | 2,453.16 | 416.12 | 539.71 | 5,165.31 | 198.07 | 404.61 | |
| Tabla particionada + GSI | 128 | 9,662.11 | 13.24 | 25.28 | 22,584.89 | 5.66 | 9.73 |
| 256 | 10,431.73 | 24.52 | 51.02 | 25,558.26 | 10.01 | 17.95 | |
| 512 | 15,634.51 | 32.72 | 73.13 | 27,116.56 | 18.86 | 39.65 | |
| 1024 | 22,948.76 | 44.53 | 108.68 | 32,509.87 | 31.43 | 73.13 |
Con un GSI en la columna de índice:
QPS de consultas por rango: 3,415.64 → 22,948.76 — 571% improvement
QPS de consultas puntuales: 5,476.76 → 32,509.87 — 493% improvement
Rendimiento de escritura
| Tabla | Hilos | QPS de solo escritura | Latencia promedio (ms) | Percentil 95 (ms) | QPS de lectura y escritura | Latencia promedio (ms) | Percentil 95 (ms) |
|---|---|---|---|---|---|---|---|
| Tabla particionada | 128 | 86,548.12 | 8.87 | 10.27 | 113,655.28 | 22.52 | 26.2 |
| 256 | 115,774.71 | 13.26 | 19.29 | 149,677.52 | 34.19 | 44.17 | |
| 512 | 143,928.94 | 20.51 | 34.95 | 14,555.16 | 70.28 | 112.67 | |
| 1024 | 153,501.7 | 39.53 | 70.55 | 132,150.69 | 131.58 | 287.38 | |
| Tabla particionada + GSI | 128 | 52,069.22 | 14.25 | 18.28 | 90,074.59 | 28.41 | 33.72 |
| 256 | 66,250.79 | 23.17 | 32.53 | 114,420.32 | 44.73 | 57.87 | |
| 512 | 75,700.74 | 39.1 | 59.99 | 111,093.61 | 92.09 | 142.39 | |
| 1024 | 76,557.94 | 80.14 | 134.9 | 101,828.32 | 182.51 | 350.33 |
Con un GSI en la columna de índice:
QPS de solo escritura: 153,501.7 → 76,557.94 — 50% reduction
QPS mixto de lectura y escritura: 149,677.52 → 114,420.32 — 23% reduction