{"id":4421,"date":"2018-01-11T11:56:34","date_gmt":"2018-01-11T19:56:34","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=4421"},"modified":"2025-06-13T20:20:11","modified_gmt":"2025-06-14T03:20:11","slug":"offset-keyset-pagination-n1ql-query-couchbase","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/offset-keyset-pagination-n1ql-query-couchbase\/","title":{"rendered":"Paginaci\u00f3n de Base de Datos: Uso de OFFSET y Keyset en N1QL"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4429\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/01\/arrows2-300x128.png\" alt=\"\" width=\"516\" height=\"220\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2-300x128.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2-768x327.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2-20x9.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png 853w\" sizes=\"auto, (max-width: 516px) 100vw, 516px\" \/><\/p>\n<p><span style=\"font-weight: 400\">Lea los antecedentes de la paginaci\u00f3n en mi art\u00edculo anterior: <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/es\/optimizing-database-pagination-using-couchbase-n1ql\/\"><span style=\"font-weight: 400\">https:\/\/www.couchbase.com\/blog\/optimizing-database-pagination-using-couchbase-n1ql\/<\/span><\/a><\/p>\n<p><span style=\"font-weight: 400\">La paginaci\u00f3n es la tarea de dividir el resultado potencial en p\u00e1ginas y recuperar las p\u00e1ginas requeridas, una a una bajo demanda.  El uso de OFFSET y LIMIT es la forma m\u00e1s sencilla de escribir la paginaci\u00f3n en las consultas a bases de datos. Juntos, OFFSET y LIMIT, forman la cl\u00e1usula de paginaci\u00f3n de la sentencia SELECT. La paginaci\u00f3n es un trabajo de aplicaci\u00f3n com\u00fan y su implementaci\u00f3n tiene un gran impacto en la experiencia del cliente. Veamos los problemas y soluciones con Couchbase N1QL en detalle.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Markus Winand de <\/span><a href=\"https:\/\/use-the-index-luke.com\/\"><span style=\"font-weight: 400\">https:\/\/use-the-index-luke.com\/<\/span><\/a><span style=\"font-weight: 400\"> argumenta que puede no ser lo m\u00e1s eficiente. Tambi\u00e9n sugiere, cuando sea posible, utilizar la paginaci\u00f3n por conjuntos de teclas en lugar de la paginaci\u00f3n OFFSET. Para este art\u00edculo, voy a utilizar las consultas de ejemplo modelado en su art\u00edculo, <\/span><a href=\"https:\/\/use-the-index-luke.com\/no-offset\"><span style=\"font-weight: 400\">https:\/\/use-the-index-luke.com\/no-offset<\/span><\/a><span style=\"font-weight: 400\"> para mostrar qu\u00e9 optimizaciones OFFSET hemos hecho, cu\u00e1ndo y c\u00f3mo explotar la paginaci\u00f3n de conjuntos de teclas en N1QL. <\/span><\/p>\n<p><span style=\"font-weight: 400\">Dado que Couchbase incluye un conjunto de datos de muestra de viajes, lo utilizaremos para escribir nuestras consultas de paginaci\u00f3n.<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">OBTENER LA PRIMERA P\u00c1GINA<\/span><\/li>\n<\/ol>\n<pre class=\"theme:github scroll:true whitespace-before:1 whitespace-after:1 lang:plsql decode:true\">SELECT *\r\nFROM `travel-sample`\r\nWHERE type = \u2018hotel\u2019\r\nORDER BY country, city\r\nOFFSET 0\r\nLIMIT 10;\r\n\r\nCREATE INDEX ixtopic ON `travel-sample`(type);\r\n<\/pre>\n<p><span style=\"font-weight: 400\">Para esta consulta, utilizando el \u00edndice ixtopic, el motor de consulta se ejecuta de forma sencilla. El motor de consultas obtiene todas las claves cualificadas del \u00edndice, a continuaci\u00f3n obtiene todos los documentos, ordena en funci\u00f3n de la cl\u00e1usula ORDER BY y, por \u00faltimo, elimina el n\u00famero de documentos OFFSET (en este caso cero) y proyecta el n\u00famero de documentos LIMIT (en este caso 10).<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4430\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-09-at-10.34.54-AM-300x169.png\" alt=\"\" width=\"744\" height=\"419\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/Screen-Shot-2018-01-09-at-10.34.54-AM-300x169.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/Screen-Shot-2018-01-09-at-10.34.54-AM-1024x577.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/Screen-Shot-2018-01-09-at-10.34.54-AM-768x433.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/Screen-Shot-2018-01-09-at-10.34.54-AM-1536x866.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/Screen-Shot-2018-01-09-at-10.34.54-AM-20x11.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/Screen-Shot-2018-01-09-at-10.34.54-AM-1320x744.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/Screen-Shot-2018-01-09-at-10.34.54-AM.png 1558w\" sizes=\"auto, (max-width: 744px) 100vw, 744px\" \/><\/p>\n<p><span style=\"font-weight: 400\">Aqu\u00ed est\u00e1 el plan que muestra el \u00edndice y los vanos.<\/span><\/p>\n<p>&nbsp;<\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:js decode:true\">          {\r\n            \"index\": \"ixtype\",\r\n            \"index_id\": \"8630f5f7e05ee113\",\r\n            \"index_projection\": {\r\n              \"primary_key\": true\r\n            },\r\n            \"keyspace\": \"travel-sample\",\r\n            \"namespace\": \"default\",\r\n            \"spans\": [\r\n              {\r\n                \"exact\": true,\r\n                \"range\": [\r\n                  {\r\n                    \"high\": \"\\\"hotel\\\"\",\r\n                    \"inclusion\": 3,\r\n                    \"low\": \"\\\"hotel\\\"\"\r\n                  }\r\n\r\n<\/pre>\n<p><span style=\"font-weight: 400\">N1QL elige el \u00edndice ixtype e introduce el filtro (type = \"hotel\") en la exploraci\u00f3n del \u00edndice. Para aplicar la cl\u00e1usula ORDER BY, recupera todos los documentos. En la fase de ordenaci\u00f3n, reconocemos la cl\u00e1usula LIMIT 10 y hacemos que la ordenaci\u00f3n sea eficiente manteniendo s\u00f3lo los 10 primeros elementos.<\/span><\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:js decode:true\">    {\r\n       \"#operator\": \"Order\",\r\n       \"limit\": \"10\",\r\n       \"sort_terms\": [\r\n         {\r\n           \"expr\": \"(`travel-sample`.`country`)\"\r\n         },\r\n         {\r\n           \"expr\": \"(`travel-sample`.`city`)\"\r\n         }\r\n       ]\r\n     },\r\n<\/pre>\n<p><span style=\"font-weight: 400\">Veamos la eficiencia del operador de escaneo de \u00edndices con este \u00edndice:<\/span><\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:js decode:true\">               \"#operator\": \"IndexScan2\",\r\n               \"#stats\": {\r\n                 \"#itemsOut\": 917,\r\n                 \"#phaseSwitches\": 3671,\r\n                 \"execTime\": \"2.646892ms\",\r\n                 \"kernTime\": \"31.095431ms\",\r\n                 \"servTime\": \"19.781593ms\"\r\n               },\r\n\u2026\r\n               \"#operator\": \"Fetch\",\r\n               \"#stats\": {\r\n                 \"#itemsIn\": 917,\r\n                 \"#itemsOut\": 917,\r\n                 \"#phaseSwitches\": 3787,\r\n                 \"execTime\": \"3.43324ms\",\r\n                 \"kernTime\": \"20.847541ms\",\r\n                 \"servTime\": \"69.875698ms\"\r\n               },\r\n\u2026\r\n           \"#operator\": \"Order\",\r\n           \"#stats\": {\r\n             \"#itemsIn\": 917,\r\n             \"#itemsOut\": 10,\r\n             \"#phaseSwitches\": 1849,\r\n             \"execTime\": \"6.519061ms\",\r\n             \"kernTime\": \"88.307572ms\"\r\n           },<\/pre>\n<p><span style=\"font-weight: 400\">El indizador ha devuelto 917 claves de documento. El motor de consulta obtuvo 917 documentos. A continuaci\u00f3n, el operador de clasificaci\u00f3n (orden) los orden\u00f3 y devolvi\u00f3 los 10 elementos.<\/span><\/p>\n<p><span style=\"font-weight: 400\">2. OBTENER LA SEGUNDA P\u00c1GINA<\/span><\/p>\n<pre class=\"whitespace-before:1 whitespace-after:1 lang:plsql decode:true\">SELECT *\r\nFROM `travel-sample`\r\nWHERE type = \u2018hotel\u2019\r\nORDER BY country, city\r\nOFFSET 10\r\nLIMIT 10;\r\n<\/pre>\n<p><span style=\"font-weight: 400\">En este caso, todo es igual que en la consulta1 excepto:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El operador de ordenaci\u00f3n (ORDER BY) devolver\u00e1 20 documentos (offset + limit).<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El nuevo operador OFFSET se ejecutar\u00e1 despu\u00e9s del operador Order y eliminar\u00e1 las 10 primeras filas.<\/span><\/li>\n<\/ol>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:js decode:true\">         \"#operator\": \"Order\",\r\n           \"#stats\": {\r\n             \"#itemsIn\": 917,\r\n             \"#itemsOut\": 20,\r\n             \"#phaseSwitches\": 1859,\r\n             \"execTime\": \"6.485904ms\",\r\n             \"kernTime\": \"65.92484ms\"\r\n           },\r\n   {\r\n           \"#operator\": \"Offset\",\r\n           \"#stats\": {\r\n             \"#itemsOut\": 10,\r\n             \"#phaseSwitches\": 32,\r\n             \"execTime\": \"5.071503ms\",\r\n             \"kernTime\": \"701ns\",\r\n             \"state\": \"running\"\r\n           },\r\n           \"expr\": \"10\",\r\n           \"#time_normal\": \"00:00.0050\",\r\n           \"#time_absolute\": 0.005071503\r\n         },\r\n<\/pre>\n<p><span style=\"font-weight: 400\">A medida que el OFFSET aumenta, el n\u00famero de documentos escaneados por la clasificaci\u00f3n tambi\u00e9n aumentar\u00e1, consumiendo m\u00e1s memoria y CPU.<\/span><\/p>\n<ol start=\"3\">\n<li><span style=\"font-weight: 400\"> Mejoremos el rendimiento cubriendo las claves de predicado y ordenaci\u00f3n con un \u00fanico \u00edndice.<\/span><\/li>\n<\/ol>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:plsql decode:true\">CREATE INDEX ixtypectcy ON `travel-sample`(type, country, city);\r\nLet\u2019s execute our recent query again:\r\nSELECT *\r\nFROM `travel-sample`\r\nWHERE type = \u2018hotel\u2019\r\nORDER BY country, city\r\nOFFSET 10\r\nLIMIT 10;\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4435\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/01\/Screen-Shot-2018-01-09-at-2.38.36-PM-300x179.png\" alt=\"\" width=\"641\" height=\"383\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/Screen-Shot-2018-01-09-at-2.38.36-PM-300x179.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/Screen-Shot-2018-01-09-at-2.38.36-PM-20x12.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/Screen-Shot-2018-01-09-at-2.38.36-PM.png 740w\" sizes=\"auto, (max-width: 641px) 100vw, 641px\" \/><\/p>\n<p><span style=\"font-weight: 400\">Utiliza el \u00edndice adecuado y crea los filtros adecuados (spans) para la exploraci\u00f3n del \u00edndice.Explain incluye lo siguiente.<\/span><\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:js decode:true\">       {\r\n           \"#operator\": \"IndexScan2\",\r\n           \"index\": \"ixtypectcy\",\r\n           \"index_id\": \"2a2ed6573354e21\",\r\n           \"index_projection\": {\r\n             \"primary_key\": true\r\n           },\r\n           \"keyspace\": \"travel-sample\",\r\n           \"limit\": \"10\",\r\n           \"namespace\": \"default\",\r\n           \"offset\": \"10\",\r\n           \"spans\": [\r\n             {\r\n               \"exact\": true,\r\n               \"range\": [\r\n                 {\r\n                   \"high\": \"\\\"hotel\\\"\",\r\n                   \"inclusion\": 3,\r\n                   \"low\": \"\\\"hotel\\\"\"\r\n                 }\r\n               ]\r\n             }\r\n           ],\r\n<\/pre>\n<p><span style=\"font-weight: 400\">Veamos la eficiencia del operador de escaneo de \u00edndices con este \u00edndice:<\/span><\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:js decode:true\">               \"#operator\": \"IndexScan2\",\r\n               \"#stats\": {\r\n                 \"#itemsOut\": 10,\r\n                 \"#phaseSwitches\": 43,\r\n                 \"execTime\": \"41.786\u00b5s\",\r\n                 \"kernTime\": \"11.15\u00b5s\",\r\n                 \"servTime\": \"855.759\u00b5s\"\r\n               },\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400\">S\u00f3lo se devuelven las 10 claves de documento necesarias a partir de la exploraci\u00f3n del \u00edndice.  El optimizador N1QL eval\u00faa tanto la cl\u00e1usula WHERE como la cl\u00e1usula de paginaci\u00f3n (OFFSET, LIMIT). El optimizador de consultas decide enviar la cl\u00e1usula de paginaci\u00f3n al indexador bas\u00e1ndose en la cl\u00e1usula order by de la consulta y en el orden de las claves del \u00edndice. \u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">En este caso, el predicado de la consulta es: type = 'hotel'<\/span><\/p>\n<p><span style=\"font-weight: 400\">La cl\u00e1usula Order by es: ORDER BY pa\u00eds, ciudad<\/span><\/p>\n<p><span style=\"font-weight: 400\">El orden de las claves del \u00edndice es: (tipo, pa\u00eds, ciudad)<\/span><\/p>\n<p><span style=\"font-weight: 400\">Por simple comparaci\u00f3n, el orden por cl\u00e1usula no es exactamente el mismo que el orden por clave del \u00edndice. Sin embargo, la clave principal del \u00edndice (tipo) tiene un predicado de igualdad (tipo = 'hotel'). Por lo tanto, el optimizador sabe que las claves proyectadas del documento estar\u00e1n en el orden de (pa\u00eds y ciudad).<\/span><\/p>\n<p><span style=\"font-weight: 400\">**y la cl\u00e1usula ORDER BY para ver si puede empujar hacia abajo los par\u00e1metros de paginaci\u00f3n a la exploraci\u00f3n del \u00edndice.  En este caso, hay una coincidencia perfecta.<\/span><\/p>\n<p><span style=\"font-weight: 400\">El optimizador pasa tanto OFFSET como LIMIT en la paginaci\u00f3n al escaneo de \u00edndice y el escaneo de \u00edndice devuelve s\u00f3lo las 10 claves de documento requeridas sin importar el OFFSET. Por lo tanto, fetch s\u00f3lo necesita obtener los 10 documentos. El indexador tiene que pasar por el escaneo del \u00edndice para evaluar las claves.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Esta consulta se ejecut\u00f3 en unos 6,81 milisegundos en mi entorno. Vamos a paginar las p\u00e1ginas siguientes para ver el rendimiento:<\/span><\/p>\n<table>\n<tbody>\n<tr>\n<td><span style=\"font-weight: 400\">OFFSET<\/span><\/td>\n<td><span style=\"font-weight: 400\">L\u00cdMITE<\/span><\/td>\n<td><span style=\"font-weight: 400\">Tiempo de respuesta<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">10<\/span><\/td>\n<td><span style=\"font-weight: 400\">10<\/span><\/td>\n<td><span style=\"font-weight: 400\">6,81 ms<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">20<\/span><\/td>\n<td><span style=\"font-weight: 400\">10<\/span><\/td>\n<td><span style=\"font-weight: 400\">7,17 ms<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">100<\/span><\/td>\n<td><span style=\"font-weight: 400\">10<\/span><\/td>\n<td><span style=\"font-weight: 400\">7,02 ms<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">400<\/span><\/td>\n<td><span style=\"font-weight: 400\">10<\/span><\/td>\n<td><span style=\"font-weight: 400\">9,54 ms<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">800<\/span><\/td>\n<td><span style=\"font-weight: 400\">10<\/span><\/td>\n<td><span style=\"font-weight: 400\">9,08 ms<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-weight: 400\">Si desea paginar en orden descendente, cambie la consulta y el \u00edndice por los siguientes. La intercalaci\u00f3n de la clave en el \u00edndice debe coincidir con la intercalaci\u00f3n de la consulta. En este caso, tanto el pa\u00eds como la ciudad est\u00e1n en orden descendente.<\/span><\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:plsql decode:true\">DROP INDEX `travel-sample`.ixtypectcy;\r\n\r\nCREATE INDEX ixtypectcy ON `travel-sample`(type, country DESC, city DESC);\r\n\r\nSELECT country, city\r\nFROM `travel-sample`\r\nWHERE type = \"hotel\"\r\nORDER BY country DESC, city DESC\r\nOFFSET 10\r\nLIMIT 10;<\/pre>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:js decode:true\">\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"#operator\": \"IndexScan2\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"covers\": [\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"cover ((`travel-sample`.`type`))\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"cover ((`travel-sample`.`country`))\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"cover ((`travel-sample`.`city`))\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"cover ((meta(`travel-sample`).`id`))\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0],\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"index\": \"ixtypectcy\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"keyspace\": \"travel-sample\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"limit\": \"10\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"namespace\": \"default\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"offset\": \"10\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"spans\": [\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"exact\": true,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"range\": [\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"high\": \"\\\"hotel\\\"\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"inclusion\": 3,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"low\": \"\\\"hotel\\\"\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0]\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0],\r\n\r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400\">Veamos ahora una consulta que no est\u00e1 cubierta por el \u00edndice. En la consulta que vimos antes, decidimos recuperar el nombre del hotel junto con el pa\u00eds y la ciudad. El nombre no est\u00e1 en el \u00edndice.<\/span><\/p>\n<p>&nbsp;<\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:default decode:true\">CREATE INDEX ixtypectcy ON `travel-sample` (type, country DESC, city DESC);\r\n\r\nSELECT country, city, name\r\nFROM `travel-sample`\r\nWHERE type \u00a0= \"hotel\"\r\nORDER BY country desc, city desc\r\nOFFSET 10\r\nLIMIT 10;<\/pre>\n<p><span style=\"font-weight: 400\">En este caso, de nuevo, el \u00edndice tiene los datos para cubrir la cl\u00e1usula WHERE y la cl\u00e1usula ORDER BY. El escaneo del \u00edndice aplicar\u00e1 el predicado. El orden del \u00edndice coincide con el orden de la consulta (nota: s\u00f3lo hay un predicado de igualdad en la clave principal. Por lo tanto, el pa\u00eds y la ciudad se ordenan autom\u00e1ticamente). El \u00edndice omite el n\u00famero OFFSET de claves cualificadas y devuelve el n\u00famero de claves especificado por la cl\u00e1usula LIMIT. El motor recupera los documentos para mantener el orden especificado por la cl\u00e1usula ORDER BY.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Todas estas peque\u00f1as optimizaciones juntas aseguran que el rendimiento de la consulta sea consistente tanto si OFFSET es 10, 100 o 1000. La \u00fanica sobrecarga entre OFFSET m\u00e1s altos es la exploraci\u00f3n del \u00edndice omitiendo los elementos adicionales. La evaluaci\u00f3n de la clave del \u00edndice y la omisi\u00f3n es significativamente m\u00e1s r\u00e1pida que obtener todos los documentos y ordenarlos.<\/span><\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:default decode:true\">\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"#operator\": \"Sequence\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"~children\": [\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"#operator\": \"IndexScan2\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"index\": \"ixtypectcy\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"index_id\": \"b2ab2c276bba7862\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"index_projection\": {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"primary_key\": true\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"keyspace\": \"travel-sample\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"limit\": \"10\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"namespace\": \"default\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"offset\": \"10\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"spans\": [\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"exact\": true,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"range\": [\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"high\": \"\\\"hotel\\\"\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"inclusion\": 3,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"low\": \"\\\"hotel\\\"\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0]\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}<\/pre>\n<p><span style=\"font-weight: 400\">Consideremos una consulta de larga duraci\u00f3n con un potencial de devoluci\u00f3n de hasta 24.000 documentos.<\/span><\/p>\n<p><span class=\"theme:github lang:plsql highlight:0 decode:true crayon-inline\">create index idxtypeaiaid ON `viajes-muestra`(tipo, aerolinea, airlineid) <\/span><\/p>\n<p><span style=\"font-weight: 400\">Incluso cuando los predicados de consulta de paginaci\u00f3n y el orden por est\u00e1n completamente cubiertos por el \u00edndice, hay un n\u00famero limitado de casos en los que el LIMIT y OFFSET de paginaci\u00f3n pueden ser empujados al escaneo del \u00edndice para hacerlo muy eficiente.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Estas son las reglas generales y los requisitos para enviar OFFSET y LIMIT al indexador.  Tenga en cuenta que estas reglas no son exhaustivas ni completas, pero le dan una idea de cu\u00e1ndo se realiza esta optimizaci\u00f3n.<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El escaneo de la consulta debe realizarse en un \u00fanico espacio clave (referencia \u00fanica en la cl\u00e1usula FROM sin JOINs.<\/span>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">FROM `travel-sample` t<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">FROM `travel-sample` hotel INNER JOIN `travel-sample` landmarks ON KEYS hotel.lmid<\/span><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p><span style=\"font-weight: 400\">El caso (a) cumple los requisitos, y el (b) no.<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Todos los predicados de la consulta son empujados hacia abajo en el escaneo del \u00edndice (spans).<\/span>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">No podemos empujar los predicados (col LIKE \"%xyz\") al escaneo del \u00edndice. Por lo tanto, la paginaci\u00f3n no se puede empujar hacia abajo tambi\u00e9n.<\/span><\/li>\n<\/ol>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Todos los predicados deben estar representados por un \u00fanico span. Si tenemos que hacer varios escaneos de \u00edndice, despu\u00e9s del procesamiento del escaneo de \u00edndice (por ejemplo, escaneo de uni\u00f3n, escaneo distinto en el explain), no podemos hacer que el indexador eval\u00fae la paginaci\u00f3n. La consulta se ejecutar\u00e1 sin enviar la cl\u00e1usula de paginaci\u00f3n al escaneo del \u00edndice. A continuaci\u00f3n se muestran ejemplos de predicados que generan un \u00fanico intervalo.<\/span>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Por ejemplo (a entre 4 y 8 y a  12)<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">(a = 5 O a = 6)<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">(a IN [4, 6, 9]) <\/span><\/li>\n<\/ol>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Todos los predicados deben ser exactos.<\/span>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Predicados exactos: (a = 5), (a entre 9,8 y 9,99)<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Predicados inexactos: (a &gt; 5 y a &gt; $param)<\/span><\/li>\n<\/ol>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">La consulta no puede contener cl\u00e1usulas de agregaci\u00f3n, agrupaci\u00f3n, tener. No deben eliminar ning\u00fan documento despu\u00e9s del escaneo del \u00edndice (no hay filtrado\/reducci\u00f3n posterior al escaneo del \u00edndice).<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Las claves ORDER BY y el orden de las claves deben coincidir con la clave del \u00edndice y el orden de la clave del \u00edndice.<\/span>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">CREAR \u00cdNDICE i1 EN t(a, b, c);<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">SELECT * FROM t WHERE a = 1 ORDER BY a, b, c;<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">SELECT * FROM t WHERE a = 1 ORDER BY b, c;<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">SELECT * FROM t WHERE a &gt; 3 ORDER BY b, c<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">SELECT * FROM t WHERE a &gt; 3 ORDER BY a, b, c<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">SELECT * FROM t WHERE (a LIKE \"%xyz\") ORDER BY a, b, c OFFSET 10 LIMIT 5;<\/span><\/li>\n<li style=\"list-style-type: none\"><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p><span style=\"font-weight: 400\">El caso (2) coincide perfectamente con el pedido.<\/span><\/p>\n<p><span style=\"font-weight: 400\">El caso (3) no coincide perfectamente, pero la clave principal tiene un filtro de igualdad. Por lo tanto, sabemos que los resultados de la exploraci\u00f3n estar\u00e1n en el orden de (b, c).  Por lo tanto, la paginaci\u00f3n pushdown al \u00edndice es posible.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Para el caso (4), la clave principal tiene un predicado de rango (a &gt; 3) y, por lo tanto, no es posible el pushdown de paginaci\u00f3n.<\/span><\/p>\n<p><span style=\"font-weight: 400\">En el caso (5), la cl\u00e1usula ORDER BY coincide perfectamente con las claves del \u00edndice. Por lo tanto, podemos enviar la paginaci\u00f3n al indexador, incluso si hay un predicado de rango en la clave principal.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Para el caso (f), podemos explotar el orden del \u00edndice, pero no podemos presionar OFFSET y LIMIT porque el predicado completo no puede ser evaluado por el escaneo del \u00edndice. Dado que obtenemos los resultados en el orden requerido, una vez proyectados el n\u00famero de documentos OFFSET y LIMIT, finalizamos la exploraci\u00f3n del \u00edndice.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Para simplificar, he utilizado una sola clave principal. Las afirmaciones son generalizadas y aplicables a m\u00faltiples claves principales.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Obviamente, la l\u00f3gica de este optimizador es compleja. V\u00e9ase informaci\u00f3n adicional en el ap\u00e9ndice sobre los requisitos.<\/span><\/p>\n<p><b>OFFSET por encima:<\/b><\/p>\n<p><span style=\"font-weight: 400\">La muestra de viajes inicial tiene unos 900 documentos con (tipo = \"hotel\"). Para experimentar, simplemente aumento la cantidad de datos volviendo a insertar los mismos datos varias veces utilizando la siguiente consulta:<\/span><\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:plsql decode:true\">insert into `travel-sample`(key UUID(), value t) select t from `travel-sample` t ;\r\n\r\nselect count(*) from `travel-sample` where type = \u201chotel\u201d;\r\n\r\n{\r\n\r\n\u00a0\u00a0\u00a0\"$1\": 38318\r\n\r\n\u00a0}<\/pre>\n<p><span style=\"font-weight: 400\">Ahora, probemos esta consulta:<\/span><\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:plsql decode:true\">SELECT *\r\nFROM `travel-sample`\r\nWHERE type = \u2018hotel\u2019\r\nORDER BY country, city\r\nOFFSET 38000\r\nLIMIT 10;<\/pre>\n<table>\n<tbody>\n<tr>\n<td><span style=\"font-weight: 400\">OFFSET<\/span><\/td>\n<td><span style=\"font-weight: 400\">L\u00cdMITE<\/span><\/td>\n<td><span style=\"font-weight: 400\">Tiempo de respuesta<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">38000<\/span><\/td>\n<td><span style=\"font-weight: 400\">10<\/span><\/td>\n<td><span style=\"font-weight: 400\">28,97 ms<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-weight: 400\">A medida que aumenta el OFFSET, aumenta el tiempo que tarda el indizador en recorrer los elementos del \u00edndice. Esto afecta tanto a la latencia como al rendimiento. \u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">\u00bfPodemos mejorar esto? La paginaci\u00f3n por teclas viene al rescate. Todas las reglas que hemos mencionado para la optimizaci\u00f3n de la paginaci\u00f3n se aplican tambi\u00e9n en este caso. Adem\u00e1s, uno de los predicados tiene que ser UNIQUE para que podamos navegar claramente de una p\u00e1gina a otra sin que aparezcan documentos duplicados en varias p\u00e1ginas. Con Couchbase, estamos de suerte. Cada documento de un bucket tiene una clave de documento \u00fanica. Es referenciada por META().id en la consulta N1QL.<\/span><\/p>\n<p><span style=\"font-weight: 400\">La idea b\u00e1sica es que los clientes suelen querer la p\u00e1gina SIGUIENTE en lugar de una p\u00e1gina aleatoria del principio del conjunto de resultados. Por lo tanto, cuando obtenga cada p\u00e1gina en orden, recuerde el \u00faltimo conjunto (M\u00c1S ALTO\/M\u00c1S BAJO dependiendo de la cl\u00e1usula ORDER BY). A continuaci\u00f3n, utilice esa informaci\u00f3n para establecer los predicados y posicionar el \u00edndice para la siguiente b\u00fasqueda. Esto evitar\u00e1 el desperdicio de procesamiento de claves durante OFFSET.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Veamos un ejemplo:<\/span><\/p>\n<p><span style=\"font-weight: 400\">CREATE INDEX ixtypectcy ON `travel-sample`<\/span><span style=\"font-weight: 400\">\u00a0(tipo, pa\u00eds, ciudad, META().id);<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">GET La PRIMERA P\u00c1GINA.  F\u00edjate que he a\u00f1adido META().id a la cl\u00e1usula index, projection y ORDER BY para que garantice el valor UNIQUE en cada una de ellas.<\/span><\/li>\n<\/ol>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:plsql decode:true\">SELECT country, city, META().id\r\nFROM `travel-sample` use index (ixtypectcy)\r\nWHERE type = \"hotel\"\r\nORDER BY country, city, META().id\r\nOFFSET 0\r\nLIMIT 5;<\/pre>\n<p>Resultados:<\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:js decode:true\">\u00a0{\r\n\u00a0\u00a0\u00a0\"city\": \"Avignon\",\r\n\u00a0\u00a0\u00a0\"country\": \"France\",\r\n\u00a0\u00a0\u00a0\"id\": \"000cb76b-ed85-4f56-9a6e-a6c300902944\"\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"city\": \"Avignon\",\r\n\u00a0\u00a0\u00a0\"country\": \"France\",\r\n\u00a0\u00a0\u00a0\"id\": \"0070d2ac-e411-4aeb-a1e7-4a00635d2d5a\"\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"city\": \"Avignon\",\r\n\u00a0\u00a0\u00a0\"country\": \"France\",\r\n\u00a0\u00a0\u00a0\"id\": \"01e4c1da-3749-43ce-88e3-37a00d0a376f\"\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"city\": \"Avignon\",\r\n\u00a0\u00a0\u00a0\"country\": \"France\",\r\n\u00a0\u00a0\u00a0\"id\": \"0352b5c9-fcbf-48bc-9cf8-f5760cc910a2\"\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"city\": \"Avignon\",\r\n\u00a0\u00a0\u00a0\"country\": \"France\",\r\n\u00a0\u00a0\u00a0\"id\": \"038c8a13-e1e7-4848-80ec-8819ff923602\"\r\n\u00a0}<\/pre>\n<p><span style=\"font-weight: 400\">Esta consulta se ejecut\u00f3 en 5,14 milisegundos.<\/span><\/p>\n<ol start=\"2\">\n<li><span style=\"font-weight: 400\"> Ahora, construya la consulta para la p\u00e1gina siguiente SIN utilizar OFFSET:<\/span><\/li>\n<\/ol>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:plsql decode:true\">SELECT country, city, META().id\r\nFROM `travel-sample` use index (ixtypectcy)\r\nWHERE type = \"hotel\"\r\nAND country &gt;= \u201cFrance\u201d\r\nAND city &gt;= \u201cAvignon\u201d\r\nAND META().id &gt; \"038c8a13-e1e7-4848-80ec-8819ff923602\"\r\nORDER BY country, city, META().id\r\nLIMIT 5;<\/pre>\n<p><span style=\"font-weight: 400\">\u00bfC\u00f3mo hemos construido esta consulta?<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Reutilice todos los predicados de la cl\u00e1usula WHERE. (tipo = \"hotel\").<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Ahora, tome las claves del ORDER BY y construya los predicados adicionales. As\u00ed, simplemente tome el valor m\u00e1s alto devuelto por la \u00faltima consulta y a\u00f1ada los nuevos predicados.   No a\u00f1ada la clave del documento todav\u00eda.  En este caso, estamos ordenando en orden ascendente. Por lo tanto, utilice el operador Mayor que O Igual a.<\/span><\/li>\n<\/ol>\n<p>En este caso, es: (pa\u00eds &gt;= \"Francia\" Y ciudad &gt;= \"Avi\u00f1\u00f3n\").<\/p>\n<p><span style=\"font-weight: 400\">Ahora, para asegurar un valor \u00fanico, a\u00f1adimos el predicado META().id.<\/span><\/p>\n<p><span style=\"font-weight: 400\">(META().id &gt; \"038c8a13-e1e7-4848-80ec-8819ff923602\")<\/span><\/p>\n<p><span style=\"font-weight: 400\">Esto se ejecuta en 5 milisegundos con el siguiente plan. A medida que avance por las p\u00e1ginas siguientes, simplemente repita los pasos para construir la siguiente consulta y evitar el OFFSET. \u00a1Puede continuar hasta el infinito con un tiempo de respuesta similar!<\/span><\/p>\n<pre class=\"theme:github whitespace-before:1 whitespace-after:1 lang:js decode:true\">\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"#operator\": \"IndexScan2\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"covers\": [\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"cover ((`travel-sample`.`type`))\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"cover ((`travel-sample`.`country`))\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"cover ((`travel-sample`.`city`))\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"cover ((meta(`travel-sample`).`id`))\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"cover ((meta(`travel-sample`).`id`))\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0],\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"index\": \"ixtypectcy\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"index_id\": \"5e43ce0471785942\",\r\n\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"index_projection\": {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"entry_keys\": [\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a00,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a01,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a02\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0],\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"primary_key\": true\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"keyspace\": \"travel-sample\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"limit\": \"5\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"namespace\": \"default\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"spans\": [\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"exact\": true,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"range\": [\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"high\": \"\\\"hotel\\\"\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"inclusion\": 3,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"low\": \"\\\"hotel\\\"\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"inclusion\": 1,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"low\": \"\\\"France\\\"\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"inclusion\": 1,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"low\": \"\\\"Avignon\\\"\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"inclusion\": 0,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"low\": \"\\\"038c8a13-e1e7-4848-80ec-8819ff923602\\\"\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0]\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0],<\/pre>\n<p><span style=\"font-weight: 400\"><strong>RESUMEN:<\/strong> <\/span><\/p>\n<p><span style=\"font-weight: 400\">Acabas de aprender c\u00f3mo funciona la paginaci\u00f3n. Tambi\u00e9n aprendiste c\u00f3mo el optimizador N1QL de Couchbase explota el \u00edndice para mejorar la eficiencia del rendimiento de la paginaci\u00f3n de consultas.  Puedes usar las t\u00e9cnicas de paginaci\u00f3n keyset para mejorar a\u00fan m\u00e1s el rendimiento de OFFSET usando la t\u00e9cnica escrita.<\/span><b><\/b><\/p>\n<p><b>Referencias:<\/b><\/p>\n<ol>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/es\/optimizing-database-pagination-using-couchbase-n1ql\/\">https:\/\/www.couchbase.com\/blog\/optimizing-database-pagination-using-couchbase-n1ql\/<\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.slideshare.net\/MarkusWinand\/p2d2-pagination-done-the-postgresql-way?qid=237cb981-6e99-46e8-9197-96eacfa0bb86&amp;v=&amp;b=&amp;from_search=3\"><span style=\"font-weight: 400\">https:\/\/www.slideshare.net\/MarkusWinand\/p2d2-pagination-done-the-postgresql-way<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/use-the-index-luke.com\/sql\/partial-results\/fetch-next-page\"><span style=\"font-weight: 400\">https:\/\/use-the-index-luke.com\/sql\/partial-results\/fetch-next-page<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/blog.jooq.org\/2013\/10\/26\/faster-sql-paging-with-jooq-using-the-seek-method\/\"><span style=\"font-weight: 400\">https:\/\/blog.jooq.org\/2013\/10\/26\/faster-sql-paging-with-jooq-using-the-seek-method\/<\/span><\/a><\/li>\n<\/ol>\n<p><b>Ap\u00e9ndice: <\/b><span style=\"font-weight: 400\">Optimizar la consulta con orden, desplazamiento y l\u00edmite para aprovechar el orden de los \u00edndices<\/span><\/p>\n<p><span style=\"font-weight: 400\">La evaluaci\u00f3n de la consulta ORDER BY puede explotar el orden del \u00edndice con el indexador devolviendo los resultados en el orden requerido y la consulta no tiene que modificar el orden (por ejemplo, hace agrupaciones, uniones). Cuando cambia el orden de los registros, es necesario utilizar datos de ordenaci\u00f3n para satisfacer la cl\u00e1usula ORDER BY.<\/span><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">No se utilizar\u00e1 el orden de \u00edndice cuando la cl\u00e1usula from contenga agregados.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El orden del \u00edndice no se utilizar\u00e1 cuando est\u00e9 presente la cl\u00e1usula GROUP BY.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El orden del \u00edndice no se utilizar\u00e1 cuando se utilicen JOINs, NEST o UNNEST.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El orden del \u00edndice no se utilizar\u00e1 cuando DISTINCT est\u00e9 presente.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">No se utilizar\u00e1 el orden de \u00edndice cuando se utilicen operadores SET. Esto incluye UNION, UNION ALL, INTERSECT, EXCEPT, EXCEPTALL.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El orden de los \u00edndices no se utilizar\u00e1 cuando se trate de una exploraci\u00f3n primaria.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">No se utilizar\u00e1 el orden de \u00edndice cuando se trate de una exploraci\u00f3n de intersecci\u00f3n o uni\u00f3n.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El orden de los \u00edndices no se utilizar\u00e1 cuando se trate de \u00edndices de matrices.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El orden del \u00edndice no se utilizar\u00e1 cuando la intercalaci\u00f3n del orden (ASC, DESC) no coincida con la intercalaci\u00f3n del \u00edndice.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El orden de \u00edndice no se utilizar\u00e1 cuando alg\u00fan t\u00e9rmino de orden no coincida con claves de \u00edndice.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Si la consulta explota el orden del \u00edndice, el operador Orden no estar\u00e1 presente en el EXPLAIN de la consulta.<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400\">OFFSET y LIMIT pueden ser empujados a IndexScan <\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">cuando el ORDER BY est\u00e1 presente y es capaz de explotar el orden del \u00edndice<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Cuando la consulta ORDER BY no est\u00e1 presente<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Todos los predicados se env\u00edan al indizador como parte de los intervalos.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Los valores de los tramos empujados son exactos <\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Basado en intervalos El Indexador no genera falsos positivos<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">La consulta no reduce a\u00fan m\u00e1s los resultados de la exploraci\u00f3n de \u00edndices.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Si el OFFSET es empujado al indexador \"offset\" aparecer\u00e1 en la secci\u00f3n IndexScan del EXPLAIN y el Operador Offset no estar\u00e1 presente al final del EXPLAIN.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Si el l\u00edmite es empujado al indexador \"limit\" aparecer\u00e1 en la secci\u00f3n IndexScan del EXPLAIN. <\/span><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Read the pagination background in my previous article: https:\/\/www.couchbase.com\/blog\/optimizing-database-pagination-using-couchbase-n1ql\/ Pagination is the task of dividing the potential result into pages and retrieving the required pages, one by one on demand. \u00a0Using OFFSET and LIMIT is the easy way to write [&hellip;]<\/p>","protected":false},"author":55,"featured_media":4429,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1814,1815,9417,1812],"tags":[1998,1696,1261,2081],"ppma_author":[8929],"class_list":["post-4421","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-design","category-best-practices-and-tutorials","category-performance","category-n1ql-query","tag-application","tag-indexing","tag-json","tag-pagination"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.7.1 (Yoast SEO v25.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>OFFSET and Keyset Pagination in N1QL Query | Couchbase<\/title>\n<meta name=\"description\" content=\"Pagination is a common application and has a major impact on customer experience. Here are detailed issues and solutions with Couchbase N1QL.\" \/>\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\/offset-keyset-pagination-n1ql-query-couchbase\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Database Pagination: Using OFFSET and Keyset in N1QL\" \/>\n<meta property=\"og:description\" content=\"Pagination is a common application and has a major impact on customer experience. Here are detailed issues and solutions with Couchbase N1QL.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/offset-keyset-pagination-n1ql-query-couchbase\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-01-11T19:56:34+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T03:20:11+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png\" \/>\n\t<meta property=\"og:image:width\" content=\"853\" \/>\n\t<meta property=\"og:image:height\" content=\"363\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Keshav Murthy\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@rkeshavmurthy\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Keshav Murthy\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/\"},\"author\":{\"name\":\"Keshav Murthy\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c261644262bf98e146372fe647682636\"},\"headline\":\"Database Pagination: Using OFFSET and Keyset in N1QL\",\"datePublished\":\"2018-01-11T19:56:34+00:00\",\"dateModified\":\"2025-06-14T03:20:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/\"},\"wordCount\":2258,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png\",\"keywords\":[\"application\",\"Indexing\",\"JSON\",\"pagination\"],\"articleSection\":[\"Application Design\",\"Best Practices and Tutorials\",\"High Performance\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/\",\"name\":\"OFFSET and Keyset Pagination in N1QL Query | Couchbase\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png\",\"datePublished\":\"2018-01-11T19:56:34+00:00\",\"dateModified\":\"2025-06-14T03:20:11+00:00\",\"description\":\"Pagination is a common application and has a major impact on customer experience. Here are detailed issues and solutions with Couchbase N1QL.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png\",\"width\":853,\"height\":363},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Database Pagination: Using OFFSET and Keyset in N1QL\"}]},{\"@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\/c261644262bf98e146372fe647682636\",\"name\":\"Keshav Murthy\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/4e51d72fc07c662aa791316deafffac4\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g\",\"caption\":\"Keshav Murthy\"},\"description\":\"Keshav Murthy is a Vice President at Couchbase R&amp;D. Previously, he was at MapR, IBM, Informix, Sybase, with more than 20 years of experience in database design &amp; development. He lead the SQL and NoSQL R&amp;D team at IBM Informix. He has received two President's Club awards at Couchbase, two Outstanding Technical Achievement Awards at IBM. Keshav has a bachelor's degree in Computer Science and Engineering from the University of Mysore, India, holds eleven US patents and has four US patents pending.\",\"sameAs\":[\"https:\/\/blog.planetnosql.com\/\",\"https:\/\/x.com\/rkeshavmurthy\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/keshav-murthy\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"OFFSET and Keyset Pagination in N1QL Query | Couchbase","description":"Pagination is a common application and has a major impact on customer experience. Here are detailed issues and solutions with Couchbase N1QL.","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\/offset-keyset-pagination-n1ql-query-couchbase\/","og_locale":"es_MX","og_type":"article","og_title":"Database Pagination: Using OFFSET and Keyset in N1QL","og_description":"Pagination is a common application and has a major impact on customer experience. Here are detailed issues and solutions with Couchbase N1QL.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/offset-keyset-pagination-n1ql-query-couchbase\/","og_site_name":"The Couchbase Blog","article_published_time":"2018-01-11T19:56:34+00:00","article_modified_time":"2025-06-14T03:20:11+00:00","og_image":[{"width":853,"height":363,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png","type":"image\/png"}],"author":"Keshav Murthy","twitter_card":"summary_large_image","twitter_creator":"@rkeshavmurthy","twitter_misc":{"Written by":"Keshav Murthy","Est. reading time":"11 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/"},"author":{"name":"Keshav Murthy","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c261644262bf98e146372fe647682636"},"headline":"Database Pagination: Using OFFSET and Keyset in N1QL","datePublished":"2018-01-11T19:56:34+00:00","dateModified":"2025-06-14T03:20:11+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/"},"wordCount":2258,"commentCount":1,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png","keywords":["application","Indexing","JSON","pagination"],"articleSection":["Application Design","Best Practices and Tutorials","High Performance","SQL++ \/ N1QL Query"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/","url":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/","name":"OFFSET and Keyset Pagination in N1QL Query | Couchbase","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png","datePublished":"2018-01-11T19:56:34+00:00","dateModified":"2025-06-14T03:20:11+00:00","description":"Pagination is a common application and has a major impact on customer experience. Here are detailed issues and solutions with Couchbase N1QL.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/01\/arrows2.png","width":853,"height":363},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/offset-keyset-pagination-n1ql-query-couchbase\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Database Pagination: Using OFFSET and Keyset in N1QL"}]},{"@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\/c261644262bf98e146372fe647682636","name":"Keshav Murthy","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/4e51d72fc07c662aa791316deafffac4","url":"https:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g","caption":"Keshav Murthy"},"description":"Keshav Murthy es Vicepresidente de Couchbase R&amp;D. Anteriormente, estuvo en MapR, IBM, Informix, Sybase, con m\u00e1s de 20 a\u00f1os de experiencia en dise\u00f1o y desarrollo de bases de datos. Dirigi\u00f3 el equipo de I+D de SQL y NoSQL en IBM Informix. Ha recibido dos premios President's Club en Couchbase y dos premios Outstanding Technical Achievement en IBM. Keshav es licenciado en Inform\u00e1tica e Ingenier\u00eda por la Universidad de Mysore (India), es titular de once patentes estadounidenses y tiene cuatro pendientes.","sameAs":["https:\/\/blog.planetnosql.com\/","https:\/\/x.com\/rkeshavmurthy"],"url":"https:\/\/www.couchbase.com\/blog\/es\/author\/keshav-murthy\/"}]}},"authors":[{"term_id":8929,"user_id":55,"is_guest":0,"slug":"keshav-murthy","display_name":"Keshav Murthy","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g","first_name":"Keshav","last_name":"Murthy","user_url":"https:\/\/blog.planetnosql.com\/","author_category":"","description":"Keshav Murthy es Vicepresidente de Couchbase R&amp;D. Anteriormente, estuvo en MapR, IBM, Informix, Sybase, con m\u00e1s de 20 a\u00f1os de experiencia en dise\u00f1o y desarrollo de bases de datos. Dirigi\u00f3 el equipo de I+D de SQL y NoSQL en IBM Informix. Ha recibido dos premios President's Club en Couchbase y dos premios Outstanding Technical Achievement en IBM. Keshav es licenciado en Inform\u00e1tica e Ingenier\u00eda por la Universidad de Mysore (India), es titular de diez patentes estadounidenses y tiene tres pendientes."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/4421","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\/55"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=4421"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/4421\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/4429"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=4421"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=4421"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=4421"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=4421"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}