Arquivos QVD - o que há dentro, parte 2

No primeiro artigo sobre a estrutura do arquivo QVD, descrevi a estrutura geral e me refiro aos metadados com detalhes suficientes. Neste artigo, descreverei o formato para armazenar informações sobre colunas e compartilharei minha experiência na interpretação desses dados.


Então (lembre-se), um arquivo QVD corresponde a uma tabela relacional, que, como você sabe, consiste em linhas. Cada linha da tabela, por sua vez, consiste em colunas (ou campos) e as linhas têm a mesma estrutura, que pode ser descrita, por exemplo, pelo operador SQL (criar tabela).


Em um arquivo QVD, uma tabela é armazenada como duas partes indiretamente relacionadas:


As tabelas de caracteres (meu termo) contêm valores exclusivos para cada coluna na tabela de origem. É sobre eles que discutiremos abaixo.


A tabela de linhas contém as linhas da tabela de origem, cada linha armazena os índices dos valores da coluna (campo) da linha na tabela de símbolos correspondente. Discutirei a tabela de linhas com mais detalhes na terceira parte desta série.


No exemplo do nosso prato (lembre-se - da primeira parte)


SET NULLINTERPRET =<sym>; tab1: LOAD * INLINE [ ID, NAME 123.12,"Pete" 124,12/31/2018 -2,"Vasya" 1,"John" <sym>,"None" ]; 

Nesta placa:


  • 5 linhas
  • o campo "ID" possui 4 valores exclusivos (NULL não é considerado um valor, com mais detalhes na terceira parte)
  • o campo "NAME" possui 5 valores únicos
  • a primeira linha da tabela de linhas conterá os índices 0 e 0, correspondentes aos valores 123.12 e "Pete", respectivamente

Ocasiões especiais


Como regra, tabelas de símbolos são criadas para todos os campos da tabela no arquivo QVD. Mas existem nuances.


Se o campo tiver um valor, esse valor geralmente será armazenado na tabela de símbolos (nesse caso, a tabela de símbolos conterá um registro). E na tabela de linhas o campo estará ausente (pois é claro qual deve ser o valor desse campo em cada linha ...)


Se o campo não tiver valores (sempre contém NULL), nenhuma tabela de símbolos será criada nele.


Esses casos especiais serão descritos na terceira parte, quando chegarmos às linhas e ao algoritmo para sua recreação.


Armazenando tabelas de caracteres em um arquivo


Cada tabela de símbolos é armazenada em um arquivo QVD como um bloco binário, seu deslocamento (relativo ao início do bloco binário) está contido no campo Deslocamento da seção de metadados desse campo, o comprimento (em bytes) está no campo Comprimento dos metadados.


Assim, a primeira tabela de caracteres sempre terá um deslocamento de 0.


As tabelas de símbolos seguem uma após a outra e não são separadas uma da outra.


Estrutura da tabela de caracteres


A tabela de símbolos contém valores de campo que se seguem sem separadores, cada valor é representado da seguinte maneira:


  • um byte codifica o tipo de campo (descreverei abaixo)
  • então vem o valor binário opcional (depende do tipo de campo)
  • seguido por um valor opcional da sequência (depende do tipo de campo)

As strings são armazenadas "como estão" (na codificação especificada nos metadados), a string termina com um byte zero. A cadeia pode ter comprimento zero, ou seja, consistem apenas em byte zero.


Os valores binários são armazenados de acordo com as regras da arquitetura em que o arquivo QVD foi gerado (pela minha experiência, você pode simplesmente lê-los como valores binários com o objetivo de "endian").


Tipos de campo


Toda a variedade de tipos de dados QVD reuniu três


  • (1) inteiro (4 bytes)
  • (2) ponto flutuante (8 bytes)
  • (4) linha que termina com zero

Existem também tipos combinados


  • (5) um número inteiro seguido por sua representação em cadeia (4 bytes mais uma cadeia com um byte zero)
  • (6) um número de ponto flutuante seguido por sua representação de cadeia (8 bytes mais uma cadeia com um byte zero)

Entre parênteses, forneci os valores numéricos dos "tipos" (o primeiro byte do valor do campo na tabela de símbolos).


Uma mente indagadora perguntará: "onde estão os três?" Isso não é para mim, também tenho muitas perguntas, a partir dos comentários aqui, como o herói de Khabensky disse no famoso filme "Vou me abster ...".


Em geral, isso é tudo, não é difícil - certo?


Duas observações práticas não muito agradáveis


