Manter todos os pedidos entre páginas

MySQLBeginner
Pratique Agora

Introdução

Seu colega já otimizou as duas consultas de primeira página da loja. A fila de retirada mostra os mais antigos primeiro, e o histórico de clientes mostra os mais recentes primeiro. Agora, um chamador precisa continuar além dos primeiros sete pedidos. Vários pedidos reais compartilham um timestamp, portanto um cursor apenas de timestamp pode perder registros ou repeti-los.

Esta unidade independente fornece seu próprio retrato MySQL, queue.sql e history.sql funcionais de primeira página, índices aplicados e indexes.sql. Ela não precisa de arquivos da VM anterior. Você editará as duas consultas salvas para que cada pedido original seja preservado em percursos completos de páginas em ordem crescente e decrescente, mantendo acesso indexado eficiente.

Os pré-requisitos são os parâmetros MySQL, limites semiabertos, ordenação por duas colunas e planos de diagnóstico da primeira unidade. Cursores que podem ser NULL, suas comparações completas e verificações de páginas profundas são ensinados aqui. Use Terminal e /home/labex/project/order-desk. Altere apenas queue.sql e history.sql; preserve os índices fornecidos/sua fonte, todos os fatos dos pedidos, as colunas, a chave primária e as ferramentas executáveis.

Cada página ainda contém até sete pedidos reais e usa no máximo 64 solicitações nativas de linhas no diagnóstico. A conexão preparada mantém index condition pushdown desativado para esta comparação controlada; mantenha essa configuração e evite dicas ao otimizador. As solicitações usam um retrato fixo dos dados. Não se afirma garantia de retrato consistente sob atualizações concorrentes, contagem de E/S física nem latência em produção. Os rótulos e as saídas do ambiente de execução permanecem em inglês.

Levar as duas chaves para a próxima página de retirada

Nesta etapa, você avançará na fila dos mais antigos primeiro sem perder os pedidos restantes no mesmo timestamp.

Comece em Terminal, no shell normal. Os programas fornecidos db e desk são as mesmas interfaces praticadas na primeira unidade. Se um caminho ou nome de arquivo estiver errado, use ls, verifique o nome real e tente novamente sem alterar linhas originais. cat exibe aqui o texto salvo da consulta. A solicitação page a seguir lê sua saída real; nenhuma consulta de referência corrige linhas ausentes.

cd /home/labex/project/order-desk
cat queue.sql
./desk page queue

A consulta salva tem as condições úteis de loja/estado/tempo e a ordenação (placed_at,order_id), mas nenhuma condição de cursor. Sua primeira página retorna corretamente 900001 a 900007. O cursor_for_next_request do posto contém o tempo e o ID da última linha real. Ele identifica onde uma próxima solicitação pode começar; não promete outra página não vazia.

--after recebe dois argumentos: o último timestamp real e o último ID real de pedido. As aspas mantêm o espaço do timestamp dentro de um único argumento do shell. Solicite a próxima página usando o cursor que acabou de observar:

./desk page queue --after "2025-05-10 09:15:00.000000" 900007

A consulta inicial inalterada retorna novamente os primeiros sete IDs porque ignora esse cursor. Todos os comandos foram executados com sucesso, mas esta é a próxima página errada. Não altere os timestamps de origem nem elimine duplicatas de uma lista exibida para ocultar o problema.

O posto fornece mais duas variáveis nativas de sessão: @after_at e @after_id. Para a primeira página, ambas são NULL, significando ausência de cursor anterior. O SQL testa essa ausência com IS NULL, não = NULL. Caso contrário, uma próxima linha na ordem dos mais antigos primeiro deve ter um timestamp posterior, ou o mesmo timestamp e um ID maior. Usar apenas placed_at > @after_at perderia os IDs 900008 e 900009 no horário repetido.

Mantenha o grupo, o estado e os limites semiabertos existentes. Coloque as alternativas do cursor entre parênteses, ligadas a esses filtros por AND; OR não deve liberar uma linha das outras condições de negócio. A ordem continua crescente pelas duas chaves. cat > queue.sql substitui a consulta completa abaixo; o marcador SQL do here-document entre aspas impede a expansão do shell e fecha sozinho na linha.

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

A primeira página permanece inalterada. A próxima página agora contém 900008, 900009 e 900021, com seus tempos e centavos originais. A próxima meia-noite exata continua fora do dia solicitado; o último microssegundo permanece dentro. O plano deve alcançar o intervalo indexado do cursor em vez de ler e descartar cada pedido anterior. Inspecione as linhas reais junto com a contagem de diagnóstico.

