Como o Google armazena suas tabelas do Big Query e como isso afeta você

Publicados: 2016-02-24

Esta é uma instalação de palestra técnica de nosso blog, trazida a você pelo extraordinário desenvolvedor, Adam Knox.

Embora o Big Query use uma sintaxe muito semelhante ao SQL, na verdade ele leva um tato significativamente diferente para uma solução para processar grandes quantidades de dados. O Big Query tem a tendência de aplicar força bruta e, na verdade, não usa índices, portanto, muitos dados significam muitos processadores e tempo de processamento. Para conseguir isso, o Google optou por uma maneira diferente de armazenar dados que podem afetar a maneira como você projeta suas consultas.

Formato de arquivo

Quando uma tabela é criada, o Google usa seu formato ColumnIO para armazenar seus dados. Cada coluna é armazenada como um arquivo separado, com exceção dos campos repetidos. Se você tiver uma tabela com as colunas: nome (string), phoneNumbers (inteiro repetido); o nome será armazenado em uma única linha com os outros nomes e todos os números de telefone associados a esse nome serão armazenados em uma única linha com os números de telefone. As colunas também podem ser divididas se ficarem muito grandes, mas isso não terá impacto no fluxo de trabalho.

Saber disso fornece a capacidade de executar consultas mais rápidas ao não processar colunas com as quais você realmente não se preocupa e, em alguns casos, torna possível até mesmo antes impossibilitar a execução de consultas. As consultas também podem se tornar mais baratas, pois o sistema cobra pela quantidade de dados processados ​​e, se uma coluna não for incluída na consulta, esses dados não serão processados.

Armazenamento de arquivo

Se você criou uma tabela, pode se sentir razoavelmente seguro de que ela não vai a lugar nenhum, porque, uma vez que seus arquivos são criados, eles são armazenados em três datacenters diferentes e até mesmo em três locais diferentes dentro de cada datacenter. Como o Big Query coloca problemas nos processadores, os dados precisam estar prontamente acessíveis. A advertência para isso são conjuntos de dados temporários. Há uma opção para especificar um tempo de expiração para tabelas em um conjunto de dados e as tabelas desaparecerão quando forem mais antigas do que esta data de expiração.

Hierarquia da Tabela

Um projeto tem a capacidade de armazenar conjuntos de dados, cada um podendo conter tabelas. O comando completo para acessar uma tabela na sintaxe do Big Query é [projectname:datasetname.tablename] , no entanto, pode ser abreviado para dataset.tablename se você estiver acessando a tabela do projeto em que está trabalhando atualmente.

Dividir os dados relacionados em tabelas separadas (por exemplo: por data ou após a ocorrência de um evento específico) pode ser benéfico para fazer consultas mais sustentáveis, uma vez que as consultas geralmente são executadas em todas as linhas de uma tabela. Isso significa que você pode querer olhar para várias tabelas, então há algo chamado de meta tabela oculta em cada conjunto de dados que pode ser acessado em [projectname:datasetname.__TABLES__] e contém informações sobre cada tabela no conjunto de dados e pode ser usado para agregar tabelas para questionando.

O comando TABLE_QUERY é um comando que permite que várias tabelas semelhantes sejam agregadas antes de executar uma consulta no agregado, e qualquer coluna em __TABLES__ pode ser usada para formar esse agregado. Por exemplo, se eu quiser uma ideia dos tempos de resposta desde 1º de janeiro de 2016 para um projeto, poderia executar a seguinte consulta que mostra os tempos de resposta mínimo, médio e máximo:

 SELECT QUANTILES((protoPayload.endTime - protoPayload.startTime), 3) AS responseTimeBucketsInMilliseconds FROM (TABLE_QUERY(appengine_logs, "table_id CONTAINS 'appengine_googleapis_com_request_log' AND creation_time > 1451606400000"))

Uma vez que apenas duas colunas, cada uma contendo inteiros, são usadas, esta ainda é uma consulta razoavelmente barata ($ 0,0003), embora esteja acessando 28+ que me disseram que tem 1,857 TB pela consulta abaixo e custaria cerca de 9 $ para acessar todos os campos de .

 SELECT SUM(size_bytes)/1000000000 FROM [repcore-prod:appengine_logs.__TABLES__] WHERE table_id CONTAINS 'appengine_googleapis_com_request_log' AND creation_time > 1451606400000

Atualizando arquivos

O Big Query é ótimo quando se trata de registrar mudanças e analisar essas mudanças, porque você pode transmitir novas linhas para uma tabela. É, no entanto, um péssimo dispositivo de armazenamento de dados para pesquisas rápidas e frequentes de linhas específicas devido à falta de índices, e também não é ótimo para armazenar representações singulares de objetos que você espera alterar porque as linhas em uma tabela não podem ser modificadas ou removidas .

Mesas de Divisão

Em algumas situações, até mesmo acessar uma única coluna é demais para lidar com o Big Query. Apresento a você a seguinte consulta inutilizável que retorna IDs de lista por ordem de data de criação da lista:

 SELECT lid FROM [repcore-prod:datastore.LIS] ORDER BY ct

Tecnicamente, isso recentemente se tornou possível, mas não para as pessoas da Vendasta, porque isso requer habilitar um nível de faturamento mais alto. Como não há índices pré-encomendados, ele está processando uma pequena quantidade de dados muito intensamente, portanto, neste caso, eles estão cobrando pelo processamento. A alteração da camada de faturamento pode ser feita em consultas interativas na IU do Big Query marcando "permitir ilimitado" (se ativado) no botão "opções".

Supondo que sua consulta seja o mais eficiente possível, existem algumas abordagens restantes para reduzir os tamanhos das tabelas para contornar esses tipos de limites rígidos. O primeiro são os decoradores de tempo de mesa e o segundo é com um hash.

Você pode aprender mais sobre decoradores de mesa aqui. Ao contrário de filtrar os resultados usando comandos como LIMIT/WHERE/HAVING/OMIT , os decoradores de tabela realmente diminuirão o custo de consultar uma tabela porque nem mesmo acessarão os dados fora do intervalo determinado. Infelizmente, esse método é quase inútil em Vendasta porque mesmo para tabelas como o ListingHistoryModel para o qual realmente transmitimos, ainda descartamos a tabela inteira e a substituímos todos os dias por uma réplica se for do NDB, o que significa que os decoradores de tempo de tabela só funcionarão no ListingHistoryModel se você só se preocupa com as entradas do dia atual.

Observar o registro é o único lugar em que eles podem ser bastante úteis na Vendasta. Devido ao tamanho do conteúdo real do log, os limites de computação e memória são fáceis de atingir, e consultar até mesmo apenas a coluna do conteúdo do log é caro. Com os logs, normalmente também se preocupa apenas com pontos específicos no tempo, que é exatamente o que o decorador de tempo ajuda.

Resultados da Consulta

Cada vez que você executa uma consulta, ela cria uma nova tabela e, às vezes, cria tabelas ocultas desconhecidas nos bastidores. Se desejar, você pode dar um nome à tabela de resultados para mantê-la ou deixá-la ficar com o nome que o Google deu a ela e deixá-la desaparecer após um dia. Se você já se deparou com uma “resposta muito grande para retornar”, é porque eles estão protegendo você de você mesmo. É fácil criar tabelas enormes (especialmente com junções cruzadas). Se isso acontecer e você esperava que acontecesse, será necessário nomear a tabela e habilitar a opção “Permitir resultados grandes”. Se você repetir uma consulta que não possui novas linhas transmitidas para ela, você apenas obterá os resultados armazenados em cache se eles ainda estiverem por perto.