QVD文件-内部内容,第2部分

在有关QVD文件结构的第一篇文章中 ,我详细描述了一般结构并详细介绍了元数据。 在本文中,我将描述用于存储有关列的信息的格式,并分享我在解释此数据时的经验。


因此(记住)QVD文件对应于一个关系表,该表由行组成。 该表的每一行依次由列(或字段)组成,并且这些行具有相同的结构,例如,可以通过SQL运算符(创建表)进行描述。


在QVD文件中,表存储为两个间接相关的部分:


字符表 (我的术语)包含源表中每一列的唯一值。 关于它们,我们将在下面讨论。


行表包含源表的行,每行存储相应符号表中该行的列(字段)值的索引。 我将在本系列的第三部分中更详细地讨论行表。


以我们的盘子为例(请记住-从第一部分开始)


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

在此板中:


  • 5线
  • “ ID”字段具有4个唯一值(不认为NULL为值,在第三部分中对此有更详细的说明)
  • “ NAME”字段具有5个唯一值
  • 行表的第一行将包含索引0和0,分别对应于值123.12和“ Pete”

特殊场合


通常,将为QVD文件中的所有表字段创建符号表。 但是有细微差别。


如果该字段具有一个值,则该值通常存储在符号表中(在这种情况下,符号表将包含一个记录)。 并且在行表中该字段将不存在(因此很明显此字段的值应在每一行中...)


如果该字段根本没有任何值(始终包含NULL),则不会在其上创建任何符号表。


这些特殊情况将在第三部分中进行描述,当我们到达线和它们的重新创建算法时。


将字符表存储在文件中


每个符号表都作为二进制块存储在QVD文件中,其偏移量(相对于二进制块的开头)包含在此字段的元数据部分的“偏移量”字段中,长度(以字节为单位)位于元数据的“长度”字段中。


因此,第一个字符表将始终具有0的偏移量。


符号表一个接一个,并且没有以任何方式彼此分开。


字符表结构


符号表包含彼此不带分隔符的字段值,每个值表示如下:


  • 一个字节编码字段的类型(我将在下面描述)
  • 然后是可选的二进制值(取决于字段的类型)
  • 后面跟一个可选的字符串值(取决于字段的类型)

字符串按“原样”存储(使用元数据中指定的编码),字符串以零字节结尾。 该字符串的长度可以为零,即 仅包含零字节。


二进制值是根据生成QVD文件的体系结构规则存储的(根据我的经验,您可以着眼于“ endian”将其简单地读取为二进制值)。


栏位类型


QVD的各种数据类型结合了三种基本


  • (1)整数(4个字节)
  • (2)浮点数(8个字节)
  • (4)以零结尾的行

也有组合类型


  • (5)整数及其后的字符串表示形式(4个字节加上一个零字节的字符串)
  • (6)浮点数,其后为字符串表示形式(8个字节加上一个零字节字符串)

在括号中,我给出了“类型”的数值(符号​​表中字段值的第一个字节)。


一个有疑问的人会问:“三个在哪里?” 这不是我一个人,从这里的评论中我也有很多问题,正如哈本斯基的主人公在著名电影《我不会……》中所说。


总的来说,这并不困难-对吗?


两个不太愉快的实践观察


同一字段在符号表中可以具有不同类型的值(整数,浮点和字符串)。 在进行一系列实验之前,我本人不相信这一点……唯一可以“保证”的事情(第一部分的警告-不能保证)-不能有“数字”和“带字符串的数字”(一个或另一个)的混合) 这很重要,一个有查询能力的人会明白:-)。


必须连续读取非数字字段的值(上面表示法中不是1和2型)-无法将自己放在字段号N上……这是可以理解的,但是效率很低(在处理方面)。


再次考虑上面的标签,ID字段的字符表将如下所示(我写字节/字符):


  • 数字6(类型)+ 8个字节(浮点值123.12)+ 7个字节(零字节的字符串“ 123.12”)
  • 数字5(类型)+ 4字节(整数值124)+ 4字节(字符串“ 124”,零字节)
  • 数字5(类型)+ 4个字节(整数-2)+ 3个字节(带零字节的字符串“ -2”)
  • 数字5(类型)+ 4字节(整数1)+ 2字节(字符串“ 1”,零字节)

总共40个字节(请参阅上一部分-元数据,ID字段的Length属性的值)。


从实践


正如我已经写过的,实际的任务(其中之一)是使用QVD文件重新创建表。 从以上可以看出(至少-应该遵循,我尝试过:-)),从列的描述(元数据加数据)不可能明确确定字段的类型(例如,写在“ create table ...”中的字段)。 。


正如我在第一部分中提到的-90%的字段在元数据中具有UNKNOWN类型,标签也不允许您唯一地设置字段类型(我不会向读者加载详细信息-相信我)...


如何成为


在我的工作中,我沿着统计路径走-我分析了一定百分比的列值,并根据结果得出结论-为其分配哪种类型。 准确性非常令人满意,麻烦的是您需要分析(通常情况下)所有数据。在我的实践中,我将自己限制在字段值的前5-10%。


如果我们以数据类型为结尾,那么一个会问的人会问一个合理的问题-提到的“创建表”意味着更多的数据类型...


我会这样说:在已处理的文件中,除了上面列出的数据类型外,未找到其他数据类型。 这些文件对应于真实数据库的非常真实的表,并且包含整个数据类型(例如,我什至有Blob ...为什么它们出现在QVD中?最好写注释)。


可能要使数据类型完整,您需要说明日期和时间戳(其他类型取决于长度)。


日期以QVD的整数形式表示-从时代开始(点击时代)开始的天数。 QlikView / QlikSense专家会轻松告诉您启动的时间(尽管是1899年12月30日,请不要问为什么)。


QVD中的时间戳由包含日期的浮点数表示,如上所述,而小数部分中的时间(其中.0对应于时间“ 00:00:00”,。999999对应于时间“ 23:59:59”-请参见更详细的信息,例如, 此处 )。


我还没有深入研究这个方向-从QVD重新创建的表包含“日期”和“日期时间”等字段的整数和浮点类型。 或者,您可以使用字符串表示形式-对于此类型的字段,始终使用组合的表示形式(类型5和6)。


最后(关于实践)-读取大文件时,为字符串字段创建索引是合乎逻辑的,就像我所做的那样。 在符号表的大小远小于行数的情况下(即,一个值在原始表的字段中出现一次以上),这会大大减少处理时间。


总结一下


在本文中,我们检查了字段(列)的唯一值的存储,看到列被存储为唯一值的序列,意识到数据类型是混合的,并且只有三种类型(整数,浮点和行)。


接下来,我们需要熟悉字符串的存储方式-有关QVD结构的系列文章的第三篇也是最后一部分将专门讨论这一点。

Source: https://habr.com/ru/post/zh-CN455940/


All Articles