A ação walk executa repetidamente esta mesma consulta salva, passando o cursor da última linha real, até aparecer uma página realmente vazia. Ela mantém exatamente a ordem e os campos retornados; não ordena, não elimina duplicatas nem preenche resultados. Se uma consulta repetir seu último cursor, a ferramenta informa um erro em vez de apresentar um percurso parcial como completo.

./desk walk queue
./desk page queue --after "2025-05-10 23:59:59.999999" 900021

O percurso entrega todos os dez pedidos exatamente uma vez: sete, depois três e depois uma página vazia. O cursor explícito da última linha também retorna uma lista vazia de linhas. Esse é um final válido, diferentemente de um Order desk error. Se um arquivo ou SQL estiver errado, use ls ou cat para inspecioná-lo, corrija a consulta salva e execute novamente a solicitação real. Não altere os índices fornecidos nem as linhas originais. Execute a verificação da etapa após confirmar a fila completa.

Continuar o histórico dos mais recentes primeiro com trabalho limitado

Nesta etapa, você completará a direção oposta do cursor e comparará uma página profunda com uma leitura dos mesmos dados baseada em deslocamento.

Permaneça em Terminal e em /home/labex/project/order-desk. Mantenha a consulta corrigida de retirada e os índices preparados/sua fonte. O histórico de clientes usa DESC tanto para tempo quanto para ID, portanto uma próxima linha tem um tempo anterior, ou o mesmo tempo e um ID menor. Seu filtro de cliente e intervalo semiaberto continuam valendo. O caso NULL de primeira página permanece igual.

Substitua a consulta completa do histórico. Não adicione uma restrição de estado ready: o histórico de clientes inclui todos os estados e lojas originais desse 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

A primeira página começa com 900021 e depois 900009 até 900004. Sua próxima página contém 900003, 900002 e 900001. O percurso completo mantém todos os dez pedidos e depois chega a uma página realmente vazia. O pedido de zero centavos permanece na primeira página; tempo ou preço iguais nunca unem identidades.

Um OFFSET profundo pede ao MySQL para descartar linhas anteriores após a ordenação. Ele pode retornar sete linhas corretas enquanto lê muito mais. Em vez disso, um cursor pode começar perto da última chave real. Compare os dois no histórico de janeiro a abril do cliente 77, cujo fim exclusivo é 1º de maio.

No cliente nativo abaixo, LIMIT 1 OFFSET 199 pula 199 linhas ordenadas e retorna a 200ª linha, a última que precede uma página com OFFSET 200. EXPLAIN ANALYZE realmente executa a consulta com deslocamento e informa o trabalho de seus iteradores. O SELECT final exibe as linhas reais dessa página. Here-documents e ambas as direções de ordenação são os mesmos já praticados.

./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

A 200ª linha é o pedido 94263 em 2025-02-25 02:30:00.000000. Observe as linhas reais do iterador inferior: a solicitação com deslocamento precisa passar pelas primeiras 200 antes de entregar sete. Agora use essa linha real como cursor da consulta salva, com o mesmo cliente e os mesmos limites. --from e --until se aplicam apenas a esta execução.

./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

Os mesmos sete IDs aparecem, começando por 3542 e 87067. A consulta com cursor deve alcançar os intervalos indexados com uma pequena contagem real de solicitações, em vez de descartar 200 linhas anteriores. Compare o trabalho na mesma página, não em duas solicitações não relacionadas; milissegundos decorridos ainda não estabelecem o resultado da aceitação.

Por fim, verifique outro cliente, um intervalo vazio válido e o percurso inalterado de retirada:

./desk page history --actor 78
./desk page history --from 2027-01-01 --until 2027-01-02
./desk walk queue

Mantenha os dois arquivos SQL reutilizáveis. Os índices fornecidos e indexes.sql permanecem intactos. Um erro de SQL/arquivo/conexão de uma consulta continua sendo um erro; o leitor não inventa pedidos ausentes. Estes são percursos estáveis sobre o retrato fixo preparado, não um retrato transacional durante alterações concorrentes. A verificação final valida campos/ordem originais exatos, percursos pequenos completos, identidades/intervalos/cursores diferentes e trabalho de diagnóstico, além da preservação da origem e das ferramentas.

Resumo

Você deu continuidade a duas visões indexadas de pedidos por meio de cursores completos de timestamp e ID, preservou cada pedido com horário igual e cada valor de zero centavos e verificou finais realmente vazios. Comparou a mesma página profunda por meio de OFFSET e solicitações com cursor indexado sem tratar milissegundos como prova. As duas direções funcionam sobre o retrato fixo, enquanto os dados originais, as ferramentas e os índices preparados permanecem intactos.