As aplicações Web paginam frequentemente os dados à medida que são apresentados aos utilizadores. O utilizador final recebe uma página de resultados e, quando navega para a página seguinte, o lote de resultados seguinte é obtido e apresentado. Esta página descreve como adicionar a paginação aos resultados da pesquisa quando efetua uma pesquisa de texto completo no Spanner.
Opções de paginação
Existem duas formas de implementar consultas paginadas no Spanner: paginação baseada em chaves (recomendada) e paginação baseada em deslocamentos.
A paginação baseada em chaves é um método para obter resultados da pesquisa em blocos mais pequenos e mais fáceis de gerir, garantindo resultados consistentes em todos os pedidos. Um identificador exclusivo (a "chave") do último resultado de uma página é usado como ponto de referência para obter o conjunto seguinte de resultados.
Geralmente, o Spanner recomenda a utilização da paginação baseada em chaves. Embora a paginação baseada em deslocamentos seja mais fácil de implementar, tem duas desvantagens significativas:
- Custo de consulta mais elevado:a paginação baseada em deslocamentos obtém e descarta repetidamente os mesmos resultados, o que leva a um aumento dos custos e a uma diminuição do desempenho.
- Resultados inconsistentes: nas consultas paginadas, cada página é normalmente obtida com uma data/hora de leitura diferente. Por exemplo, a primeira página pode ser proveniente de uma consulta às 13:00 e a seguinte de uma consulta às 13:10. Isto significa que os resultados da pesquisa podem mudar entre consultas, o que leva a resultados inconsistentes nas páginas.
Por outro lado, a paginação baseada em chaves usa um identificador único (chave) do último resultado de uma página para obter o conjunto de resultados seguinte. Isto garante uma obtenção eficiente e resultados consistentes, mesmo que os dados subjacentes mudem.
Para oferecer estabilidade nos resultados das páginas, a aplicação pode emitir todas as consultas para diferentes páginas na mesma data/hora. No entanto, isto pode falhar se a consulta exceder o período de retenção de versões (o predefinido é 1 hora). Por exemplo, esta falha ocorre se version_gc
for de uma hora e o utilizador final tiver obtido os primeiros resultados às 13:00 e clicado em Seguinte às 15:00.
Use a paginação baseada em chaves
A paginação baseada em chaves memoriza o último item da página anterior e usa-o como ponto de partida para a consulta da página seguinte. Para o conseguir, a consulta tem de devolver as colunas especificadas na cláusula ORDER BY
e limitar o número de linhas através de LIMIT
.
Para que a paginação baseada em chaves funcione, a consulta tem de ordenar os resultados por alguma ordem total rigorosa. A forma mais fácil de obter um é escolher qualquer total de pedidos e, em seguida, adicionar colunas de desempate, se necessário. Na maioria dos casos, a ordem total é a ordem de ordenação do índice de pesquisa e a combinação única de colunas é a chave principal da tabela base.
Usando o nosso esquema de exemplo Albums
, para a primeira página, a consulta tem o seguinte aspeto:
GoogleSQL
SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 10;
PostgreSQL
SELECT albumid, releasetimestamp
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY releasetimestamp DESC, albumid
LIMIT 10;
O AlbumId
é o fator de desempate, uma vez que ReleaseTimestamp
não é uma chave. Podem existir dois álbuns diferentes com o mesmo valor para ReleaseTimestamp
.
Para retomar, a aplicação executa novamente a mesma consulta, mas com uma cláusula WHERE
que restringe os resultados da página anterior. A condição adicional tem de ter em conta a direção da chave (ascendente versus descendente), os critérios de desempate e a ordem dos valores NULL para colunas anuláveis.
No nosso exemplo, AlbumId
é a única coluna de chave (por ordem crescente) e não pode ser NULL, pelo que a condição é a seguinte:
GoogleSQL
SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE (ReleaseTimestamp < @last_page_release_timestamp
OR (ReleaseTimestamp = @last_page_release_timestamp
AND AlbumId > @last_page_album_id))
AND SEARCH(AlbumTitle_Tokens, @p)
ORDER BY ReleaseTimestamp DESC, AlbumId ASC
LIMIT @page_size;
PostgreSQL
Este exemplo usa os parâmetros de consulta $1
, $2
, $3
e $4
, que estão associados
aos valores especificados para last_page_release_timestamp
, last_page_album_id
, query
e page_size
, respetivamente.
SELECT albumid, releasetimestamp
FROM albums
WHERE (releasetimestamp < $1
OR (releasetimestamp = $1
AND albumid > $2))
AND spanner.search(albumtitle_tokens, $3)
ORDER BY releasetimestamp DESC, albumid ASC
LIMIT $4;
O Spanner interpreta este tipo de condição como seekable. Isto significa que o Spanner não lê o índice dos documentos que está a filtrar. Esta otimização torna a paginação baseada em chaves muito mais eficiente do que a paginação baseada em deslocamentos.
Use paginação baseada em deslocamento
A paginação baseada em deslocamento tira partido das cláusulas LIMIT
e OFFSET
da consulta SQL para simular páginas. O valor LIMIT
indica o número de resultados por página.
O valor OFFSET
é definido como zero para a primeira página, o tamanho da página para a segunda página e o dobro do tamanho da página para a terceira página.
Por exemplo, a seguinte consulta obtém a terceira página, com um tamanho da página de 50:
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 50 OFFSET 100;
PostgreSQL
SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY releasetimestamp DESC, albumid
LIMIT 50 OFFSET 100;
Notas de utilização:
- A cláusula
ORDER BY
é altamente recomendada para garantir uma ordenação consistente entre as páginas. - Nas consultas de produção, use parâmetros de consulta em vez de constantes para especificar
LIMIT
eOFFSET
para tornar o armazenamento em cache de consultas mais eficiente. Para mais informações, consulte Parâmetros de consulta.
O que se segue?
- Saiba como classificar os resultados da pesquisa.
- Saiba como fazer uma pesquisa de substring.
- Saiba como misturar consultas de texto completo e sem texto.
- Saiba como pesquisar várias colunas.