Introducción
Hay tres cosas importantes en los sistemas de bases de datos: rendimiento, rendimiento, rendimiento. Para los sistemas de bases de datos NoSQL, hay tres cosas importantes: rendimiento a escala, rendimiento a escala, rendimiento a escala.
Entender las opciones de índice, crear el índice correcto, con las claves correctas, el orden correcto y la expresión correcta es crítico para el rendimiento de las consultas y el rendimiento a escala en Couchbase. Hemos hablado de modelado de datos para JSON y consulta en JSON anterior. En este artículo, discutiremos las opciones de indexación para JSON en Couchbase.
Couchbase 5.0 tiene tres tipos de categorías de índice. Cada clúster de Couchbase solo puede tener una categoría de índice, ya sea índice secundario global estándar o índice secundario global optimizado para memoria.
| Secundaria estándar: versión 4.0 y superior |
|
| Índice de memoria optimizada: 4,5 y superior |
|
| Secundaria estándar: versión 5.0 |
|
El índice secundario estándar (de 4.0 a 4.6.x) almacena utiliza el motor de almacenamiento ForestDB para almacenar el índice B-Tree y mantiene el conjunto óptimo de trabajo de los datos en el buffer. Esto significa que el tamaño total del índice puede ser mucho mayor que la cantidad de memoria disponible en cada nodo de índice.
Un índice optimizado para memoria utiliza una novedosa lista de esquí sin bloqueos para mantener el índice y conserva 100% de los datos del índice en memoria. Un índice optimizado para memoria (MOI) tiene mejor latencia para las exploraciones del índice y también puede procesar las mutaciones de los datos mucho más rápido.
El índice secundario estándar de la versión 5.0 utiliza el motor de almacenamiento plasma de nuestra edición empresarial, que utiliza la lista de exclusión sin bloqueo como MOI, pero admite índices de gran tamaño que no caben en la memoria.
Los tres tipos de índices implementan el control de concurrencia multiversión (MVCC) para proporcionar resultados de escaneo de índices consistentes y un alto rendimiento. Durante la instalación del clúster, elija el tipo de índice.
El objetivo es ofrecerle una visión general de los distintos índices que se crean en cada uno de estos servicios para que sus consultas puedan ejecutarse de forma eficiente. El objetivo de este artículo no es describir o comparar y contrastar estos dos tipos de servicios de índice. No cubre el Índice de Búsqueda de Texto Completo (FTS), lanzado en Couchbase 5.0.
Tomemos el viaje-muestra y probar estos índices.
En la consola web, vaya a Configuración->Cubos de muestra para instalar la muestra de viaje.
Aquí tienes los distintos índices que puedes crear.
- Índice primario
- Índice primario con nombre
- Índice secundario
- Índice compuesto secundario
- Índice funcional
- Índice de matrices
- matriz ALL
- matriz ALL DISTINCT
- Índice parcial
- Índice adaptativo
- Índices duplicados
- Índice de cobertura
Fondo
Couchbase es una base de datos distribuida. Soporta un modelo de datos flexible usando JSON. Cada documento en un bucket tendrá una clave de documento única generada por el usuario. Esta unicidad se aplica durante la inserción de los datos.
He aquí un documento de ejemplo.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
SELECCIONE meta().id, viaje DESDE Viajar-muestra viaje DONDE tipo = aerolínea límite 1; [ { "id": "aerolínea_10", "viaje": { "Indicativo": "MILE-AIR", "país": "Estados Unidos", "iata": "Q5", "icao": "MLA", "id": 10, "nombre": "40-Mile Air", "tipo": "aerolínea" } } ] |
Tipo de índices
1. Índice primario
crea el índice primario en "viaje-muestra":
El índice primario es simplemente el índice de la clave de documento de todo el bucket. La capa de datos de Couchbase impone la restricción de unicidad en la clave del documento. El índice primario, como cualquier otro índice en Couchbase, se mantiene de forma asíncrona. Se puede establecer la recencia de los datos estableciendo el parámetro nivel de coherencia para su consulta.
Estos son los metadatos de este índice:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
SELECCIONAR * DESDE sistema:índices DONDE nombre = '#primary"; "índices": { "datastore_id": "http://127.0.0.1:8091", "id": "f6e3c75d6f396e7d", "clave_índice": [], "is_primary": verdadero, "keypace_id": "viaje-muestra", "nombre": "#primary", "namespace_id": "por defecto", "estado": "en línea", "usando": "gsi" } |
Los metadatos proporcionan información adicional sobre el índice: Dónde reside el índice (datastore_id), su estado (state) y el método de indexación (using).
El índice primario se utiliza para escaneos de bucket completos (escaneos primarios) cuando la consulta no tiene ningún filtro (predicados) o se puede utilizar otro índice o ruta de acceso. En Couchbase, almacenas múltiples keyspaces (documentos de diferente tipo, clientes, pedidos, inventario, etc) en un único bucket. Entonces, cuando haces el escaneo primario, la consulta usará el índice para obtener las claves de los documentos y buscará todos los documentos en el bucket y luego aplicará el filtro. Esto es MUY CARO.
El diseño de la clave de documento es algo así como un diseño de clave primaria con múltiples partes.
Apellido:nombre:ID cliente
Ejemplo: smith:john:X1A1849
En Couchbase, es una buena práctica prefijar la clave con el tipo de documento. Dado que se trata de un documento de cliente, pongamos el prefijo CX. Ahora, la clave se convierte en:
|
1 |
Ejemplo: CX:smith:john:X1A1849 |
Así que, en el mismo cubo, habrá otros tipos de documentos.
|
1 |
PEDIDOS tipo: OD:US:CA:294829 |
|
1 |
ARTÍCULOS tipo: IT:KD93823 |
Estas son simplemente las mejores prácticas. No hay restricciones sobre el formato o la estructura de la clave del documento en Couchbase, excepto que tienen que ser únicas dentro de un bucket.
Ahora, si tienes documentos con varias claves y tienes un índice primario, puedes utilizar las siguientes consultas de forma eficiente.
Ejemplo 1: Búsqueda de una clave de documento específica.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
SELECCIONE * DESDE ventas DONDE META().id = "CX:smith:john:X1A1849"; { "#operator": "IndexScan2", "índice": "#primary", "index_id": "4c92ab0bcca9690a", "espacio clave": "ventas", "espacio de nombres": "por defecto", "vanos": [ { "exacto": verdadero, "rango": [ { "alto": "\"CX:smith:john:X1A1849\"", "inclusión": 3, "bajo": "\"CX:smith:john:X1A1849\"" } ] } ], } |
Si conoce la clave completa del documento, puede utilizar la siguiente sentencia y evitar por completo el acceso al índice.
SELECCIONAR * DESDE ventas UTILICE TECLAS ["CX:smith:john:X1A1849"]
Puede obtener más de un documento en una declaración.
|
1 |
SELECCIONE * DESDE ventas UTILICE TECLAS ["CX:smith:john:X1A1849", "CX:smithjr:john:X2A1492"] |
Ejemplo 2: Busque un patrón. Consigue TODOS los documentos del cliente.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
SELECCIONE * DESDE ventas DONDE META().id COMO "CX:%"; { "#operator": "IndexScan2", "índice": "#primary", "index_id": "4c92ab0bcca9690a", "espacio clave": "ventas", "espacio de nombres": "por defecto", "vanos": [ { "exacto": verdadero, "rango": [ { "alto": "\"CX;\"", "inclusión": 1, "bajo": "\"CX:\"" }" ] } ], } |
Ejemplo 3: Consiga todos los clientes con "herrero" como apellido.
La siguiente consulta utiliza el índice primario de forma eficiente, obteniendo únicamente los clientes con un rango determinado. Nota: Este escaneo distingue entre mayúsculas y minúsculas. Para realizar una exploración sin distinguir mayúsculas de minúsculas, puede crear un índice secundario con UPPER() o LOWER() de la clave del documento.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
SELECCIONE * DESDE ventas DONDE META().id COMO "CX:smith%"; { "#operator": "IndexScan2", "índice": "#primary", "index_id": "4c92ab0bcca9690a", "espacio clave": "ventas", "espacio de nombres": "por defecto", "vanos": [ { "exacto": verdadero, "rango": [ { "alto": "\"CX:smiti\"", "inclusión": 1, "bajo": "\"CX:smith\"" } ] } ], } |
Ejemplo 4: Es habitual que algunas aplicaciones utilicen una dirección de correo electrónico como parte del documento, ya que son valores únicos. En ese caso, necesita averiguar todos los clientes con "@gmail.com". Si este es un requerimiento típico, entonces, almacene el REVERSO de la dirección de correo electrónico como la clave y simplemente haga el escaneo del patrón de cadena líder.
Correo electrónico:johnsmith@gmail.com; clave: invertir("johnsmith@gmail.com") => moc.liamg@htimsnhoj
Correo electrónico: janesnow@yahoo.com clave: invertir("janesnow@yahoo.com") => moc.oohay@wonsenaj
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
SELECCIONE * DESDE ventas DONDE meta().id COMO (invertir("@yahoo.com") || "%"); { "#operator": "IndexScan2", "índice": "#primary", "index_id": "4c92ab0bcca9690a", "espacio clave": "ventas", "espacio de nombres": "por defecto", "vanos": [ { "rango": [ { "alto": "moc.oohayA\"", "inclusión": 1, "bajo": "\ "moc.oohay@\"" } ] } ], } |
2. Índice primario con nombre
En Couchbase 5.0, puedes crear múltiples réplicas de cualquier índice con un simple parámetro a CREATE INDEX. Lo siguiente creará 3 copias del índice y tiene que haber un mínimo de 3 nodos de índice en el clúster.
|
1 2 |
CREAR PRIMARIO ÍNDICE EN muestra-viaje CON {"num_replica":2}; CREAR PRIMARIO ÍNDICE `def_primary` EN Viajar-muestra ; |
También puede asignar un nombre al índice primario. El resto de las características del índice primario son las mismas, excepto el nombre del índice. Un buen efecto secundario de esto es que puedes tener múltiples índices primarios en versiones de Couchbase anteriores a la 5.0 usando diferentes nombres. Los índices duplicados ayudan a la alta disponibilidad así como a la distribución de la carga de consultas a través de ellos. Esto es cierto tanto para los índices primarios como para los secundarios.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
SELECCIONE meta().id como documentkey, Viajar-muestra aerolínea DESDE Viajar-muestra DONDE tipo = aerolínea límite 1; { "aerolínea": { "Indicativo": "MILE-AIR", "país": "Estados Unidos", "iata": "Q5", "icao": "MLA", "id": 10, "nombre": "40-Mile Air", "tipo": "aerolínea" }, "documentkey": "aerolínea_10" } |
3. Índice secundario
El índice secundario es un índice sobre cualquier clave-valor o clave-documento. Este índice puede ser cualquier clave dentro del documento. La clave puede ser de cualquier tipo: escalar, objeto o matriz. La consulta tiene que utilizar el mismo tipo de objeto para que el motor de consulta pueda explotar el índice.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
CREAR ÍNDICE nombre_viajero EN Viajar-muestra`(nombre); nombre es a simple escalar valor. { "nombre": "Air France" } CREAR ÍNDICE travel_geo en Viajar-muestra`(geo); geo es un objeto incrustado en el documento. Ejemplo: "geo": { "alt": 12, "lat": 50.962097, "lon": 1.954764 } Creación de índices en llaves de anidado objetos es directamente. CREAR ÍNDICE travel_geo en Viajar-muestra`(geo.alt); CREAR ÍNDICE travel_geo en Viajar-muestra`(geo.lat); |
El campo horario es una matriz de objetos con los detalles del vuelo. Esto indexa el array completo. No es exactamente útil a menos que estés buscando el array completo.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
CREAR ÍNDICE calendario_viajes EN Viajar-muestra`(horario); Ejemplo: "horario": [ { "día": 0, "vuelo": "AF198", "utc": "10:13:00" }, { "día": 0, "vuelo": "AF547", "utc": "19:14:00" }, { "día": 0, "vuelo": "AF943", "utc": "01:31:00" }, { "día": 1, "vuelo": "AF356", "utc": "12:40:00" }, { "día": 1, "vuelo": "AF480", "utc": "08:58:00" }, { "día": 1, "vuelo": "AF250", "utc": "12:59:00" } ] |
4. Índice secundario compuesto
Es común tener consultas con múltiples filtros (predicados). Por lo tanto, se desean índices con múltiples claves para que los índices puedan devolver sólo las claves cualificadas de los documentos. Además, si una consulta sólo hace referencia a las claves del índice, el motor de consulta simplemente responderá a la consulta a partir del resultado de la exploración del índice sin ir a los nodos de datos. Se trata de una optimización de rendimiento muy utilizada.
|
1 |
CREAR ÍNDICE idx_stctln EN `viaje-muestra` (estado, ciudad, nombre.apellido) |
Cada una de las claves puede ser un campo escalar simple, un objeto o una matriz. Para que se pueda aprovechar el filtrado de índices, los filtros tienen que utilizar el tipo de objeto correspondiente en el filtro de consulta. Las claves de los índices secundarios pueden incluir claves de documento (meta().id) explícitamente si es necesario filtrar sobre ellas en el índice.
Veamos las consultas que aprovechan y las que no aprovechan el índice.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
1.SELECCIONE * DESDE Viajar-muestra DONDE estado = CA; En predicado coincide con el líder clave de el índice. Así que.., este consulta utiliza el índice a totalmente evaluar el predicado (estado = CA"). 2.SELECCIONE * DESDE Viajar-muestra DONDE estado = CA Y ciudad = Windsor; En predicados match el líder dos llaves. Así que este es bien ajuste como Bien. 3.SELECCIONE * DESDE Viajar-muestra DONDE estado = CA Y ciudad = Windsor Y nombre.apellido = "herrero; En tres predicados en este consulta coincide con el tres índice llaves perfectamente. Así que.., este es a bien match. 4.SELECCIONE * DESDE Viajar-muestra DONDE ciudad = Windsor Y nombre.apellido = "herrero; En este consulta, aunque predicados match dos de el índice llaves, el líder clave no es emparejado. Así que.., el índice no puede y es no usado para este consulta planes. 5.SELECCIONE * DESDE Viajar-muestra DONDE nombre.apellido = "herrero; Similar a anterior consulta, este consulta tiene el predicado en el tercera clave de el índice. Así que.., este índice no puede sea usado. 6.SELECCIONE * DESDE Viajar-muestra DONDE estado = CA Y nombre.apellido = "herrero; Este consulta tiene predicado en primero y el tercera clave. En este índice es y puede sea elegido, nosotros no puede pulse abajo el predicado después de saltarse un índice clave (segundo clave en este caso). Así que.., sólo el primero predicado (estado = "CA") se sea empujado abajo a índice escanear. "#operator": "IndexScan2", "índice": "idx_stctln", "index_id": "dadbb12da565ed28", "proyección_índice": { "clave_primaria": verdadero }, "espacio clave": "viaje-muestra", "espacio de nombres": "por defecto", "vanos": [ { "exacto": verdadero, "rango": [ { "alto": "\"CA\"", "inclusión": 3, "bajo": "\"CA\"" } ] } 7.SELECCIONE * DESDE Viajar-muestra DONDE estado IS NO FALTA Y ciudad = Windsor Y nombre.apellido = "herrero; Este es a modificado versión de consulta 4 arriba. A utilice este índice, el consulta necesita a tienen un adicional predicado (estado IS NO FALTA) suponiendo que que representa su aplicación requisito. |
5. Índice funcional (expresión)
Es habitual tener nombres en la base de datos con una mezcla de mayúsculas y minúsculas. Cuando necesites buscar "Juan", quieres que busque cualquier combinación de "Juan", "juan", etc. Así es como se hace.
CREAR ÍNDICE nombre_del_viaje EN Viajar-muestra`(BAJO(nombre));
Proporcione la cadena de búsqueda en minúsculas y el índice buscará eficazmente los valores ya escritos en minúsculas en el índice.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
EXPLICAR SELECCIONE * DESDE Viajar-muestra DONDE BAJO(nombre) = "john"; { "#operator": "IndexScan", "índice": "nombre_del_viaje", "index_id": "2f39d3b7aac6bbfe", "espacio clave": "viaje-muestra", "espacio de nombres": "por defecto", "vanos": [ { "Rango": { "Alto": [ "\"john\"" ], "Inclusión": 3, "Bajo": [ "\"john\"" ] } } ] } |
Puede utilizar expresiones complejas en este índice funcional.
CREAR ÍNDICE travel_cx1 EN Viajar-muestra`(BAJO(nombre), longitud*de ancho, redondo(salario));
También verás que se pueden crear índices de array en una expresión que devuelva un array en la siguiente sección.
6. Índice de matrices
JSON es jerárquico. En el nivel superior, puede tener campos escalares, objetos o matrices. Cada objeto puede anidar otros objetos y matrices. Cada array puede tener otros objetos y arrays. Y así sucesivamente. El anidamiento continúa.
Cuando tienes esta rica estructura, así es como indexas un array particular o un campo dentro del sub-objeto.
Considera la matriz, programa:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
horario: [ { "día" : 0, "vuelos_especiales" : [ { "vuelo" : "AI111", "utc" : "1:11:11" }, { "vuelo" : "AI222", "utc" : "2:22:22" } ] }, { "día": 1, "vuelo": "AF552", "utc": "14:41:00" } ] CREAR ÍNDICE travel_sched EN Viajar-muestra (TODOS DISTINTO ARRAY v.día PARA v EN horario FIN) |
v es la variable que hemos declarado implícitamente para hacer referencia a cada elemento/objeto dentro de la matriz: schedule v.day hace referencia al elemento dentro de cada objeto de la matriz schedule.
La siguiente consulta explotará el índice del array.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
EXPLICAR SELECCIONE * DESDE Viajar-muestra DONDE CUALQUIER v EN PROGRAMA SATISFACE v.día = 2 FIN; { "#operator": "DistinctScan", "escanear": { "#operator": "IndexScan", "índice": "travel_sched", "index_id": "db7018bff5f10f17", "espacio clave": "viaje-muestra", "espacio de nombres": "por defecto", "vanos": [ { "Rango": { "Alto": [ "2" ], "Inclusión": 3, "Bajo": [ "2" ] } } ], "usando": "gsi" } |
Dado que la clave es una expresión generalizada, dispone de flexibilidad para aplicar lógica y procesamiento adicionales a los datos antes de indexarlos. Por ejemplo, puede crear una indexación funcional en los elementos de cada matriz. Dado que se está haciendo referencia a campos individuales del objeto o elemento dentro de la matriz, la expresión creación de índices, el tamaño y la búsqueda son eficientes. El índice anterior sólo almacena los valores distintos dentro de una matriz. Para almacenar todos los elementos de una matriz en un índice, utilice el modificador DISTINCT en la expresión.
CREAR ÍNDICE travel_sched EN Viajar-muestra` (TODOS DISTINTO ARRAY v.día PARA v EN horario FIN)
El índice de array se puede crear sobre valores estáticos (como arriba) o una expresión que devuelva un array. TOKENS() son una de estas expresiones, devolviendo un array de tokens de un objeto. Puede crear un índice en esta matriz y buscar utilizando el índice.
Couchbase 5.0 hace más sencillo crear y emparejar los índices de array. Proporcionando el prefijo ALL ( o ALL DISTINCT) a la clave la convertirá en una clave de array.
|
1 2 3 4 5 6 7 8 9 |
CREAR ÍNDICE idx_cx6 EN Viajar-muestra`(TODOS TOKENS(public_likes)) DONDE tipo = "hotel"; SELECCIONE t.name, t.country, t.public_likes DESDE Viajar-muestra t DONDE t.tipo = hotel AND ANY p IN TOKENS(public_likes) SATISFACE p = 'Vallie FIN; |
Los índices de matrices también pueden crearse en elementos dentro de matrices de matrices. No hay límite en el nivel de anidamiento de la expresión de la matriz. La expresión de la consulta debe coincidir con la expresión del índice.
7. Índice parcial
Hasta ahora, los índices que hemos creado crearán índices sobre todo el bucket. Como el modelo de datos de Couchbase es JSON y los esquemas JSON son flexibles, un índice puede no contener entradas a documentos con claves de índice ausentes. Eso es lo esperado. A diferencia de los sistemas relacionales, donde cada tipo de fila está en una tabla distinta, los buckets de Couchbase pueden tener documentos de varios tipos. Normalmente, los clientes incluyen un campo de tipo para diferenciar los distintos tipos.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "aerolínea": { "Indicativo": "MILE-AIR", "país": "Estados Unidos", "iata": "Q5", "icao": "MLA", "id": 10, "nombre": "40-Mile Air", "tipo": "aerolínea" }, "documentkey": "aerolínea_10" } |
Si desea crear un índice de documentos de líneas aéreas, sólo tiene que añadir el campo de tipo para la cláusula WHERE del índice.
CREAR ÍNDICE info_viajes EN Viajar-muestra`(nombre, id, icoo, iata) DONDE tipo = aerolínea;
Esto creará un índice sólo en los documentos que tengan (tipo = 'compañía aérea'). En tus consultas, tendrías que incluir el filtro (tipo = 'compañía aérea') además de otros filtros para que este índice cumpla los requisitos.
Puede utilizar predicados complejos en la cláusula WHERE del índice. Varios casos de uso para explotar los índices parciales son:
- Partición de un índice grande en varios índices mediante la función mod.
- Partición de un índice grande en varios índices y colocación de cada índice en nodos indexadores distintos.
- Partición del índice en función de una lista de valores. Por ejemplo, puede tener un índice para cada estado.
- Simulando la partición del rango del índice a través de un filtro de rango en la cláusula WHERE. Una cosa a recordar es que las consultas N1QL de Couchbase usarán un índice particionado por bloque de consulta. Usa UNION ALL para que una consulta explote múltiples índices particionados en una sola consulta.
8. Índice adaptativo
Un índice adaptativo crea un índice único en todo el documento o conjunto de campos de un documento. Se trata de un índice de forma o matriz que utiliza el par {"clave": valor} como clave única del índice. El propósito es evitar la pesadilla de una consulta que tiene que coincidir con las claves principales del índice en los índices tradicionales.
El índice adaptativo tiene dos ventajas:
- Se pueden evaluar múltiples predicados en el espacio de claves utilizando diferentes secciones del mismo índice.
- Evite crear varios índices sólo para reordenar las claves del índice.
- Evite el orden de las claves de índice.
Por ejemplo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
CREAR ÍNDICE `ai_self` EN Viajar-muestra`(DISTINTO PAIRS(ai_self)) DONDE tipo = "aeropuerto"; EXPLICAR SELECCIONE * DESDE Viajar-muestra DONDE faa = "OFS" Y `tipo` = "aeropuerto"; { "#operator": "IntersectScan", "escaneos": [ { "#operator": "IndexScan2", "índice": "ai_self", "index_id": "c564a55225d9244c", "proyección_índice": { "clave_primaria": verdadero }, "espacio clave": "viaje-muestra", "espacio de nombres": "por defecto", "vanos": [ { "exacto": verdadero, "rango": [ { "alto": "[\"faa\", \"SFO\"]", "inclusión": 3, "bajo": "[\"faa\", \"SFO\"]" } ] } ], "usando": "gsi" } ... ] } |
El mismo índice puede utilizarse también para consultas con otros predicados. Esto reduce el número de índices que tendrías que crear a medida que crece el documento.
|
1 2 3 4 |
EXPLICAR SELECCIONE * DESDE Viajar-muestra DONDE ciudad = "Seattle" Y `tipo` = "aeropuerto"; |
Consideraciones sobre su uso:
- Dado que cada campo de atributo tiene una entrada de índice, el tamaño de los índices puede ser enorme.
- El índice adaptativo es un índice de matriz. Está limitado por la restricción de los índices del array.
Consulte la documentación detallada sobre índice adaptativo en la documentación de Couchbase.
9. Índice de duplicados
Esto no es realmente un tipo especial de índice, sino una característica de la indexación de Couchbase. Puedes crear índices duplicados con nombres distintos.
|
1 2 3 4 5 6 7 8 9 10 11 |
CREAR ÍNDICE i1 EN Viajar-muestra`(BAJO(nombre),id, icoo) DONDE tipo = "aerolínea"; CREAR ÍNDICE i2 EN Viajar-muestra`(BAJO(nombre),id, icoo) DONDE tipo = "aerolínea"; CREAR ÍNDICE i3 EN Viajar-muestra`(BAJO(nombre),id, icoo) DONDE tipo = "aerolínea"; |
Los tres índices tienen claves idénticas, cláusula WHERE idéntica; la única diferencia es el nombre de los índices. Puede elegir su ubicación física mediante la cláusula WITH de CREATE INDEX. Durante la optimización de la consulta, ésta elegirá uno de los nombres. Lo verá en su plan. Durante la ejecución de la consulta, estos índices se utilizan de forma rotatoria para distribuir la carga. Esto proporciona escalabilidad, escalabilidad multidimensional, rendimiento y alta disponibilidad. No está nada mal.
Couchbase 5.0 hace el índice duplicado MÁS SENCILLO. En lugar de crear múltiples índices con nombres distintos, puedes simplemente especificar el número de índices de réplica que necesitas.
|
1 2 3 4 |
CREAR ÍNDICE i1 EN Viajar-muestra`(BAJO(nombre),id, icoo) DONDE tipo = aerolínea CON {"num_replica" : 2 }; |
Esto creará 2 copias adicionales del índice además del índice i1. Las funciones de equilibrio de carga y HA son las mismas que un índice equivalente.
10. Índice de cobertura
La selección del índice para una consulta depende únicamente de los filtros de la cláusula WHERE de la consulta. Una vez hecha la selección del índice, el motor analiza la consulta para ver si puede responderse utilizando sólo los datos del índice. En caso afirmativo, el motor de consulta omite la recuperación del documento completo. Se trata de una optimización del rendimiento que hay que tener en cuenta al diseñar los índices.
¡Todos juntos ya!
Vamos a crear un índice de matriz funcional compuesta particionada.
|
1 2 3 4 5 6 7 8 9 10 |
CREAR ÍNDICE viajar_todos EN Viajar-muestra`( iata, BAJO(nombre), SUPERIOR(indicativo), TODOS DISTINTO ARRAY p.modelo PARA p EN chorros FIN), TO_NUMBER(rating), meta().id ) DONDE BAJO(país) = "estados unidos" Y tipo = "aerolínea" CON {"num_replica" : 2} |
Reglas para crear los índices.
Hasta ahora, hemos visto los tipos de índices. Veamos ahora cómo diseñar los índices para tu carga de trabajo.
Regla #1: UTILIZAR CLAVES
En Couchbase, cada documento de un bucket tiene una clave única generada por el usuario. Los documentos se distribuyen entre los distintos nodos mediante el hash de esta clave (nosotros utilizamos hashing coherente). Cuando tenga la clave del documento, puede obtener los documentos directamente de las aplicaciones (a través de SDK). Incluso cuando se tienen las claves de los documentos, es posible que se desee hacer la obtención y hacer algún post-procesamiento a través de N1QL. Es entonces cuando se utiliza el método USE KEYS.

Por ejemplo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
SELECCIONE nombre, dirección DESDE Viajar-muestra h UTILICE TECLAS [ "hotel_10025", "hotel_10026", "hotel_10063", "hotel_10064", "hotel_10138", "hotel_10142", "hotel_10158", "hotel_10159", "hotel_10160", "hotel_10161", "hotel_10180", "hotel_10289", "hotel_10290", "hotel_10291", "hotel_1072", "hotel_10848", "hotel_10849", "hotel_10850", "hotel_10851", "hotel_10904" ] DONDE h.país = "Reino Unido" Y ARRAY_LENGTH(public_likes) > 3; |
El método de acceso USE KEYS puede utilizarse incluso cuando se realizan uniones. He aquí un ejemplo:
SELECCIONE * DESDE PEDIDOS o UTILICE TECLAS ["ord::382"] INNER JOIN CLIENTE c EN TECLAS o.id;
En Couchbsae 5.0, los índices sólo se utilizan para procesar el primer espacio clave (bucket) de cada cláusula FROM. Los espacios clave posteriores se procesan mediante la obtención directa del documento.
SELECCIONE * DESDE PEDIDOS o INNER JOIN CLIENTE c EN TECLAS o.id DONDE o.estado = "CA";
En esta sentencia, procesamos el espacio de claves ORDERS a través de un índice sobre (estado) si está disponible. En caso contrario, utilizamos el índice primario para escanear ORDERS. A continuación, obtenemos los documentos de CLIENTES que coinciden con el identificador del documento de PEDIDOS.
Norma #2: UTILIZAR ÍNDICE DE COBERTURA
Ya hemos hablado de los tipos de índice. El índice correcto sirve para dos cosas:
- Reducir el conjunto de trabajo de la consulta para acelerar su rendimiento
- Almacenar y proporcionar datos adicionales incluso.
Cuando una consulta puede responderse completamente con los datos almacenados en el índice, se dice que la consulta es cubierta por el índice de cobertura. Debe intentar que la mayoría de sus consultas, si no todas, estén cubiertas. Esto reducirá la carga de procesamiento en el servicio de consulta, reducir la obtención adicional del servicio de datos.
La selección del índice se sigue realizando en función de los predicados de la consulta. Una vez realizada la selección del índice, el optimizador evaluará si el índice contiene todos los atributos necesarios para la consulta y creará un acceso cubierto a la ruta del índice.

Ejemplos:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
CREAR ÍNDICE idx_cx3 EN CLIENTE(estado, ciudad, nombre.apellido) DONDE estado = prima; /* La consulta a continuación no será cubierto desde que dijo: SELECT * */ SELECCIONE * DESDE CLIENTE DONDE estado = CA AND status = 'premium'; /* El índice tiene los tres campos requeridos por la consulta. */ /* Se cubrirá la consulta, como se muestra en el plan explain. */ SELECCIONE estado, estado, ciudad DE CLIENTE WHERE estado = 'CA' AND status = 'prima"; { "#operator": "IndexScan2", "tapas": [ "cover ((`CUSTOMER`.`state`))", "cover ((`CUSTOMER`.`city`))", "cover (((`CUSTOMER`.`name`).`lastname`))", "cover ((meta(`CUSTOMER`).`id`))" ], "filter_covers": { "cover ((`CUSTOMER`.`status`))": "premium" }, "índice": "idx_cx3", "index_id": "18f8209144215971", "proyección_índice": { "entry_keys": [ 0, 1 ] } |
Observe que el campo status de la cláusula WHERE del índice (status = 'premium') también está cubierto. Sabemos que todos los documentos del índice tienen un campo llamado estado con el valor "premium". Podemos simplemente proyectar este valor. El campo "Filter_covers" de la explicación muestra esta información.
Mientras el índice tenga el campo, una consulta puede realizar filtrados adicionales, uniones, agregación, paginación después de obtener los datos del indexador sin obtener el documento completo.
Regla #3: UTILIZAR LA REPLICACIÓN DE ÍNDICES

En un cluster de Couchbase, tienes múltiples servicios de índices. Antes de Couchbase 5.0, podías crear manualmente índices de réplica (equivale) para mejorar el rendimiento, el equilibrio de carga y la alta disponibilidad.
Antes de la 5.0:
|
1 2 3 4 5 6 7 8 9 |
CREAR ÍNDICE idx1 EN CLIENTE(estado, ciudad, nombre.apellido) DONDE estado = prima; CREAR ÍNDICE idx2 EN CLIENTE(estado, ciudad, nombre.apellido) DONDE estado = prima; CREAR ÍNDICE idx3 EN CLIENTE(estado, ciudad, nombre.apellido) DONDE estado = prima; |
Reconocemos la equivalencia de estos tres índices porque las expresiones clave y la cláusula WHERE son exactamente lo mismo.
Durante la fase de optimización de la consulta, el motor N1QL elige uno de los tres índices para el escaneo de índices (suponiendo que se cumplan otros requisitos) para crear el plan de consulta. Durante la ejecución de la consulta, ésta prepara el paquete de escaneo y envía una solicitud de escaneo de índice. Durante este proceso, basándonos en las estadísticas de carga, enviamos la petición a uno de ellos. La idea es que, con el tiempo, cada uno de ellos tenga una carga similar.
Este proceso de creación de índices réplica (índices equivalentes) se facilita con un simple parámetro.
|
1 2 3 4 |
CREAR ÍNDICE idx1 EN CLIENTE(estado, ciudad, nombre.apellido) DONDE estado = prima CON { "num_replica":2 }; |
Es lo mismo que crear tres índices distintos pero equivalentes.
Regla #4: INDEXAR POR CARGA DE TRABAJO, NO POR BUCKET/KEYSPACE
Considere toda la carga de trabajo de la aplicación y los acuerdos de nivel de servicio (SLA) para cada una de las consultas. Las consultas que tengan requisitos de latencia de milisegundos con un alto rendimiento requerirán índices personalizados y réplicas, mientras que otras podrían compartir índices.
Puede haber espacios de claves en los que simplemente se realicen operaciones set & get o en los que se puedan realizar consultas con USE KEYS. Estos espacios de claves no necesitarán índices.
Analice las consultas para encontrar los predicados comunes, proyecciones de un espacio de claves. Puede optimizar el número de índices basándose en los predicados comunes. Si una de sus consultas no tiene un predicado en la clave o claves principales, vea si añadir (campo NO FALTA) tiene sentido para que el índice pueda ser compartido.
Está bien tener un índice primario mientras desarrollas tu aplicación o consultas. Pero, antes de realizar pruebas, cree los índices adecuados y elimine el índice primario de su sistema, a menos que su aplicación utilice los casos descritos en la sección "Índice primario". Si tienes un índice primario en producción y las consultas acaban haciendo un escaneo primario completo con un span completo en el índice, te estás buscando problemas. En Couchbase, el índice primario indexa todos los documentos del bucket.
Cada índice secundario en Couchbase debería tener una cláusula WHERE, con al menos una condición sobre el tipo de documento. Esto no lo impone el sistema, pero es un buen diseño.
|
1 2 3 |
CREAR ÍNDICE def_route_src_dst EN Viajar-muestra (`sourceairport`, aeropuerto de destino") DONDE (`tipo` = "ruta"); |
Crear los índices adecuados es una de las mejores prácticas para optimizar el rendimiento. Esto no es lo único que hay que hacer para obtener el mejor rendimiento. La configuración del clúster, el ajuste, la configuración del SDK y el uso de sentencias preparadas desempeñan un papel importante.
Regla #5: INDEXAR POR PREDICADO, NO POR PROYECTO
Parece una regla obvia. Pero de vez en cuando me encuentro con gente que comete este error.
Considere la consulta:
|
1 2 3 4 |
SELECCIONE ciudad, estado, estado DESDE CLIENTE DONDE estado = CA Y estado = prima; |
La consulta puede utilizar cualquiera de los siguientes índices:
|
1 2 3 4 5 6 |
Cree índice i1 en CLIENTE(estado); Cree índice i2 en CLIENTE(estado); Cree índice i3 en CLIENTE(estado, estado); Cree índice i4 en CLIENTE(estado, estado); Cree índice i5 en CLIENTE(estado) DONDE estado = "prima"; Cree índice i6 en CLIENTE(estado) DONDE estado = "CA"; |
Para que el índice cubra completamente la consulta, basta con añadir el campo ciudad al índice 3-6.
Sin embargo, si tiene un índice con la ciudad como clave principal, el optimizador no lo detectará.
|
1 2 3 |
Cree índice i7 O EN CLIENTE(ciudad, estado) DONDE estado = "prima"; |
Consulte el artículo detallado sobre cómo funciona la exploración de índices en varios escenarios para optimizar el índice: https://dzone.com/articles/understanding-index-scans-in-couchbase-50-n1ql-que
Norma #6: AÑADIR ÍNDICES PARA CUMPLIR LOS ANS
Para las bases de datos relacionales, lo más importante eran tres cosas: rendimiento, rendimiento y rendimiento.
Para las bases de datos NoSQL, lo más importante son tres cosas: rendimiento a escala, rendimiento a escala, rendimiento a escala.
Una cosa son tus consultas ejecutando pruebas básicas de rendimiento en tu portátil, y otra cosa es ejecutar las consultas de alto rendimiento y baja latencia en el clúster. Afortunadamente, en Couchbase es fácil identificar y escalar los recursos cuello de botella de forma independiente, gracias al escalado multidimensional. Cada uno de los servicios en Couchbase se abstrae en servicios distintos: datos, índice, consulta. La consola de Couchbase tiene estadísticas de cada uno de los servicios de forma independiente.
Una vez creados los índices para sus consultas y optimizados los índices para la carga de trabajo, puede añadir índices de réplica (equivalentes) adicionales para mejorar la latencia, ya que equilibramos la carga de los escaneos entre los índices de réplica.
Regla #7: ÍNDICE PARA EVITAR LA CLASIFICACIÓN
El índice ya tiene los datos en el orden de las claves del índice. Tras la exploración, el índice devuelve los resultados en el orden de las claves del índice.
|
1 2 3 |
CREAR ÍNDICE idx3 EN Viajar-muestra`(estado, ciudad, nombre.apellido) DONDE estado = prima; |
Los datos se almacenan y devuelven en el orden: estado, ciudad, nombre.apellido. Por lo tanto, si tienes una consulta que espera los datos en el orden estado, ciudad, nombre.apellido, un índice te ayudará a evitar la ordenación.
En este ejemplo, los resultados se ordenan por nombre.apellido, la tercera clave del índice. Por lo tanto, es necesario ordenar el conjunto de resultados por nombre.apellido. Explain le indicará si el plan requiere esta ordenación.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
EXPLICAR SELECCIONE estado, ciudad, nombre.apellido DESDE Viajar-muestra DONDE estado = prima Y estado = CA Y ciudad COMO san% ORDENAR POR nombre.apellido; { "plan": { "#operator": "Secuencia", "~niños": [ { "#operator": "Secuencia", "~niños": [ { "#operator": "IndexScan2", "tapas": [ "cubrir ((`viaje-muestra`.`estado`))", "cubrir ((`viaje-muestra`.`ciudad`))", "cover (((`viaje-muestra`.`nombre`).`apellido`))", "cover ((meta(`viaje-muestra`).`id`))" ], "filter_covers": { "cover ((`viaje-muestra`.`estado`))": "premium" }, "índice": "idx3", "index_id": "19a5aed899d281fe", "proyección_índice": { "entry_keys": [ 0, 1, 2 ] }, "espacio clave": "viaje-muestra", "espacio de nombres": "por defecto", "vanos": [ { "exacto": verdadero, "rango": [ { "alto": "\"CA\"", "inclusión": 3, "bajo": "\"CA\"" }, { "alto": "\"sao\"", "inclusión": 1, "bajo": "\"san\"" } ] } ], "usando": "gsi" }, { "#operator": "Paralelo", "~niño": { "#operator": "Secuencia", "~niños": [ { "#operator": "Filtro", "condición": "((cover ((`viaje-muestra`.`estado`)) = \"premium\") and (cover ((`viaje-muestra`.`estado`)) = \"CA\")) and (cover ((`viaje-muestra`.`ciudad`)) like \"san%"))" }, { "#operator": "ProyectoInicial", "result_terms": [ { "expr": "cubrir ((`viaje-muestra`.`estado`))" }, { "expr": "cubrir ((`viaje-muestra`.`ciudad`))" }, { "expr": "cover (((`viaje-muestra`.`nombre`).`apellido`))" } ] } ] } } ] }, { "#operator": "Pedido", "sort_terms": [ { "expr": "cover (((`viaje-muestra`.`nombre`).`apellido`))" } ] }, { "#operator": "ProyectoFinal" } ] }, "texto": "SELECT state, city, name.lastname \nFROM `travel-sample`\nWHERE status = 'premium' AND state = 'CA' AND city LIKE 'san%'\nORDER BY name.lastname;" } |
La consulta siguiente tiene la correspondencia perfecta para las claves del índice. Por lo tanto, la ordenación es innecesaria. En la salida explain, falta el operador de ordenación.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
EXPLICAR SELECCIONE estado, ciudad, nombre.apellido DESDE Viajar-muestra DONDE estado = prima Y estado = CA Y ciudad COMO san% ORDENAR POR estado, ciudad, nombre.apellido; { "plan": { "#operator": "Secuencia", "~niños": [ { "#operator": "Secuencia", "~niños": [ { "#operator": "IndexScan2", "tapas": [ "cubrir ((`viaje-muestra`.`estado`))", "cubrir ((`viaje-muestra`.`ciudad`))", "cover (((`viaje-muestra`.`nombre`).`apellido`))", "cover ((meta(`viaje-muestra`).`id`))" ], "filter_covers": { "cover ((`viaje-muestra`.`estado`))": "premium" }, "índice": "idx3", "index_id": "19a5aed899d281fe", "proyección_índice": { "entry_keys": [ 0, 1, 2 ] }, "espacio clave": "viaje-muestra", "espacio de nombres": "por defecto", "vanos": [ { "exacto": verdadero, "rango": [ { "alto": "\"CA\"", "inclusión": 3, "bajo": "\"CA\"" }, { "alto": "\"sao\"", "inclusión": 1, "bajo": "\"san\"" } ] } ], "usando": "gsi" }, { "#operator": "Paralelo", "maxParalelismo": 1, "~niño": { "#operator": "Secuencia", "~niños": [ { "#operator": "Filtro", "condición": "((cover ((`viaje-muestra`.`estado`)) = \"premium\") and (cover ((`viaje-muestra`.`estado`)) = \"CA\")) and (cover ((`viaje-muestra`.`ciudad`)) like \"san%"))" }, { "#operator": "ProyectoInicial", "result_terms": [ { "expr": "cubrir ((`viaje-muestra`.`estado`))" }, { "expr": "cubrir ((`viaje-muestra`.`ciudad`))" }, { "expr": "cover (((`viaje-muestra`.`nombre`).`apellido`))" } ] }, { "#operator": "ProyectoFinal" } ] } } ] } ] }, "texto": "SELECT state, city, name.lastname \nFROM `travel-sample`\nWHERE status = 'premium' AND state = 'CA' AND city LIKE 'san%'\nORDER BY state, city, name.lastname;" } |
Explotar el orden de clasificación del índice puede no parecer importante hasta que se ve el caso de uso de la paginación. Cuando la consulta ha especificado OFFSET y LIMIT, se puede utilizar un índice para eliminar de forma eficiente los documentos que a la aplicación no le interesan o no necesita. Véase el artículo sobre paginación para más detalles.
El optimizador N1QL primero selecciona el índice basándose en los predicados de la consulta (filtros) y luego verifica si el índice puede cubrir todas las referencias de la consulta en proyección y orden por. Después, el optimizador intenta eliminar la ordenación y decidir sobre el pushdown de OFFSET y LIMIT. La explicación muestra si el OFFSET y el LIMIT fueron empujados a la exploración del índice.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
"espacio clave": "viaje-muestra", "límite": "20", "espacio de nombres": "por defecto", "offset": "100", "vanos": [ { "exacto": verdadero, "rango": [ { "alto": "\"CA\"", "inclusión": 3, "bajo": "\"CA\"" }, { "alto": "\"sao\"", "inclusión": 1, "bajo": "\"san\"" } ] } ] |
Regla #8: Número de índices
No hay límite artificial en el número de índices que puedes tener en el sistema. Si vas a crear un gran número de índices en un bucket que tiene los datos, utiliza la opción de creación diferida para que la transferencia de datos entre el servicio de datos y el servicio de índices sea eficiente.
Regla #9: Índice durante INSERT, DELETE, UPDATE
El índice se mantiene de forma asíncrona. Sus actualizaciones de datos a través de la API clave-valor o cualquier sentencia N1QL sólo actualizan los documentos en el bucket. El índice recibe la notificación de los cambios a través del flujo y aplica los cambios al índice. Esta es la secuencia de operaciones para una sentencia UPDATE. La sentencia utiliza el índice para calificar los documentos a actualizar; obtiene los documentos y los actualiza; luego escribe los documentos de vuelta y devuelve cualquier dato solicitado desde la sentencia UPDATE.

Regla #11: ORDEN DE CLAVE DE ÍNDICE Y TIPOS DE PREDICADO
Las peticiones de escaneo del índice creadas por los usuarios de la consulta son las N primeras claves consecutivas del índice. Por tanto, el orden de la clave del índice es importante.
Consideremos una consulta con varios predicados:
|
1 2 3 4 5 |
SELECCIONE cid, dirección DESDE CLIENTE DONDE estado = CA Y tipo = prima Y código postal EN [29482, 29284, 29482, 28472] Y salario < 50000 Y edad > 45; |
Se trata de reglas generales para el orden de las claves en el índice. Las claves pueden ser atributos escalares más simples o expresiones que devuelven valores escalares: por ejemplo, UPPER(nombre.apellido).
- La primera prioridad son las claves con predicados de igualdad. En esta consulta, es sobre estado y tipo. Cuando hay varios predicados del mismo tipo, elige cualquier combinación.
- La segunda prioridad son las claves con predicados IN. En esta consulta, se trata del código postal.
- La tercera prioridad es el predicado menor que (<). En este caso, es sobre el salario.
- La cuarta prioridad son los predicados between. Esta consulta no tiene un predicado between.
- La quinta prioridad son los predicados mayor que (>). En esta consulta, es sobre la edad.
- La sexta prioridad son los predicados de array: ANY, o EVERY AND ANY, predicados después de UNNEST.
- Busque añadir campos adicionales para que el índice cubra la consulta.
- Después de hacer este análisis, busque cualquier expresión que se pueda mover a la cláusula WHERE. Por ejemplo, en este caso, type = "premium" se puede mover porque el campo type es designado por los usuarios para identificar el tipo de clientes.
Con esto, llegamos al siguiente índice.
|
1 2 3 4 5 |
CREAR ÍNDICE orden_idx EN CLIENTE ( estado, código postal, salario, edad, dirección, cid ) DONDE tipo = "premium"; |
Regla #12: Saber leer EXPLAIN y PROFILING
No importa cuántas reglas sigas, tendrás que entender los planes de consulta y el perfil, monitorizar el sistema bajo carga y ajustarlo. La capacidad de comprender y analizar el plan de consulta y la información de perfiles es la clave para ajustar una consulta y una carga de trabajo. Hay dos buenos artículos sobre estos temas. Repásalos y prueba los ejemplos.
- https://dzone.com/articles/understanding-index-scans-in-couchbase-50-n1ql-que
- https://www.couchbase.com/blog/profiling-monitoring-update-2/
Referencias
- Nitro: A Fast, Scalable In-Memory Storage Engine for NoSQL Global Secondary Index: http://vldb2016.persistent.com/industrial_track_papers.php
- Couchbase: http://www.couchbase.com
- Documentación de Couchbase: http://docs.couchbase.com
- N1QL: Guía práctica: https://www.couchbase.com/blog/n1ql-practical-guide-second-edition/
- Asesor de índices: Reglas para la creación de índices: https://www.slideshare.net/journalofinformix/couchbase-n1ql-index-advisor
Hola Keshav,
Soy nuevo en CB, así que disculpen mi falta de comprensión.
Se menciona en este blog
"Así, cuando se hace el escaneo primario, la consulta utilizará el índice para obtener las claves de los documentos y buscará todos los documentos en el bucket y luego aplicará el filtro. Así que esto es MUY CARO".
He leído esto en muchos sitios y es lo mismo que me han dicho, es decir, que hay que evitar un índice primario. No consigo entender por qué. En Oracle o cualquier otro RDBMS, la búsqueda basada en claves primarias/únicas es la más rápida/mejor. Entiendo que si la consulta N1QL no tiene predicado entonces escaneará todo el bucket, es decir, escaneará todas las claves usando el índice primario y eso sería caro. Pero si se especifica la clave en el predicado, ¿no sería lo más rápido?
En el ejemplo 1, la clave específica se menciona en el predicado. Así que debería ser casi tan bueno getid('clave'), ¿no?
Gracias
Hola pccb,
Si tienes la clave del documento (esta es la clave única dentro del bucket), tienes un método de acceso incorporado y es el más eficiente de N1QL.
SELECT * FROM mybucket USE KEYS "cx:482:gn:284";
También puede utilizar el índice primario para esto mediante la emisión:
SELECT * FROM mybucket WHERE meta().id = "cx:482:gn:284";
Puede realizar escaneos de rango inteligentes en meta().id utilizando el índice primario:
SELECT * FROM mybucket WHERE meta().id LIKE "cx:482:gn:%";
Estos son los aspectos que debe tener en cuenta:
1. El bucket de Couchbase puede documentar todos los tipos: cliente, pedido, artículo, etc. Índice primario será a través de todos estos tipos de documentos.
2. Si el desarrollador/usuario construye cuidadosamente la consulta para realizar un escaneo de igualdad o de rango limitado, el uso del índice primario está bien.
3. Pero, si alguien realiza una consulta sin estas directrices o realiza una consulta sin ningún otro índice cualificado en producción, acabamos utilizando el escaneo primario y el escaneo y obtención de todo el índice y todos los documentos del bucket. Típicamente, eso es algo malo en producción.
Hola,
¿Hay alguna forma de evitar un índice, es decir, de hacer que CB NO lo utilice?
Lo que intentamos conseguir es lo siguiente:
Habrá un índice primario para que los desarrolladores puedan probar sus consultas. Sin embargo, una vez que hayan finalizado las consultas, incluido el índice necesario, nos gustaría que las ejecutaran asegurándose de que no están utilizando el índice primario. La razón es que, incluso después de crear el índice secundario adecuado, es posible que la consulta siga utilizando el índice primario y el desarrollador no se haya dado cuenta. Así que si hay una manera de evitar el uso del índice primario, entonces ejecutarían la consulta utilizando esa opción.
Gracias
Gracias por los comentarios. He abierto una mejora para añadir esto: https://issues.couchbase.com/browse/MB-32109
¿Hay algún error tipográfico o me estoy perdiendo algo?
CREAR ÍNDICE travel_sched EN
viaje-muestra(ALL DISTINCT ARRAY v.day FOR v IN schedule END)
¿Es "ALL DISTINCT" una sintaxis válida y qué significa? No la he encontrado en la documentación.
Gracias