Introducción
Tu colega ya ha optimizado las dos consultas de primera página de la tienda. La cola de recogida muestra primero los pedidos más antiguos y el historial del cliente, los más recientes. Ahora una llamada necesita continuar después de los primeros siete pedidos. Varios pedidos reales comparten una marca temporal, por lo que un cursor basado solo en ella puede perder registros o repetirlos.
Esta unidad independiente proporciona su propia instantánea MySQL, queue.sql y history.sql de primera página funcionales, índices aplicados e indexes.sql. No necesita archivos de la VM anterior. Editarás las dos consultas guardadas para que cada pedido original sobreviva a recorridos completos de páginas ascendentes y descendentes, manteniendo un acceso indexado eficiente.
Se requieren los parámetros MySQL, los límites semiabiertos, la ordenación de dos columnas y los planes de diagnóstico de la primera unidad. Aquí se enseñan los cursores que admiten null, sus comparaciones completas y las comprobaciones de páginas profundas. Usa Terminal y /home/labex/project/order-desk. Modifica solo queue.sql y history.sql; conserva los índices y su fuente proporcionados, todos los datos de pedidos, las columnas, la clave primaria y las herramientas ejecutables.
Cada página sigue conteniendo como máximo siete pedidos reales y usa como máximo 64 solicitudes nativas de filas de diagnóstico. La conexión preparada mantiene desactivado index condition pushdown para esta comparación controlada; conserva esa configuración y evita indicaciones al optimizador. Las solicitudes usan una instantánea fija de datos. No se afirma ninguna garantía de instantánea ante actualizaciones concurrentes, recuento de E/S física ni latencia en producción. Las etiquetas y salidas del entorno se mantienen en inglés.
Llevar ambas claves a la siguiente página de recogida
En este paso, avanzarás por la cola del pedido más antiguo al más reciente sin perder los pedidos restantes de la misma marca temporal.
Empieza en Terminal, en el intérprete normal del sistema. Los programas proporcionados db y desk son las mismas interfaces practicadas en la primera unidad. Si una ruta o un nombre de archivo es incorrecto, usa ls, comprueba el nombre real y vuelve a intentarlo sin modificar las filas originales. Aquí cat imprime el texto guardado de la consulta. La solicitud page siguiente lee su salida real; ninguna consulta de referencia repara filas ausentes.
cd /home/labex/project/order-desk
cat queue.sql
./desk page queue
La consulta guardada tiene las condiciones útiles de tienda, estado y tiempo, y la ordenación (placed_at,order_id), pero ninguna condición de cursor. Su primera página devuelve correctamente de 900001 a 900007. El cursor_for_next_request del puesto contiene el tiempo y el ID de la última fila real. Identifica dónde puede comenzar una solicitud siguiente; no promete otra página no vacía.
--after recibe dos argumentos: la última marca temporal real y el último ID de pedido real. Las comillas mantienen el espacio de la marca temporal dentro de un único argumento del intérprete. Solicita la página siguiente usando el cursor que acabas de observar:
./desk page queue --after "2025-05-10 09:15:00.000000" 900007
La consulta inicial sin cambios vuelve a devolver los primeros siete ID porque ignora ese cursor. Todos los comandos se ejecutaron correctamente, pero esta es la página siguiente equivocada. No cambies las marcas temporales fuente ni elimines duplicados de una lista mostrada para ocultar el problema.
El puesto proporciona dos variables de sesión nativas más: @after_at y @after_id. Para la primera página, ambas son NULL, que significa que no hay cursor previo. SQL comprueba esa ausencia con IS NULL, no con = NULL. En otro caso, la siguiente fila en orden del más antiguo al más reciente debe tener una marca temporal posterior, o la misma marca temporal y un ID mayor. Usar solo placed_at > @after_at perdería los ID 900008 y 900009 de la hora repetida.
Conserva el grupo, el estado y los límites semiabiertos existentes. Coloca las alternativas de cursor entre paréntesis, unidas a esos filtros por AND; OR no debe liberar una fila de las otras condiciones de negocio. El orden sigue siendo ascendente por ambas claves. cat > queue.sql reemplaza la consulta completa siguiente; el marcador SQL entre comillas del here-document impide la expansión del intérprete y cierra en su propia línea.
cat > queue.sql <<'SQL'
SELECT order_id,shop_id AS group_id,customer_id AS actor_id,
state,placed_at AS event_at,total_cents AS amount_cents
FROM orders
WHERE shop_id=@group_id AND state=@state
AND placed_at>=@from_at AND placed_at<@until_at
AND (@after_at IS NULL
OR placed_at>@after_at
OR (placed_at=@after_at AND order_id>@after_id))
ORDER BY placed_at ASC,order_id ASC
LIMIT 7;
SQL
./desk page queue
./desk page queue --after "2025-05-10 09:15:00.000000" 900007
./desk plan queue --after "2025-05-10 09:15:00.000000" 900007
La primera página permanece sin cambios. La siguiente contiene ahora 900008, 900009 y 900021 con sus tiempos y centavos originales. La medianoche siguiente exacta sigue fuera del día solicitado; el último microsegundo permanece dentro. El plan debería llegar al intervalo indexado del cursor en lugar de leer y descartar cada pedido anterior. Inspecciona juntas las filas reales y el recuento de diagnóstico.
La acción walk ejecuta repetidamente esta misma consulta guardada, pasando el cursor de la última fila real, hasta que aparece una página realmente vacía. Conserva exactamente el orden y los campos devueltos; no ordena, elimina duplicados ni rellena los resultados. Si una consulta repite su último cursor, la herramienta informa de un error en lugar de presentar un recorrido parcial como completo.
./desk walk queue
./desk page queue --after "2025-05-10 23:59:59.999999" 900021
El recorrido entrega los diez pedidos exactamente una vez: siete, después tres y después una página vacía. El cursor explícito de la última fila también devuelve una lista vacía de filas. Es un final válido, a diferencia de un Order desk error. Si un archivo o SQL es incorrecto, usa ls o cat para inspeccionarlo, corrige la consulta guardada y vuelve a ejecutar la solicitud real. No alteres los índices proporcionados ni las filas originales. Ejecuta la comprobación del paso después de confirmar la cola completa.
Continuar el historial del más reciente al más antiguo con trabajo acotado
En este paso, completarás la dirección opuesta del cursor y compararás una página profunda con una lectura de los mismos datos basada en desplazamiento.
Permanece en Terminal y en /home/labex/project/order-desk. Conserva la consulta de recogida corregida y los índices y su fuente preparados. El historial del cliente usa DESC para tiempo e ID, por lo que una fila siguiente tiene un tiempo anterior, o el mismo tiempo y un ID menor. Su filtro de cliente y su intervalo semiabierto siguen vigentes. El caso NULL de primera página permanece igual.
Reemplaza la consulta de historial completa. No añadas una restricción de estado ready: el historial del cliente incluye todos los estados y tiendas originales de ese cliente.
cat > history.sql <<'SQL'
SELECT order_id,shop_id AS group_id,customer_id AS actor_id,
state,placed_at AS event_at,total_cents AS amount_cents
FROM orders
WHERE customer_id=@actor_id
AND placed_at>=@from_at AND placed_at<@until_at
AND (@after_at IS NULL
OR placed_at<@after_at
OR (placed_at=@after_at AND order_id<@after_id))
ORDER BY placed_at DESC,order_id DESC
LIMIT 7;
SQL
./desk page history
./desk page history --after "2025-05-10 09:15:00.000000" 900004
./desk walk history
La primera página empieza con 900021 y después va de 900009 a 900004. Su página siguiente contiene 900003, 900002 y 900001. El recorrido completo conserva los diez pedidos y después llega a una página realmente vacía. El pedido de cero centavos permanece en la primera página; ni el tiempo ni el precio iguales fusionan identidades.
Un OFFSET profundo pide a MySQL descartar las filas anteriores después de ordenarlas. Puede devolver siete filas correctas mientras lee muchas más. En su lugar, un cursor puede empezar cerca de la última clave real. Compara ambos sobre el historial de enero a abril del cliente 77, cuyo final exclusivo es el 1 de mayo.
En el cliente nativo siguiente, LIMIT 1 OFFSET 199 omite 199 filas ordenadas y devuelve la fila 200, la última que precede a una página OFFSET 200. EXPLAIN ANALYZE ejecuta realmente la consulta con desplazamiento e informa del trabajo de sus iteradores. El SELECT final muestra las filas reales de esa página. Los here-documents y ambas direcciones de ordenación son los mismos que ya practicaste.
./db <<'SQL'
SELECT order_id,placed_at
FROM orders
WHERE customer_id=77
AND placed_at>='2025-01-01' AND placed_at<'2025-05-01'
ORDER BY placed_at DESC,order_id DESC
LIMIT 1 OFFSET 199;
EXPLAIN ANALYZE FORMAT=TREE
SELECT order_id,shop_id AS group_id,customer_id AS actor_id,
state,placed_at AS event_at,total_cents AS amount_cents
FROM orders
WHERE customer_id=77
AND placed_at>='2025-01-01' AND placed_at<'2025-05-01'
ORDER BY placed_at DESC,order_id DESC
LIMIT 7 OFFSET 200;
SELECT order_id,shop_id AS group_id,customer_id AS actor_id,
state,placed_at AS event_at,total_cents AS amount_cents
FROM orders
WHERE customer_id=77
AND placed_at>='2025-01-01' AND placed_at<'2025-05-01'
ORDER BY placed_at DESC,order_id DESC
LIMIT 7 OFFSET 200;
SQL
La fila 200 es el pedido 94263 a las 2025-02-25 02:30:00.000000. Lee las filas reales del iterador inferior: la solicitud con desplazamiento debe pasar por las primeras 200 antes de entregar siete. Ahora usa esa fila real como cursor de la consulta guardada, con el mismo cliente y límites. --from y --until se aplican solo a esta invocación.
./desk page history --from 2025-01-01 --until 2025-05-01 --after "2025-02-25 02:30:00.000000" 94263
./desk plan history --from 2025-01-01 --until 2025-05-01 --after "2025-02-25 02:30:00.000000" 94263
Aparecen los mismos siete ID, empezando por 3542 y 87067. La consulta con cursor debería llegar a los intervalos indexados con un recuento real pequeño de solicitudes, en lugar de descartar 200 filas anteriores. Compara el trabajo sobre la misma página, no dos solicitudes sin relación; los milisegundos transcurridos siguen sin establecer el resultado de aceptación.
Por último, comprueba otro cliente, un intervalo vacío válido y el recorrido de recogida sin cambios:
./desk page history --actor 78
./desk page history --from 2027-01-01 --until 2027-01-02
./desk walk queue
Conserva ambos archivos SQL reutilizables. Los índices proporcionados e indexes.sql permanecen intactos. Un error de SQL, archivo o conexión de una consulta sigue siendo un error; el lector no inventa pedidos ausentes. Estos son recorridos estables sobre la instantánea fija preparada, no una instantánea transaccional durante cambios concurrentes. La comprobación final verifica los campos y el orden originales exactos, recorridos pequeños completos, identidades, intervalos y cursores diferentes y el trabajo de diagnóstico, junto con la conservación de la fuente y las herramientas.
Resumen
Continuaste dos vistas indexadas de pedidos mediante cursores completos de marca temporal e ID, conservaste todos los pedidos de la misma hora y los valores de cero centavos, y verificaste finales de recorrido realmente vacíos. Comparaste la misma página profunda mediante solicitudes con OFFSET y con cursor indexado sin tratar los milisegundos como prueba. Ambas direcciones funcionan sobre la instantánea fija mientras permanecen intactos los datos originales, las herramientas y los índices preparados.