Um e o mesmo campo pode ter valores de tipos diferentes na tabela de símbolos (número inteiro, flutuante e seqüências de caracteres). Eu mesmo não acreditei até realizar uma série de experimentos ... A única coisa que pode ser "garantida" (com a ressalva da primeira parte - nada pode ser garantido) - não pode haver mistura de "número" e "número com uma string" (um ou outro ) Isso é importante, uma mente investigadora entenderá :-).


Os valores dos campos não numéricos (não os tipos 1 e 2 na notação acima) devem ser lidos em uma linha - é impossível se posicionar no número do campo N ... É compreensível, mas ineficiente (em termos de processamento).


Considere novamente nosso rótulo acima, a tabela de caracteres do campo ID será parecida com esta (escrevo byte / caractere):


  • número 6 (tipo) + 8 bytes (valor flutuante 123.12) + 7 bytes (string "123.12" com zero byte)
  • número 5 (tipo) + 4 bytes (valor inteiro 124) + 4 bytes (string "124" com zero byte)
  • número 5 (tipo) + 4 bytes (número inteiro -2) + 3 bytes (sequência "-2" com zero byte)
  • número 5 (tipo) + 4 bytes (número inteiro 1) + 2 bytes (sequência "1" com zero byte)

Um total de 40 bytes (consulte a parte anterior - metadados, o valor do atributo Length para o campo ID).


Da prática


A tarefa prática (uma das), como já escrevi, era recriar a tabela usando o arquivo QVD. Do exposto acima, segue-se (pelo menos - deve-se tentar :-)) que, a partir da descrição da coluna (metadados mais dados), é impossível determinar sem ambiguidade o tipo de campo (um que, por exemplo, escreva na "tabela de criação ...") .


Como mencionei na primeira parte - 90% dos campos têm tipo DESCONHECIDO nos metadados, as tags também não permitem definir exclusivamente o tipo de campo (não carregarei o leitor com os detalhes - acredite em mim) ...


Como ser


No meu trabalho, segui o caminho estatístico - analiso uma certa porcentagem dos valores das colunas e, com base nos resultados, concluo - que tipo atribuir a ela. A precisão é bastante satisfatória, o problema é que você precisa analisar (no caso geral) todos os dados ... Na minha prática, me limitei aos primeiros 5 a 10% dos valores de campo.


Se terminarmos com os tipos de dados, uma mente indagadora fará uma pergunta razoável - a "tabela de criação" mencionada implica muito mais tipos de dados ...


Eu direi o seguinte: nos arquivos processados, não foram encontrados outros tipos de dados além dos listados acima. Os arquivos correspondiam a tabelas muito reais de bancos de dados reais e continham todo o espectro de tipos de dados (por exemplo, eu recebi blobs ... Por que eles estão no QVD ??? Seria melhor escrever comentários).


Provavelmente, para completar a imagem com tipos de dados, você precisa explicar sobre datas e carimbos de data / hora (outros tipos são uma questão de duração).


As datas são apresentadas no QVD como um número inteiro - o número de dias desde o início da era (era do clique). Os especialistas em QlikView / QlikSense lhe dirão facilmente quando foi iniciado (embora fosse 30 de dezembro de 1899, não pergunte o porquê).


Os registros de data e hora no QVD são representados por um número de ponto flutuante que contém a data descrita acima e o horário na parte fracionária (onde .0 corresponde ao horário "00:00:00" e .999999 corresponde ao horário "23:59:59" - consulte mais detalhadamente, por exemplo, aqui ).


Ainda não segui essa direção - minhas tabelas recriadas do QVD contêm tipos inteiro e flutuante para campos como "date" e "datetime". Como alternativa, você pode usar a representação de sequência - para campos desse tipo, uma representação combinada é sempre usada (tipos 5 e 6).


O último (sobre a prática) - ao ler arquivos grandes, é lógico criar índices para campos de string, o que eu fiz. Isso reduz significativamente o tempo de processamento nos casos em que o tamanho da tabela de símbolos é muito menor que o número de linhas (ou seja, um valor ocorre mais de uma vez no campo da tabela original).


Resumir


Neste artigo, examinamos o armazenamento de valores únicos de campos (colunas), vimos que as colunas são armazenadas como uma sequência de valores únicos, percebemos que os tipos de dados são misturados e existem apenas três tipos (inteiro, flutuante e linha).


Em seguida, precisamos nos familiarizar com o armazenamento das strings - a terceira e última parte de uma série de artigos sobre a estrutura QVD será dedicada a isso.

Source: https://habr.com/ru/post/pt455940/


All Articles