是否有一种类型或方式如何在二进制级别的oracle中存储数据。 我对表中的dml和pl / sql的操作感兴趣。
目前所有二进制元素都存储为varchar2(1000)='11111 ... 0000.1111',但操作和数据存储大小相当大,因此需要一些优化解决方案。如果此数据可以以二进制格式存储,则需要1000/8字节 (有> 700mln记录)
也许解决方案是使用某种java + oracle组合进行这些操作。
欢迎提出意见和建议。
答案 0 :(得分:8)
如果要存储最多4000个字节的二进制数据,请使用RAW数据类型。数据将存储为一串字节而不进行字符集转换。
使用UTL_RAW
包对RAWs
执行操作。
不推荐使用LONG RAW数据类型,当需要处理超过4000个字节的数据时,应切换到BLOB。
答案 1 :(得分:6)
请参阅Vincent Malgrat的回答:如果您想在Oracle中存储和处理二进制数据,那么RAW
数据类型就可以了。
(正如alegen的回答所暗示的那样,如果你的意图是存储和检索数据库中不需要“处理”的图像,视频,音频或压缩数据,但你只是“存储”它和“检索“它,然后BLOB
数据类型可能更合适;
(注意:RAW数据类型限制为4000字节,BLOB数据类型不是。出于性能原因,我宁愿将RAW用于更短(例如,200字节或更少)的值,我需要定期访问这些值。对于更长的值,很多查询没有引用二进制数据,我倾向于赞成BLOB
。(这都是由于RAW
和BLOB
的方式不同内部存储RAW
:内联存储与单独的块,拆分行,适合块的行数等。)
对于您描述的特定问题,根据您提供的信息,RAW
听起来就像是要走的路。您指定您有1000位的序列,但是它是否是常量或最大长度,或者您是否已将更长的二进制数据字符串分解为更适合列的可管理块,这一点都不清楚。 (如果你真的在使用一大块二进制数据,那么你真的想避免将它“切碎”成一堆小块,并将每一块存储在一个单独的行上。这样做会更有效率。将它们作为单个BLOB存储在一起,并将其作为简单流进行处理。
所有这些都是为了让您决定是否使用BLOB或RAW。
除此之外,关于转换从1和0的VARCHAR2表示(例如'00101010',将每个“位”的真实信息存储为单独的字符)转换为更高效存储的二进制表示形式,每个“需要一个字节存储的8位“真实信息......
Oracle VARCHAR2
数据类型将使您将8位存储到单个字节中。也就是说,RAW(125)将存储VARCHAR2(1000)的等效值,这将为每行节省875个字节(对于SBCS,如果使用DBCS,则为两倍以上)。这将显着降低存储要求,在块中获得更多行,并允许更好的性能。
要将当前存储为HEXTORAW
的数据转换为1和0的字符串,我不知道有任何内置函数可以做到这一点。但是滚动自己的函数将二进制字符串表示转换为十六进制字符串表示是相当简单的。之后,您可以使用内置RAW
功能转换为create or replace function binstr_to_hexstr
( as_binstr in varchar2 ) return varchar2
is
li_n binary_integer default 0;
ls_hexstr varchar2(16) default '0123456789ABCDEF';
ls_return varchar2(2000) default '';
begin
if ( as_binstr is null ) then
return null;
end if;
ls_return := '';
li_n := 0;
for i in 1 .. length(as_binstr) loop
li_n := li_n*2 + abs(instr('01',substr(as_binstr,i,1))-1);
if mod(i,4) = 0 then
ls_return := ls_return || substr(ls_hexstr,li_n+1,1);
li_n := 0;
end if;
end loop;
return ls_return;
end;
/
SELECT binstr_to_hexstr('00101010') AS hexstr FROM DUAL UNION ALL
SELECT binstr_to_hexstr('00x0 010') FROM DUAL;
HEXSTR
------
2A
2A
。
这是一个可以作为起点的例子。
(注意:这个函数只是一个例子,当输入字符串的长度不是8个字符的倍数时,它不能有效地处理这种情况。此外,它的行为是字符串值包含“1”以外的字符或'0'可能不合适(因为它写的,它会将除'0'之外的任何字符视为'1'。但是,它作为一个起点已经足够了。)
MOD(length(as_binstr),8) = 0
注意:此函数仅在输入字符串的长度为8的偶数倍(即HEXTORAW
)时返回预期结果(匹配的十六进制表示)。否则,函数“丢失”尾随位和/或返回奇数个十六进制数字。 (当输入参数的长度不是8的倍数时,可以修改该函数以引发异常。)
使用客户端应用程序(如TOAD,SQL Developer或SQL * Plus)处理RAWTOHEX
数据时,RAW
和HEXTORAW
函数非常有用。 (binstr_to_hexstr
函数是我们用来将create or replace function binstr_to_raw
( as_binstr in varchar2 ) return raw
is
begin
return hextoraw(binstr_to_hexstr(as_binstr));
end;
/
函数的输出转换为RAW的函数。)例如:
UTL_RAW
正如文森特·马格拉特在答案中指出的那样,Oracle提供了一些包(例如UTL_ENCODE
和{{1}}),这些包在处理RAW数据时非常有用。
http://docs.oracle.com/cd/E11882_01/appdev.112/e25788/u_raw.htm
答案 2 :(得分:2)
为此,您可以使用BLOB
(二进制大对象)类型。 Link举例说明如何使用它。
答案 3 :(得分:2)
截至今天,我在10和11g上使用它,我认为答案需要更新。这些数据类型的内置数据类型是RAW
(可以比PL / SQL中的BLOB
更容易操作的二进制数据。)
顾名思义,RAW
数据类型是原始二进制格式,并且这样存储(第一个块的长度字节除外),因此该行的最佳存储空间。可以使用RAW
包来操纵SYS.UTL_RAW
个数据类型。它可以被转换为几乎任何数据类型(如果存储方案匹配。例如b1101
不是NUMBER
13,但它是PL_INTEGER
13和VARCHAR2
等效于{ {1}}。
此外,CHR(13)
和UTL_RAW
函数更容易使用HEXTORAW
而不是使用RAWTOHEX
进行强制转换,而是在RAW
中将数据从{16}中的数据的十六进制表示形式来回转换为VARCHAR2
{1}}。例如,HEXTORAW('d')
或HEXTORAW('D')
都会导致RAW
值b00001101
;如您所见,由于RAW
的基本块是一个字节,所以额外的零填充到左侧以形成一个字节。在转换为VARCHAR2
和其他流的过程中,数据本身充当little-endian(意味着最低有效字节位于数据的最右边的字节),但是在转换为复杂的数据类型(如NUMBER
时)只复制内存,如果是nessecary,则向左填充零。
答案 4 :(得分:-1)
我不确定这是否有帮助,但您可以使用NUMBER数据类型和bin_to_num函数:
create table test_bin(num_val number, var_val varchar2(1000));
insert into test_bin values(bin_to_num(1,0,1,0,1,0,1,0), '10101010');
select dump(num_val, 17) n, dump(var_val, 17) v from test_bin;
n | v
---------------------------------------------------
Typ=2 Len=3 c2,^B,G | Typ=1 Len=8 1,0,1,0,1,0,1,0
正如你所看到的,它是排序器 - 而不是8个字节,你只有3个,但它仍然不是一个字节
<强>更新强>
找到了一种方法,让它在一个字节中:
您可以使用chr
功能
select dump(chr(bin_to_num(1,0,1,0,1,0,1,0))) c from dual;
n
--------------------
Typ=1 Len=1 170
因此,您可以继续使用varchar2,但只需将每8位转换为char