{"id":2033,"date":"2015-12-16T19:41:28","date_gmt":"2015-12-16T19:41:27","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=2033"},"modified":"2025-06-13T23:03:43","modified_gmt":"2025-06-14T06:03:43","slug":"indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/","title":{"rendered":"\u00cdndices para N1QL: o c\u00f3mo consegu\u00ed un aumento de velocidad de un orden de magnitud"},"content":{"rendered":"<h2 id=\"toc_0\">\u00cdndices para N1QL: o c\u00f3mo consegu\u00ed un aumento de velocidad de un orden de magnitud<\/h2>\n<p>En Couchbase 4.0 introdujimos el lenguaje de consulta N1QL: un lenguaje de consulta flexible que lleva consultas tipo SQL a documentos JSON.<\/p>\n<p>Siempre que hablamos de N1QL el <span style=\"color: rgb(51, 51, 51); text-align: left;\">conversaci\u00f3n<\/span> siempre da pie a preguntas sobre el rendimiento: qu\u00e9 esperar en t\u00e9rminos de rendimiento y qu\u00e9 opciones hay para optimizar las consultas.<\/p>\n<p>Lo m\u00e1s probable es que la primera respuesta sea \"depende de su caso de uso y de la forma de sus datos\", pero sinceramente eso no ayuda mucho.<\/p>\n<p>Esta entrada del blog trata de responder a la pregunta del rendimiento con un poco m\u00e1s de detalle y dar algunas cifras reales en t\u00e9rminos de tiempo de ejecuci\u00f3n y mostrar c\u00f3mo optimizar las consultas para obtener m\u00e1s rendimiento.<\/p>\n<h2 id=\"toc_1\">Historia de fondo<\/h2>\n<p>Couchbase utiliza N1QL en varias herramientas y aplicaciones internas y la semana pasada hice una observaci\u00f3n muy importante.<\/p>\n<p><strong>Cuando se utiliza N1QL es extremadamente importante crear \u00edndices.<\/strong><\/p>\n<p>En una peque\u00f1a aplicaci\u00f3n, a\u00f1adir un \u00edndice a un atributo cambi\u00f3 el tiempo de ejecuci\u00f3n de +2min. a 2 segundos. No se hizo ning\u00fan cambio en la consulta en s\u00ed, \u00a1el \u00fanico cambio fue el \u00edndice!<\/p>\n<blockquote>\n<p>Nota: El tiempo de consulta anterior no es para una sola consulta N1QL, sino para una secuencia de m\u00faltiples consultas en la aplicaci\u00f3n en una m\u00e1quina virtual relativamente poco potente.<\/p>\n<\/blockquote>\n<p>El tiempo de ejecuci\u00f3n esperado para una consulta depende en gran medida de la complejidad de la consulta y del sistema, el Couchbase Server y el hardware.<\/p>\n<p>Por eso, para dar una respuesta m\u00e1s precisa se necesita un banco de pruebas. Se trata de un conjunto bien definido de pruebas que pueden ejecutarse en diferentes sistemas para revelar las m\u00e9tricas de rendimiento reales de una configuraci\u00f3n determinada. De este modo, se puede obtener una medici\u00f3n para un sistema y una consulta reales.<\/p>\n<p>As\u00ed, en lugar de limitarnos a afirmar que N1QL es r\u00e1pido, podemos probarlo en un sistema real: \u00a1tu propia configuraci\u00f3n!<\/p>\n<h2 id=\"toc_2\">Creaci\u00f3n de un banco de pruebas<\/h2>\n<p>En primer lugar, el rendimiento es un reto. Es un reto medirlo, pero el verdadero problema es que a menudo olvidamos QU\u00c9 estamos probando y, por tanto, tambi\u00e9n olvidamos cu\u00e1ndo poner en marcha el \"cron\u00f3metro\" y cu\u00e1ndo volver a pararlo.<\/p>\n<p>Por lo tanto, al realizar una prueba es importante definir lo que se pretende medir y c\u00f3mo medirlo de forma justa, repetible y comparable.<\/p>\n<p>En nuestro caso queremos medir la diferencia en el tiempo de ejecuci\u00f3n de una consulta N1QL predefinida cuando se utiliza un \u00edndice y cuando no se utiliza.<\/p>\n<p>S\u00f3lo estamos interesados en el tiempo de ejecuci\u00f3n real de la consulta N1QL, independientemente de cualquier retraso espec\u00edfico de la plataforma, tales como: retrasos de red, tiempo de arranque, rendimiento del SDK, tiempos de configuraci\u00f3n\/limpieza, etc.<\/p>\n<p>\u00a1En otras palabras, para esta prueba de rendimiento en particular, estamos ignorando todo lo que no sea el &apos;tiempo de ejecuci\u00f3n de la consulta&apos; en los dos escenarios!<\/p>\n<p>Por suerte, medir el tiempo de ejecuci\u00f3n de una consulta es muy f\u00e1cil. Cada respuesta de Couchbase Server se devuelve con un valor <code>Medida<\/code> que contiene todas las m\u00e9tricas sobre la solicitud.<\/p>\n<pre>\r\n<code class=\"language-JSON\">\"Metrics\": \r\n{\r\n    \"elapsedTime\": \"1.7900093s\",\r\n    \"executionTime\": \"1.7900093s\",\r\n    \"resultCount\": 0,\r\n    \"resultSize\": 0,\r\n    \"mutationCount\": 0,\r\n    \"errorCount\": 0,\r\n    \"warningCount\": 0\r\n}<\/code><\/pre>\n<p>La m\u00e9trica anterior contiene <code>executionTime<\/code> y este valor representa el tiempo de ejecuci\u00f3n en Couchbase Server, independientemente de la latencia de la red, el tiempo de ejecuci\u00f3n del c\u00f3digo de la plataforma, etc. Es exactamente lo que necesitamos.<\/p>\n<p>Antes de ejecutar cualquier consulta, necesitamos algunos datos de prueba para ejecutar las consultas. La cantidad de datos de prueba que tenemos puede influir en gran medida los resultados de la prueba y por lo tanto esto debe ser configurable para cada prueba.<\/p>\n<p>La forma de crear los datos de prueba no es en absoluto importante para nuestra prueba, como tampoco lo es el tiempo que se tarde en crearlos. Lo importante es la forma de los datos, ya que deben reflejar lo mejor posible los datos reales. Aparte de eso, tenemos un alto nivel de libertad en la forma de crearlos y el tiempo que se tarda.<\/p>\n<p>En la mayor\u00eda de los casos es justo asumir que los documentos variar\u00e1n en tama\u00f1o y forma. A Couchbase no le afecta la forma del documento. Couchbase s\u00f3lo \"ve\" una clave que apunta a un valor. El tama\u00f1o es un tema diferente y por lo tanto los documentos en el conjunto de datos deben variar en tama\u00f1o.<\/p>\n<p>La imitaci\u00f3n de varios documentos diferentes puede lograrse cambiando un <code>tipo<\/code> en el documento JSON. De nuevo, la forma no es importante para Couchbase, pero cambiando el atributo <code>tipo<\/code> podemos imitar distintos tipos de documentos aunque compartan la misma estructura documental.<\/p>\n<p>Los criterios de los datos de prueba pueden reducirse ahora a:<\/p>\n<ul>\n<li>Los documentos deben variar de tama\u00f1o<\/li>\n<li>El documento puede compartir la misma estructura JSON<\/li>\n<li>El contenido de los documentos debe ser \u00fanico<\/li>\n<li>El documento debe tener un <code>tipo<\/code> que puede modificarse para imitar diferentes documentos del conjunto de datos.<\/li>\n<\/ul>\n<p>Teniendo esto en cuenta, vamos a definir la estructura del documento JSON de la siguiente manera:<\/p>\n<pre>\r\n<code class=\"language-JSON\">{\r\n    \"Id\": \"GUID\",\r\n    \"type\": \"perfTest\",\r\n    \"IndexedType\": \"person + #\",\r\n    \"NoneIndexedType\": \"person + #\",\r\n    \"Day\": 1->29,\r\n    \"Month\": 1->12,\r\n    \"Year\": 2015,\r\n    \"TextSmall\": \"100->250 random chars\",\r\n    \"TextMedium\": \"200->500 random chars\",\r\n    \"TextLarge\": \"700->1000 random chars\",\r\n    \"TextExtraLarge\": \"1200-1500 random chars\"\r\n}<\/code><\/pre>\n<p>La estructura del documento anterior representa el documento de prueba. El tama\u00f1o de cada documento puede variar mucho, ya que todos los <code>Texto...<\/code> tienen un tama\u00f1o y un valor aleatorios. Al tener este tama\u00f1o y contenido aleatorios, cada documento imita mejor los documentos reales de un sistema real.<\/p>\n<p>Es probable que un sistema real contenga m\u00e1s de un tipo de documento y al cambiar el valor de <code>Tipo indexado<\/code> la misma estructura de documento puede imitar diferentes tipos de documento en el sistema.<\/p>\n<p>El atributo <code>Tipo indexado<\/code> puede tomar diferentes valores predecibles en la forma: <code>persona1<\/code>, <code>persona2<\/code>, <code>persona3<\/code> y <code>persona4<\/code>. Los cuatro valores diferentes se utilizan para imitar cuatro documentos diferentes. Es posible a\u00f1adir m\u00e1s &apos;tipos&apos; pero para nuestra prueba cuatro son suficientes.<\/p>\n<p>En <code>tipo<\/code> permite buscar y eliminar f\u00e1cilmente los documentos de prueba una vez finalizada la prueba, y siempre recibe el valor <code>perfTest<\/code>.<\/p>\n<p>Cargar los documentos en un bucket en Couchbase Server puede hacerse de muchas maneras. Una opci\u00f3n ser\u00eda crear previamente los documentos y cargarlos en el bucket utilizando una combinaci\u00f3n de los m\u00e9todos <code>cbbackup<\/code> y <code>cbrestore<\/code> herramientas.<\/p>\n<p>Otra opci\u00f3n ser\u00eda crear los datos de prueba sobre la marcha. Supongo que se le ocurrir\u00e1n otras formas de cargar los datos. Recuerde que este paso no es cr\u00edtico para el rendimiento. Haz lo que te resulte m\u00e1s f\u00e1cil.<\/p>\n<p>Con las definiciones anteriores en su lugar, estamos listos para definir los pasos para el banco de pruebas:<\/p>\n<ol>\n<li>Llevar el sistema a un estado conocido<\/li>\n<li>Datos de la prueba de carga<\/li>\n<li>Consultar los datos de las pruebas y medir el tiempo de ejecuci\u00f3n<\/li>\n<li>Crear \u00edndices<\/li>\n<li>Consultar los datos de las pruebas y medir el tiempo de ejecuci\u00f3n<\/li>\n<li>Llevar el sistema a un estado conocido<\/li>\n<li>Imprimir resultado<\/li>\n<\/ol>\n<h2 id=\"toc_3\">Aplicaci\u00f3n<\/h2>\n<h3 id=\"toc_4\">Primer paso<\/h3>\n<p>Aunque las funciones de manipulaci\u00f3n de datos de N1QL a\u00fan est\u00e1n en fase de previsualizaci\u00f3n, ya pueden utilizarse. Eso hace que la limpieza de datos sea muy sencilla:<\/p>\n<pre>\r\n<code class=\"language-SQL\">\"DELETE FROM `default` d WHERE d.type = &apos;perfTest&apos; RETURNING d.Id<\/code><\/pre>\n<p>Los \u00edndices pueden eliminarse mediante la funci\u00f3n <code>DROP<\/code> mando:<\/p>\n<pre>\r\n<code class=\"language-SQL\">DROP INDEX `default`.`index_1` USING GSI;\r\nDROP INDEX `default`.`index_2` USING GSI;\r\nDROP INDEX `default`.`index_3` USING GSI;<\/code><\/pre>\n<p>Couchbase Server devolver\u00e1 un error si el archivo <code>DROP<\/code> se ejecuta contra un \u00edndice que no existe. Esto puede solucionarse con una comprobaci\u00f3n de si el \u00edndice existe o no:<\/p>\n<pre>\r\n<code class=\"language-SQL\">SELECT * FROM system:indexes WHERE name=&apos;index_1&apos;; \r\nSELECT * FROM system:indexes WHERE name=&apos;index_2&apos;; \r\nSELECT * FROM system:indexes WHERE name=&apos;index_3&apos;; <\/code><\/pre>\n<h3 id=\"toc_5\">Paso 2<\/h3>\n<p>Probablemente ser\u00eda posible seguir utilizando las funciones de manipulaci\u00f3n de datos de N1QL para crear un conjunto de datos aleatorios, pero tambi\u00e9n ser\u00eda un poco m\u00e1s complicado que crear los documentos en c\u00f3digo.<\/p>\n<p>El c\u00f3digo del banco de pruebas se implementar\u00e1 utilizando .NET y los documentos se generar\u00e1n utilizando el siguiente fragmento C#:<\/p>\n<pre>\r\n<code class=\"language-C#\">private static void GenerateDocuments()\r\n{\r\n    int rounds = numberOfTestDocuments > batchSize ? numberOfTestDocuments \/ batchSize : 1;\r\n    int testDocsPerLoop = rounds > 1 ? batchSize : numberOfTestDocuments;\r\n    Random ran = new Random();\r\n\r\n    for (int n = 0; n < rounds; n++)\r\n    {\r\n        var docs = new Dictionary<string, dynamic>();\r\n\r\n        for (int i = 0; i < testDocsPerLoop; i++)\r\n        {\r\n            string id = Guid.NewGuid().ToString();\r\n            string postFix = ran.Next(1, 4).ToString();\r\n            var doc = new\r\n            {\r\n                Id = id,\r\n                type = \"perfTest\",\r\n                IndexedType = \"person\" + postFix,\r\n                NoneIndexedType = \"person\" + postFix,\r\n                Day = ran.Next(1, 29),\r\n                Month = ran.Next(1, 12),\r\n                Year = \"2015\",\r\n                TextSmall = new string(\r\n                    Enumerable.Range(0, ran.Next(100, 250)).Select(item => (char)ran.Next(44, 126)).ToArray()),\r\n                TextMedium = new string(\r\n                    Enumerable.Range(0, ran.Next(200, 500)).Select(item => (char)ran.Next(44, 126)).ToArray()),\r\n                TextLarge = new string(\r\n                    Enumerable.Range(0, ran.Next(700, 1000)).Select(item => (char)ran.Next(44, 126)).ToArray()),\r\n                TextExtraLarge = new string(\r\n                    Enumerable.Range(0, ran.Next(1200, 1500)).Select(item => (char)ran.Next(44, 126)).ToArray())\r\n            };\r\n\r\n            docs.Add(id, doc);\r\n        }\r\n\r\n        ClusterHelper\r\n           .GetBucket(\"default\")\r\n           .Upsert<dynamic>(docs);\r\n\r\n        Console.Write(\".\");\r\n    }\r\n}<\/code><\/pre>\n<p>El m\u00e9todo utiliza un bucle interior y otro exterior. El bucle interno define el tama\u00f1o del lote de subida. El bucle externo define el n\u00famero de lotes a subir a Couchbase Server.<\/p>\n<p>Los bucles se a\u00f1aden para garantizar que el programa no se quede sin memoria al cargar un gran conjunto de datos.<\/p>\n<h3 id=\"toc_6\">Paso 3<\/h3>\n<p>Despu\u00e9s de subir los documentos de prueba a Couchbase Server es hora de ejecutar la primera parte de la prueba y registrar el tiempo de ejecuci\u00f3n:<\/p>\n<pre>\r\n<code class=\"language-SQL\">SELECT * FROM `default` WHERE IndexedType=&apos;person3&apos; AND Month > 5 AND Day < 20<\/code><\/pre>\n<p>Dependiendo del n\u00famero de documentos utilizados en la prueba, es probable que esta consulta agote el tiempo de espera. En mi sistema, al ejecutar esta consulta con 500.000 documentos, se agota el tiempo de espera. Con 15.000 documentos, la consulta tarda unos 15 segundos.<\/p>\n<h3 id=\"toc_7\">Paso 4<\/h3>\n<p>Ahora es el momento de crear los \u00edndices:<\/p>\n<pre>\r\n<code class=\"language-SQL\">CREATE INDEX `index_1` ON `default`(IndexedType) USING GSI;\r\nCREATE INDEX `index_2` ON `default`(Month) USING GSI;\r\nCREATE INDEX `index_3` ON `default`(Day) USING GSI;<\/code><\/pre>\n<p>En <code>CREAR \u00cdNDICE<\/code> es s\u00edncrono y vuelve cuando el \u00edndice secundario est\u00e1 creado y listo. Eso significa que este comando puede tardar un rato en completarse, dependiendo del n\u00famero de documentos de la prueba y del tama\u00f1o de tu m\u00e1quina.<\/p>\n<p><strong>\u00cdndice m\u00faltiple frente a \u00edndice \u00fanico:<\/strong> <em>Tener varios \u00edndices independientes es beneficioso si se busca en cada atributo en consultas independientes en las que faltan otros atributos.<\/em><\/p>\n<p><em>Sin embargo, tener un solo \u00edndice reduce la sobrecarga de mantener \u00edndices separados y puede simplemente reducir los requisitos de recursos y tambi\u00e9n puede acelerar la consulta a\u00fan m\u00e1s, ya que tiene la capacidad de encontrar los elementos que califican para todos los criterios de filtro de una sola vez.<\/em><\/p>\n<p><em>En lugar de los tres \u00edndices independientes podr\u00edamos utilizar esto:<\/em><\/p>\n<pre>\r\n<code class=\"language-SQL\">CREATE INDEX `index_type_month_year` ON `default`(IndexedType, Month, Year) USING GSI;<\/code><\/pre>\n<p><em>O incluso:<\/em><\/p>\n<pre>\r\n<code class=\"language-SQL\">CREATE INDEX `index_type_month_year` ON `default`(IndexedType, Month, Year) WHERE IndexedType=&apos;person3&apos; AND Month > 5 AND Day < 20 USING GSI;<\/code><\/pre>\n<p><em>Sin embargo, me parece m\u00e1s correcto tener varios \u00edndices para este tipo de pruebas. Siempre se puede ejecutar la prueba con un solo \u00edndice y medir la diferencia en el tiempo de ejecuci\u00f3n y utilizar esa medida para tomar una decisi\u00f3n final de lo que&apos;s mejor en su caso particular.<\/em><\/p>\n<h3 id=\"toc_8\">Paso 5<\/h3>\n<p>Una vez creados los \u00edndices, es hora de ejecutar la segunda parte de la prueba y registrar el tiempo de ejecuci\u00f3n:<\/p>\n<pre>\r\n<code class=\"language-SQL\">SELECT * FROM `default` WHERE IndexedType=&apos;person3&apos; AND Month > 5 AND Day < 20<\/code><\/pre>\n<blockquote>\n<p>Nota: se trata exactamente de la misma consulta utilizada en el paso 3. No se han realizado cambios en la consulta en s\u00ed.<\/p>\n<\/blockquote>\n<p>Los tiempos de ejecuci\u00f3n t\u00edpicos en mi sistema oscilan entre 4 y 23 ms. Es una gran diferencia. Pero, \u00bfc\u00f3mo afecta el tama\u00f1o del conjunto de datos a esta medida? Tendr\u00e1s que seguir leyendo para obtener esa respuesta.<\/p>\n<h3 id=\"toc_9\">Paso 6<\/h3>\n<p>Borrar todos los documentos de prueba, eliminar los \u00edndices y devolver el sistema al estado conocido antes de ejecutar la prueba. Es lo mismo que el paso 1.<\/p>\n<p>Se podr\u00eda argumentar que el paso 1 o el paso 6 no son necesarios, pero ambos son muy importantes. Piense en el caso de que una prueba se interrumpa (se cancele, falle, etc.).<\/p>\n<h3 id=\"toc_10\">Paso 7<\/h3>\n<p>El \u00faltimo paso, y espero que el m\u00e1s interesante, el resultado.<\/p>\n<p>Resultados de mi sistema:<\/p>\n<p><img decoding=\"async\" alt=\"Test 1\" src=\"https:\/\/raw.githubusercontent.com\/martinesmann\/cb-n1ql-index-demo\/master\/Content\/test-1.png\" \/><\/p>\n<p><img decoding=\"async\" alt=\"Test 2\" src=\"https:\/\/raw.githubusercontent.com\/martinesmann\/cb-n1ql-index-demo\/master\/Content\/test-2.png\" \/><\/p>\n<p><strong>Resumen de los resultados de mi sistema:<\/strong><\/p>\n<p>MacBook Pro 16 GB de memoria, Couchbase Server ejecut\u00e1ndose en Windows 10 usando Parallels Desktop con 10 GB de memoria (Couchbase Server tiene 2 GB de memoria)<\/p>\n<ul>\n<li>15.000 documentos\n<ul>\n<li>NO-index: 15<strong>s<\/strong><\/li>\n<li>\u00edndice: 7<strong>ms<\/strong><\/li>\n<\/ul>\n<\/li>\n<li>500.000 documentos:\n<ul>\n<li>NO-index: tiempo de espera (m\u00e1s de 5<strong>min<\/strong>)<\/li>\n<li>\u00edndice: 10<strong>ms<\/strong><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong>Observaci\u00f3n<\/strong>, <em>En t\u00e9rminos de tiempo de ejecuci\u00f3n no hay gran diferencia entre 15K documentos y 500K documentos cuando se utiliza un \u00edndice.<\/em><\/p>\n<p><strong>Aprender<\/strong>, <em>El uso de \u00edndices secundarios es muy importante y contribuye en gran medida al rendimiento de las consultas.<\/em><\/p>\n<h2 id=\"toc_11\">C\u00f3digo fuente<\/h2>\n<p>El c\u00f3digo fuente est\u00e1 disponible en GitHub:<\/p>\n<p><a href=\"https:\/\/github.com\/martinesmann\/cb-n1ql-index-demo\">C\u00f3digo de prueba del \u00edndice N1QL<\/a><\/p>\n<p>La implementaci\u00f3n intenta compensar los tiempos de espera\/errores y reintentos en fallos de operaci\u00f3n y tiempos de espera.<\/p>\n<p>Un tiempo de espera se produce con bastante frecuencia cuando se utiliza N1QL&apos;s beta comando <code>BORRAR<\/code> en un gran conjunto de datos (500.000 documentos). Recuerde que esta funci\u00f3n a\u00fan est\u00e1 en fase de previsualizaci\u00f3n y, por lo tanto, no cabe esperar este comportamiento cuando se publique, pero por ahora es necesario esperar este comportamiento y compensarlo en consecuencia.<\/p>\n<h2 id=\"toc_12\">Eso es lo que pasa con los puntos de referencia. Depende.<\/h2>\n<p>\u00bfQu\u00e9 rendimiento puede esperar de su sistema? Pues depende. Pero ahora puedes ejecutar el c\u00f3digo de prueba en tu sistema y hacerte una mejor idea.<\/p>\n<p>\u00a1Pero una cosa es segura! No te olvides de crear esos \u00edndices secundarios. \u00a1Mejoran enormemente el rendimiento! En t\u00e9rminos num\u00e9ricos, \u00a1los \u00edndices pueden mejorar el rendimiento entre 100 y 1000 veces!<\/p>\n<p>El uso de \u00edndices tiene un impacto en el uso de la CPU del cl\u00faster, por lo que vale la pena considerar exactamente qu\u00e9 \u00edndices implementar y no crear m\u00e1s de los necesarios.<\/p>\n<p>Dicho esto, por una sola l\u00ednea de c\u00f3digo, la relaci\u00f3n calidad-precio es realmente buena ;)<\/p>\n<pre>\r\n<code class=\"language-SQL\">CREATE INDEX `{INDEX_NAME}` ON `{BUCKET_NAME}`({ATTRIBUTE_NAME}) USING GSI;<\/code><\/pre>\n<p>No dudes en publicar los resultados de tus pruebas en los comentarios y ay\u00fadanos a comprender mejor el rendimiento que cabe esperar de N1QL.<\/p>","protected":false},"excerpt":{"rendered":"<p>Indexes for N1QL: or how I got an order magnitude speed increase In Couchbase 4.0 we introduced N1QL query language: a flexible query language that brings SQL-like query to JSON documents. Whenever we talk about N1QL the conversation always opens [&hellip;]<\/p>","protected":false},"author":54,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1811,10127,9417,1812],"tags":[1505,1877,1506],"ppma_author":[9027],"class_list":["post-2033","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-c-sharp","category-performance","category-n1ql-query","tag-index","tag-testing","tag-tuning"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.2 (Yoast SEO v26.2) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Indexes for N1QL: or how I got an order magnitude speed increase - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/es\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Indexes for N1QL: or how I got an order magnitude speed increase\" \/>\n<meta property=\"og:description\" content=\"Indexes for N1QL: or how I got an order magnitude speed increase In Couchbase 4.0 we introduced N1QL query language: a flexible query language that brings SQL-like query to JSON documents. Whenever we talk about N1QL the conversation always opens [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2015-12-16T19:41:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T06:03:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/raw.githubusercontent.com\/martinesmann\/cb-n1ql-index-demo\/master\/Content\/test-1.png\" \/>\n<meta name=\"author\" content=\"Martin Esmann, Developer Advocate, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Martin Esmann, Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/\"},\"author\":{\"name\":\"Martin Esmann, Developer Advocate, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2795ae2ee44b46479499d6fa514b7ee8\"},\"headline\":\"Indexes for N1QL: or how I got an order magnitude speed increase\",\"datePublished\":\"2015-12-16T19:41:27+00:00\",\"dateModified\":\"2025-06-14T06:03:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/\"},\"wordCount\":1924,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"Index\",\"testing\",\"Tuning\"],\"articleSection\":[\".NET\",\"C#\",\"High Performance\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/\",\"name\":\"Indexes for N1QL: or how I got an order magnitude speed increase - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2015-12-16T19:41:27+00:00\",\"dateModified\":\"2025-06-14T06:03:43+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Indexes for N1QL: or how I got an order magnitude speed increase\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2795ae2ee44b46479499d6fa514b7ee8\",\"name\":\"Martin Esmann, Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/af6bbf8de1ed87c78bfbc9ac7454a4fc\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/c8aea3b717146fd35e6b3c299ba8b331987c90cb1996f0141f0c6de29aa04c4b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/c8aea3b717146fd35e6b3c299ba8b331987c90cb1996f0141f0c6de29aa04c4b?s=96&d=mm&r=g\",\"caption\":\"Martin Esmann, Developer Advocate, Couchbase\"},\"description\":\"Martin Esmann is a .Net Developer Advocate at Couchbase. He is a passionate developer with a deep focus on Microsoft Technologies like .NET.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/martin-esmann\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Indexes for N1QL: or how I got an order magnitude speed increase - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/es\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/","og_locale":"es_MX","og_type":"article","og_title":"Indexes for N1QL: or how I got an order magnitude speed increase","og_description":"Indexes for N1QL: or how I got an order magnitude speed increase In Couchbase 4.0 we introduced N1QL query language: a flexible query language that brings SQL-like query to JSON documents. Whenever we talk about N1QL the conversation always opens [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/es\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/","og_site_name":"The Couchbase Blog","article_published_time":"2015-12-16T19:41:27+00:00","article_modified_time":"2025-06-14T06:03:43+00:00","og_image":[{"url":"https:\/\/raw.githubusercontent.com\/martinesmann\/cb-n1ql-index-demo\/master\/Content\/test-1.png","type":"","width":"","height":""}],"author":"Martin Esmann, Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Martin Esmann, Developer Advocate, Couchbase","Est. reading time":"9 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/"},"author":{"name":"Martin Esmann, Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2795ae2ee44b46479499d6fa514b7ee8"},"headline":"Indexes for N1QL: or how I got an order magnitude speed increase","datePublished":"2015-12-16T19:41:27+00:00","dateModified":"2025-06-14T06:03:43+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/"},"wordCount":1924,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["Index","testing","Tuning"],"articleSection":[".NET","C#","High Performance","SQL++ \/ N1QL Query"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/","url":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/","name":"Indexes for N1QL: or how I got an order magnitude speed increase - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2015-12-16T19:41:27+00:00","dateModified":"2025-06-14T06:03:43+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/indexes-for-n1ql-or-how-i-got-an-order-magnitude-speed-increase\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Indexes for N1QL: or how I got an order magnitude speed increase"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2795ae2ee44b46479499d6fa514b7ee8","name":"Martin Esmann, Defensor del Desarrollador, Couchbase","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/af6bbf8de1ed87c78bfbc9ac7454a4fc","url":"https:\/\/secure.gravatar.com\/avatar\/c8aea3b717146fd35e6b3c299ba8b331987c90cb1996f0141f0c6de29aa04c4b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/c8aea3b717146fd35e6b3c299ba8b331987c90cb1996f0141f0c6de29aa04c4b?s=96&d=mm&r=g","caption":"Martin Esmann, Developer Advocate, Couchbase"},"description":"Martin Esmann es desarrollador de .Net en Couchbase. Es un desarrollador apasionado con un profundo enfoque en tecnolog\u00edas Microsoft como .NET.","url":"https:\/\/www.couchbase.com\/blog\/es\/author\/martin-esmann\/"}]}},"authors":[{"term_id":9027,"user_id":54,"is_guest":0,"slug":"martin-esmann","display_name":"Martin Esmann, Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/c8aea3b717146fd35e6b3c299ba8b331987c90cb1996f0141f0c6de29aa04c4b?s=96&d=mm&r=g","author_category":"","last_name":"Esmann","first_name":"Martin","job_title":"","user_url":"","description":"Martin Esmann es desarrollador de .Net en Couchbase. Es un desarrollador apasionado con un profundo enfoque en tecnolog\u00edas Microsoft como .NET."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/2033","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/54"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=2033"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/2033\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=2033"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=2033"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=2033"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=2033"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}