在varchar列中存储snappy编码数据

时间:2012-07-27 14:21:10

标签: java database encoding compression varchar

我使用Snappy-java编码JSON数据,我想将结果存储在varchar列的数据库中。
该数据库是具有ISO-8859-1编码的oracle数据库 我在插入数据时遇到编码问题。似乎Oracle无法识别某些字符。

我在插入之前通过对压缩数据使用Base64编码找到了解决方法。然后我就可以检索它了。)

问题在于Base64编码增加了我当时存储的数据的长度,从而减少了Snappy所带来的节省......

所以我的问题是:如何在不在Base64中对其进行编码的情况下存储该数据? 我想使用varchar的原因是因为我希望能够使用oracle索引访问表而无需访问表(性能肯定是个问题)。

我也尝试过其他压缩算法,但它们似乎都有同样的问题。 我也看了yEnc,但我找不到任何java编码器。此外,我不确定我是否理解yEnc列出的所有问题,所以我有点不情愿使用它。

非常感谢您的帮助!

4 个答案:

答案 0 :(得分:1)

您正在压缩数据。压缩的结果几乎是总是二进制数据,而不是文本......我假设Snappy也是如此。

要准确地将二进制数据存储为文本,您使用类似Base64的内容。你没有字符 - 你有字节。

要有效地存储压缩文本,您应该将数据库列更改为面向二进制的类型而不是面向文本的类型(基本上是BLOB而不是CLOB)。

答案 1 :(得分:0)

有问题的char可能是oracle db的控件char。在任何情况下,您可能需要考虑将数据保存为' text'或者一个' clob'而不是作为varchar。

除此之外,在插入数据之前,您可能需要使用zip或Huffman类型的压缩器。你玩过类似的东西:How to compress a String in Java?

答案 2 :(得分:0)

Jon Skeet简单地使用二进制字段而不是文本字段的答案是明显的解决方案。

如果您确实需要使用文本字段,请先试验一下您可以在其中存储的内容。我的猜测是你可以存储除零字节之外的任何字节,后者用于终止可变长度字符串。您可以简单地存储一个长度为255的字符串,其中包含字节0x01..0xff,然后检索它以查看是否正好返回这些字节。如果这样做,那么唯一要避免的字节是零。

如果我的理论是正确的,那么有几种简单的方法可以通过有限的数据扩展来消除零。最简单的是当你到0时,发送一个0x80,0x01。当你得到一个0x80时,发送一个0x80,0x81。然后在解码时,如果看到0x80,则只需获取下一个字节并减去1.这将使流平均扩展不到1%(0.78%)。

如果绝对最小化扩展问题,您可以使用更复杂的编码方案做得更好。

答案 3 :(得分:0)

谢谢大家的帮助!

我终于找到了解决方法。 因为我存储字节而不是字符,所以我将使用BLOB来存储数据。 BLOB的问题在于它无法编入索引。 另一种方法是使用RAW型色谱柱。它存储字节并且是可索引的。不幸的是它太小(2000字节)。 因此,我的答案包括将数据存储在BLOB中,并通过两种RAW类型的索引访问它,因为数据永远不会超过4000字节。

索引如下所示:

CREATE INDEX blob_to_raw_prd_ix 
ON product (product_id, 
            substr_dt(blob_summary,2000,1), 
            substr_dt(blob_summary,2000,2001));

其中

  • blob_summary是我将数据存储在
  • 中的BLOB列
  • substr_dt是用户定义的确定性函数(以下定义)

    创建或替换函数substr_dt(str BLOB,buffer_size int,offset int)RETURN RAW 决定性的 开始     RETURN dbms_lob.substr(str,buffer_size,offset); END;

要访问数据,我只需要使用别名查询product_id和字段,例如

SELECT     /*+ index(blob_to_raw_prd_ix) */ product_id, 
                                            substr_dt(blob_summary, 2000, 1) AS summary1, 
                                            substr_dt(blob_summary, 2000, 2001) AS summary2
FROM       product
WHERE      (product_id = ?);

在这种情况下,summary_1表示blob的前2000个字节,summary2表示最后2000个字节。 在两个数组summary1和summary2上使用连接,我得到了blob的内容。

适用于Jdbc,但我无法使用Hibernate(尚未)。 它不是最好的解决方案,因为数据在解释之前需要重新处理。但是,它解决了数据访问问题,而没有编码空间开销。