Sugestões de desempenho da API
Este documento aborda algumas técnicas que pode usar para melhorar o desempenho da sua aplicação. Em alguns casos, são usados exemplos de outras APIs ou APIs genéricas para ilustrar as ideias apresentadas. No entanto, os mesmos conceitos são aplicáveis à API BigQuery.
Compressão com gzip
Uma forma fácil e conveniente de reduzir a largura de banda necessária para cada pedido é ativar a compressão gzip. Embora isto exija tempo adicional da CPU para descomprimir os resultados, a compensação com os custos de rede torna-o geralmente muito vantajoso.
Para receber uma resposta com codificação gzip, tem de fazer duas coisas: definir um cabeçalho Accept-Encoding
e modificar o seu agente do utilizador para conter a string gzip
. Segue-se um exemplo de cabeçalhos HTTP corretamente formados para ativar a compressão gzip:
Accept-Encoding: gzip User-Agent: my program (gzip)
Trabalhar com recursos parciais
Outra forma de melhorar o desempenho das chamadas API é enviar e receber apenas a parte dos dados que lhe interessa. Isto permite que a sua aplicação evite transferir, analisar e armazenar campos desnecessários, para que possa usar recursos, incluindo rede, CPU e memória, de forma mais eficiente.
Existem dois tipos de pedidos parciais:
- Resposta parcial: um pedido em que especifica os campos a incluir na resposta (use o parâmetro de pedido
fields
). - Patch: um pedido de atualização em que envia apenas os campos que quer alterar (use o verbo HTTP
PATCH
).
Pode encontrar mais detalhes sobre como fazer pedidos parciais nas secções seguintes.
Resposta parcial
Por predefinição, o servidor envia de volta a representação completa de um recurso após o processamento de pedidos. Para um melhor desempenho, pode pedir ao servidor que envie apenas os campos de que realmente precisa e, em alternativa, receber uma resposta parcial.
Para pedir uma resposta parcial, use o parâmetro de pedido fields
para especificar os campos que quer que sejam devolvidos. Pode usar este parâmetro com qualquer pedido que devolva dados de resposta.
Tenha em atenção que o parâmetro fields
afeta apenas os dados de resposta. Não afeta os dados que tem de enviar, se existirem. Para reduzir a quantidade de dados que envia quando modifica recursos, use um pedido patch.
Exemplo
O exemplo seguinte mostra a utilização do parâmetro fields
com uma API "Demo" genérica (fictícia).
Pedido simples: este pedido HTTP GET
omite o parâmetro fields
e devolve o recurso completo.
https://www.googleapis.com/demo/v1
Resposta de recurso completa: os dados de recursos completos incluem os seguintes campos, juntamente com muitos outros que foram omitidos para simplificar.
{ "kind": "demo", ... "items": [ { "title": "First title", "comment": "First comment.", "characteristics": { "length": "short", "accuracy": "high", "followers": ["Jo", "Will"], }, "status": "active", ... }, { "title": "Second title", "comment": "Second comment.", "characteristics": { "length": "long", "accuracy": "medium" "followers": [ ], }, "status": "pending", ... }, ... ] }
Pedido de uma resposta parcial: o seguinte pedido deste mesmo recurso usa o parâmetro fields
para reduzir significativamente a quantidade de dados devolvidos.
https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)
Resposta parcial: em resposta ao pedido acima, o servidor envia uma resposta que contém apenas as informações do tipo, juntamente com uma matriz de itens reduzida que inclui apenas o título HTML e as informações das características de comprimento em cada item.
200 OK
{ "kind": "demo", "items": [{ "title": "First title", "characteristics": { "length": "short" } }, { "title": "Second title", "characteristics": { "length": "long" } }, ... ] }
Tenha em atenção que a resposta é um objeto JSON que inclui apenas os campos selecionados e os respetivos objetos principais circundantes.
Os detalhes sobre como formatar o parâmetro fields
são abordados a seguir, seguidos de mais detalhes sobre o que é exatamente devolvido na resposta.
Resumo da sintaxe do parâmetro fields
O formato do valor do parâmetro de pedido fields
baseia-se vagamente na sintaxe XPath. A sintaxe suportada é resumida abaixo e são fornecidos exemplos adicionais na secção seguinte.
- Use uma lista separada por vírgulas para selecionar vários campos.
- Use
a/b
para selecionar um campob
aninhado no campoa
; usea/b/c
para selecionar um campoc
aninhado emb
.
Exceção: para respostas da API que usam wrappers "data", em que a resposta está aninhada num objeto
data
com o aspeto dedata: { ... }
, não inclua "data
" na especificaçãofields
. A inclusão do objeto de dados com uma especificação de campos comodata/a/b
causa um erro. Em alternativa, use apenas uma especificaçãofields
, comoa/b
. - Use um subseletor para pedir um conjunto de subcampos específicos de matrizes ou objetos colocando expressões entre parênteses "
( )
".Por exemplo:
fields=items(id,author/email)
devolve apenas o ID do artigo e o email do autor para cada elemento na matriz de artigos. Também pode especificar um único subcampo, em quefields=items(id)
é equivalente afields=items/id
. - Se necessário, use carateres universais nas seleções de campos.
Por exemplo:
fields=items/pagemap/*
seleciona todos os objetos num mapa de páginas.
Mais exemplos de utilização do parâmetro fields
Os exemplos abaixo incluem descrições de como o valor do parâmetro fields
afeta a resposta.
Nota: tal como acontece com todos os valores dos parâmetros de consulta, o valor do parâmetro fields
tem de ser codificado por URL. Para uma melhor legibilidade, os exemplos neste documento omitem a codificação.
- Identifique os campos que quer que sejam devolvidos ou faça seleções de campos.
- O valor do parâmetro de pedido
fields
é uma lista de campos separados por vírgulas, e cada campo é especificado relativamente à raiz da resposta. Assim, se estiver a realizar uma operação de list, a resposta é uma coleção e, geralmente, inclui uma matriz de recursos. Se estiver a realizar uma operação que devolve um único recurso, os campos são especificados relativamente a esse recurso. Se o campo que selecionar for (ou fizer parte de) uma matriz, o servidor devolve a parte selecionada de todos os elementos na matriz.
Seguem-se alguns exemplos ao nível da recolha:
Exemplos Efeito items
Devolve todos os elementos na matriz de itens, incluindo todos os campos em cada elemento, mas nenhum outro campo. etag,items
Devolve o campo etag
e todos os elementos na matriz de artigos.items/title
Devolve apenas o campo title
para todos os elementos na matriz de artigos.
Sempre que é devolvido um campo aninhado, a resposta inclui os objetos principais circundantes. Os campos principais não incluem outros campos secundários, a menos que também sejam selecionados explicitamente.context/facets/label
Devolve apenas o campo label
para todos os membros da matrizfacets
, que está aninhada no objetocontext
.items/pagemap/*/title
Para cada elemento na matriz de itens, devolve apenas o campo title
(se presente) de todos os objetos que são filhos depagemap
.
Seguem-se alguns exemplos ao nível do recurso:
Exemplos Efeito title
Devolve o campo title
do recurso pedido.author/uri
Devolve o subcampo uri
do objetoauthor
no recurso pedido.links/*/href
Devolve o campo href
de todos os objetos que são filhos delinks
. - Pedir apenas partes de campos específicos através de subseleções.
- Por predefinição, se o seu pedido especificar campos específicos, o servidor devolve os objetos ou os elementos da matriz na sua totalidade. Pode especificar uma resposta que inclua apenas determinados subcampos. Pode fazê-lo através da sintaxe de subseleção "
( )
", como no exemplo abaixo.Exemplo Efeito items(title,author/uri)
Devolve apenas os valores de title
euri
do autor para cada elemento na matriz de artigos.
Processamento de respostas parciais
Depois de um servidor processar um pedido válido que inclua o parâmetro de consulta fields
, envia um código de estado HTTP 200 OK
, juntamente com os dados pedidos. Se o parâmetro de consulta fields
tiver um erro ou for inválido de outra forma, o servidor devolve um código de estado HTTP 400 Bad Request
, juntamente com uma mensagem de erro a indicar ao utilizador o que estava errado com a seleção de campos (por exemplo, "Invalid field selection a/b"
).
Segue-se o exemplo de resposta parcial apresentado na secção introdutória acima. O pedido usa o parâmetro fields
para especificar os campos a devolver.
https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)
A resposta parcial tem o seguinte aspeto:
200 OK
{ "kind": "demo", "items": [{ "title": "First title", "characteristics": { "length": "short" } }, { "title": "Second title", "characteristics": { "length": "long" } }, ... ] }
Nota: para APIs que suportam parâmetros de consulta para paginação de dados (por exemplo, maxResults
e nextPageToken
), use esses parâmetros para reduzir os resultados de cada consulta a um tamanho gerível. Caso contrário, os ganhos de desempenho possíveis com a resposta parcial podem não ser realizados.
Patch (atualização parcial)
Também pode evitar o envio de dados desnecessários quando modifica recursos. Para enviar dados atualizados apenas para os campos específicos que está a alterar, use o verbo HTTP PATCH
. A semântica de patch descrita neste documento é diferente (e mais simples) da que era para a implementação GData mais antiga da atualização parcial.
O breve exemplo abaixo mostra como a utilização do patch minimiza os dados que tem de enviar para fazer uma pequena atualização.
Exemplo
Este exemplo mostra um pedido de patch simples para atualizar apenas o título de um recurso de API "Demo" genérico (fictício). O recurso também tem um comentário, um conjunto de caraterísticas, o estado e muitos outros campos, mas este pedido envia apenas o campo title
, uma vez que é o único campo que está a ser modificado:
PATCH https://www.googleapis.com/demo/v1/324 Authorization: Bearer your_auth_token Content-Type: application/json { "title": "New title" }
Resposta:
200 OK
{ "title": "New title", "comment": "First comment.", "characteristics": { "length": "short", "accuracy": "high", "followers": ["Jo", "Will"], }, "status": "active", ... }
O servidor devolve um código de estado 200 OK
, juntamente com a representação completa do recurso atualizado. Uma vez que apenas o campo title
foi incluído no pedido de patch, esse é o único valor diferente do anterior.
Nota: se usar o parâmetro partial response fields
em combinação com patch, pode aumentar ainda mais a eficiência dos seus pedidos de atualização. Um pedido de patch apenas reduz o tamanho do pedido. Uma resposta parcial reduz o tamanho da resposta. Assim, para reduzir a quantidade de dados enviados em ambas as direções, use um pedido de patch com o parâmetro fields
.
Semântica de um pedido de patch
O corpo do pedido patch inclui apenas os campos de recursos que quer modificar. Quando especifica um campo, tem de incluir todos os objetos principais circundantes, tal como os principais circundantes são devolvidos com uma resposta parcial. Os dados modificados que envia são unidos aos dados do objeto principal, se existir.
- Adicionar: para adicionar um campo que ainda não existe, especifique o novo campo e o respetivo valor.
- Modificar: para alterar o valor de um campo existente, especifique o campo e defina-o para o novo valor.
- Eliminar: para eliminar um campo, especifique o campo e defina-o como
null
. Por exemplo,"comment": null
. Também pode eliminar um objeto completo (se for mutável) definindo-o comonull
. Se estiver a usar a biblioteca cliente da API Java, useData.NULL_STRING
em alternativa. Para detalhes, consulte JSON nulo.
Nota acerca das matrizes: os pedidos PATCH que contêm matrizes substituem a matriz existente pela que fornecer. Não pode modificar, adicionar nem eliminar itens numa matriz de forma gradual.
Usar o patch num ciclo de leitura-modificação-escrita
Pode ser uma prática útil começar por obter uma resposta parcial com os dados que quer modificar. Isto é especialmente importante para recursos que usam ETags, uma vez que tem de fornecer o valor ETag atual no cabeçalho HTTP If-Match
para atualizar o recurso com êxito. Depois de receber os dados, pode modificar os valores que quer alterar e enviar a representação parcial modificada de volta com um pedido de patch. Segue-se um exemplo que pressupõe que o recurso de demonstração usa ETags:
GET https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics Authorization: Bearer your_auth_token
Esta é a resposta parcial:
200 OK
{ "etag": "ETagString" "title": "New title" "comment": "First comment.", "characteristics": { "length": "short", "level": "5", "followers": ["Jo", "Will"], } }
O seguinte pedido PATCH baseia-se nessa resposta. Conforme mostrado abaixo, também usa o parâmetro fields
para limitar os dados devolvidos na resposta de patch:
PATCH https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics Authorization: Bearer your_auth_token Content-Type: application/json If-Match: "ETagString"
{ "etag": "ETagString" "title": "", /* Clear the value of the title by setting it to the empty string. */ "comment": null, /* Delete the comment by replacing its value with null. */ "characteristics": { "length": "short", "level": "10", /* Modify the level value. */ "followers": ["Jo", "Liz"], /* Replace the followers array to delete Will and add Liz. */ "accuracy": "high" /* Add a new characteristic. */ }, }
O servidor responde com um código de estado HTTP 200 OK e a representação parcial do recurso atualizado:
200 OK
{ "etag": "newETagString" "title": "", /* Title is cleared; deleted comment field is missing. */ "characteristics": { "length": "short", "level": "10", /* Value is updated.*/ "followers": ["Jo" "Liz"], /* New follower Liz is present; deleted Will is missing. */ "accuracy": "high" /* New characteristic is present. */ } }
Construir um pedido de patch diretamente
Para alguns pedidos de patch, tem de baseá-los nos dados que obteve anteriormente. Por exemplo, se quiser adicionar um item a uma matriz e não quiser perder nenhum dos elementos da matriz existentes, tem de obter primeiro os dados existentes. Da mesma forma, se uma API usar ETags, tem de enviar o valor ETag anterior com o seu pedido para atualizar o recurso com êxito.
Nota: pode usar um cabeçalho HTTP "If-Match: *"
para forçar a aplicação de um patch quando as ETags estão em utilização. Se o fizer, não precisa de fazer a leitura antes da escrita.
No entanto, noutras situações, pode construir o pedido de patch diretamente, sem obter primeiro os dados existentes. Por exemplo, pode configurar facilmente um pedido de patch que atualize um campo para um novo valor ou adicione um novo campo. Vejamos um exemplo:
PATCH https://www.googleapis.com/demo/v1/324?fields=comment,characteristics Authorization: Bearer your_auth_token Content-Type: application/json { "comment": "A new comment", "characteristics": { "volume": "loud", "accuracy": null } }
Com este pedido, se o campo de comentário tiver um valor existente, o novo valor substitui-o. Caso contrário, é definido como o novo valor. Da mesma forma, se existir uma característica de volume, o respetivo valor é substituído. Caso contrário, é criada. O campo de precisão, se estiver definido, é removido.
Processar a resposta a uma correção
Após o processamento de um pedido de patch válido, a API devolve um código de resposta HTTP 200 OK
juntamente com a representação completa do recurso modificado. Se as ETags forem usadas pela API, o servidor atualiza os valores das ETags quando processa com êxito um pedido de patch, tal como acontece com PUT
.
O pedido de patch devolve a representação completa do recurso, a menos que use o parâmetro fields
para reduzir a quantidade de dados que devolve.
Se um pedido de patch resultar num novo estado de recurso sintática ou semanticamente inválido, o servidor devolve um código de estado HTTP 400 Bad Request
ou 422 Unprocessable Entity
, e o estado do recurso permanece inalterado. Por exemplo, se tentar eliminar o valor de um campo obrigatório, o servidor devolve um erro.
Notação alternativa quando o verbo HTTP PATCH não é suportado
Se a sua firewall não permitir pedidos PATCH
HTTP, faça um pedido POST
HTTP e defina o cabeçalho de substituição como PATCH
, conforme mostrado abaixo:
POST https://www.googleapis.com/... X-HTTP-Method-Override: PATCH ...
Diferença entre patch e atualização
Na prática, quando envia dados para um pedido de atualização que usa o verbo HTTP PUT
, só precisa de enviar os campos obrigatórios ou opcionais. Se enviar valores para campos definidos pelo servidor, estes são ignorados. Embora possa parecer outra forma de fazer uma atualização parcial, esta abordagem tem algumas limitações. Com as atualizações que usam o verbo HTTP PUT
, o pedido falha se não fornecer os parâmetros obrigatórios e limpa os dados definidos anteriormente se não fornecer os parâmetros opcionais.
Por este motivo, é muito mais seguro usar uma correção. Só fornece dados para os campos que quer alterar. Os campos que omitir não são limpos. A única exceção a esta regra ocorre com elementos ou matrizes repetidos: se os omitir todos, permanecem tal como estão; se fornecer algum deles, o conjunto completo é substituído pelo conjunto que fornecer.