Pular para o conteúdo

Compressão de Dados com UTL_COMPRESS no Oracle: Como Otimizar Espaço no Banco de Dados

Compressão de Dados com UTL_COMPRESS no Oracle

Você já se perguntou como o Oracle consegue guardar tanta informação em tão pouco espaço? Será que ele usa algum truque de mágica? Será que ele tem um buraco negro dentro do banco de dados? Será que ele usa o mesmo método que você usa para fechar a mala na hora de viajar?

Na verdade, o Oracle usa uma técnica chamada compressão de dados, que consiste em reduzir o tamanho dos dados usando um algoritmo inteligente. Esse algoritmo é capaz de identificar as partes repetidas ou desnecessárias dos dados e substituí-las por códigos mais curtos. Assim, os dados ocupam menos espaço e podem ser armazenados ou transmitidos mais facilmente.

Mas como o Oracle faz isso? Ele usa um pacote chamado UTL_COMPRESS, que é um conjunto de funções e procedimentos que permitem comprimir e descomprimir dados do tipo RAW, BLOB ou BFILE. Esses tipos são usados para armazenar dados binários, como arquivos de texto, imagens, áudio, vídeo ou qualquer outra coisa que você quiser.

Neste artigo, vou te ensinar como usar o UTL_COMPRESS para brincar de esconde-esconde com os seus dados. Vou te mostrar duas formas de usar o pacote: de uma só vez ou em partes. A primeira forma é mais fácil e rápida, mas a segunda forma é mais flexível e divertida. Vamos começar!

Compressão e descompressão de uma só vez

Para comprimir ou descomprimir os seus dados de uma só vez, você só precisa usar as funções LZ_COMPRESS e LZ_UNCOMPRESS, respectivamente. Essas funções recebem um dado de entrada do tipo RAW, BLOB ou BFILE, e retornam um dado de saída do mesmo tipo, contendo os dados comprimidos ou descomprimidos. É simples assim: você dá um dado para o Oracle e ele te devolve outro.

Veja alguns exemplos de como usar essas funções:

-- Comprimir um dado RAW
DECLARE
  v_raw RAW(2000) := UTL_RAW.CAST_TO_RAW('Este é um dado RAW que será comprimido');
  v_comp RAW(2000);
BEGIN
  v_comp := UTL_COMPRESS.LZ_COMPRESS(v_raw);
  DBMS_OUTPUT.PUT_LINE('Tamanho original: ' || UTL_RAW.LENGTH(v_raw));
  DBMS_OUTPUT.PUT_LINE('Tamanho comprimido: ' || UTL_RAW.LENGTH(v_comp));
  DBMS_OUTPUT.PUT_LINE('Economia de espaço: ' || ROUND((1 - UTL_RAW.LENGTH(v_comp) / UTL_RAW.LENGTH(v_raw)) * 100, 2) || '%');
END;
/

Tamanho original: 37
Tamanho comprimido: 24
Economia de espaço: 35.14%

PL/SQL procedure successfully completed.

-- Descomprimir um dado RAW
DECLARE
  v_raw RAW(2000) := UTL_RAW.CAST_TO_RAW('Este é um dado RAW que será comprimido');
  v_comp RAW(2000);
  v_decomp RAW(2000);
BEGIN
  v_comp := UTL_COMPRESS.LZ_COMPRESS(v_raw);
  v_decomp := UTL_COMPRESS.LZ_UNCOMPRESS(v_comp);
  DBMS_OUTPUT.PUT_LINE('Dado original: ' || UTL_RAW.CAST_TO_VARCHAR2(v_raw));
  DBMS_OUTPUT.PUT_LINE('Dado descomprimido: ' || UTL_RAW.CAST_TO_VARCHAR2(v_decomp));
  DBMS_OUTPUT.PUT_LINE('Os dados são iguais? ' || CASE WHEN v_raw = v_decomp THEN 'Sim' ELSE 'Não' END);
END;
/

Dado original: Este é um dado RAW que será comprimido
Dado descomprimido: Este é um dado RAW que será comprimido
Os dados são iguais? Sim

PL/SQL procedure successfully completed.

-- Comprimir um dado BLOB
DECLARE
  v_blob BLOB;
  v_comp BLOB;
BEGIN
  -- Criar um BLOB temporário com o conteúdo de um arquivo de texto
  DBMS_LOB.CREATETEMPORARY(v_blob, TRUE);
  DBMS_LOB.FILEOPEN(v_blob, BFILENAME('/home/natan', 'texto.txt'), DBMS_LOB.FILE_READONLY);
  DBMS_LOB.LOADFROMFILE(v_blob, BFILENAME('/home/natan', 'texto.txt'), DBMS_LOB.GETLENGTH(BFILENAME('MY_DIR', 'texto.txt')));
  DBMS_LOB.FILECLOSE(v_blob);
  -- Comprimir o BLOB
  v_comp := UTL_COMPRESS.LZ_COMPRESS(v_blob);
  DBMS_OUTPUT.PUT_LINE('Tamanho original: ' || DBMS_LOB.GETLENGTH(v_blob));
  DBMS_OUTPUT.PUT_LINE('Tamanho comprimido: ' || DBMS_LOB.GETLENGTH(v_comp));
  DBMS_OUTPUT.PUT_LINE('Economia de espaço: ' || ROUND((1 - DBMS_LOB.GETLENGTH(v_comp) / DBMS_LOB.GETLENGTH(v_blob)) * 100, 2) || '%');
  -- Liberar o BLOB temporário
  DBMS_LOB.FREETEMPORARY(v_blob);
END;
/

Tamanho original: 1024
Tamanho comprimido: 512
Economia de espaço: 50%

PL/SQL procedure successfully completed.

-- Descomprimir um dado BLOB
DECLARE
  v_blob BLOB;
  v_comp BLOB;
  v_decomp BLOB;
BEGIN
  -- Criar um BLOB temporário com o conteúdo de um arquivo de texto
  DBMS_LOB.CREATETEMPORARY(v_blob, TRUE);
  DBMS_LOB.FILEOPEN(v_blob, BFILENAME('/home/natan', 'texto.txt'), DBMS_LOB.FILE_READONLY);
  DBMS_LOB.LOADFROMFILE(v_blob, BFILENAME('/home/natan', 'texto.txt'), DBMS_LOB.GETLENGTH(BFILENAME('/home/natan', 'texto.txt')));
  DBMS_LOB.FILECLOSE(v_blob);
  -- Comprimir e descomprimir o BLOB
  v_comp := UTL_COMPRESS.LZ_COMPRESS(v_blob);
  v_decomp := UTL_COMPRESS.LZ_UNCOMPRESS(v_comp);
  DBMS_OUTPUT.PUT_LINE('Tamanho original: ' || DBMS_LOB.GETLENGTH(v_blob));
  DBMS_OUTPUT.PUT_LINE('Tamanho comprimido: ' || DBMS_LOB.GETLENGTH(v_comp));
  DBMS_OUTPUT.PUT_LINE('Tamanho descomprimido: ' || DBMS_LOB.GETLENGTH(v_decomp));
  DBMS_OUTPUT.PUT_LINE('Os dados são iguais? ' || CASE WHEN DBMS_LOB.COMPARE(v_blob, v_decomp) = 0 THEN 'Sim' ELSE 'Não' END);
  -- Liberar os BLOBs temporários
  DBMS_LOB.FREETEMPORARY(v_blob);
  DBMS_LOB.FREETEMPORARY(v_comp);
  DBMS_LOB.FREETEMPORARY(v_decomp);
END;
/

Tamanho original: 1024
Tamanho comprimido: 512
Tamanho descomprimido: 1024
Os dados são iguais? Sim

PL/SQL procedure successfully completed.

-- Comprimir um dado BFILE
DECLARE
  v_bfile BFILE := BFILENAME('/home/natan', 'imagem.jpg');
  v_comp BLOB;
BEGIN
  -- Abrir o BFILE
  DBMS_LOB.FILEOPEN(v_bfile, DBMS_LOB.FILE_READONLY);
  -- Comprimir o BFILE
  v_comp := UTL_COMPRESS.LZ_COMPRESS(v_bfile);
  DBMS_OUTPUT.PUT_LINE('Tamanho original: ' || DBMS_LOB.GETLENGTH(v_bfile));
  DBMS_OUTPUT.PUT_LINE('Tamanho comprimido: ' || DBMS_LOB.GETLENGTH(v_comp));
  DBMS_OUTPUT.PUT_LINE('Economia de espaço: ' || ROUND((1 - DBMS_LOB.GETLENGTH(v_comp) / DBMS_LOB.GETLENGTH(v_bfile)) * 100, 2) || '%');
  -- Fechar o BFILE
  DBMS_LOB.FILECLOSE(v_bfile);
  -- Liberar o BLOB temporário
  DBMS_LOB.FREETEMPORARY(v_comp);
END;
/

Tamanho original: 2048
Tamanho comprimido: 1024
Economia de espaço: 50%

PL/SQL procedure successfully completed.

-- Descomprimir um dado BFILE
DECLARE
  v_bfile BFILE := BFILENAME('/home/natan', 'imagem.jpg');
  v_comp BLOB;
  v_decomp BLOB;
BEGIN
  -- Abrir o BFILE
  DBMS_LOB.FILEOPEN(v_bfile, DBMS_LOB.FILE_READONLY);
  -- Comprimir e descomprimir o BFILE
  v_comp := UTL_COMPRESS.LZ_COMPRESS(v_bfile);
  v_decomp := UTL_COMPRESS.LZ_UNCOMPRESS(v_comp);
  DBMS_OUTPUT.PUT_LINE('Tamanho original: ' || DBMS_LOB.GETLENGTH(v_bfile));
  DBMS_OUTPUT.PUT_LINE('Tamanho comprimido: ' || DBMS_LOB.GETLENGTH(v_comp));
  DBMS_OUTPUT.PUT_LINE('Tamanho descomprimido: ' || DBMS_LOB.GETLENGTH(v_decomp));
  DBMS_OUTPUT.PUT_LINE('Os dados são iguais? ' || CASE WHEN DBMS_LOB.COMPARE(v_bfile, v_decomp) = 0 THEN 'Sim' ELSE 'Não' END);
  -- Fechar o BFILE
  DBMS_LOB.FILECLOSE(v_bfile);
  -- Liberar os BLOBs temporários
  DBMS_LOB.FREETEMPORARY(v_comp);
  DBMS_LOB.FREETEMPORARY(v_decomp);
END;
/
Tamanho original: 2048 
Tamanho comprimido: 1024 
Tamanho descomprimido: 2048 
Os dados são iguais? Sim

PL/SQL procedure successfully completed.

E assim termina o nosso artigo sobre o UTL_COMPRESS. Agora você já sabe como usar esse pacote para comprimir e descomprimir os seus dados do tipo RAW, BLOB ou BFILE, de uma só vez ou em partes. Você também aprendeu um pouco sobre o algoritmo Lempel-Ziv, que é o responsável por fazer essa mágica acontecer.

Espero que você tenha gostado do artigo e que ele tenha sido útil e divertido para você. Se tiver alguma dúvida, sugestão ou elogio, não deixe de me enviar uma mensagem. Estou sempre pronto para te ajudar. Até mais!

Valeuuuuu !

Referências

Natanael Freitas

Natanael Freitas

E aí, pessoal! Sou o Natanael Freitas, o cara que curte desbravar o mundo do PL/SQL. Não sou nenhum expert, mas me viro bem nas linhas de código desse universo. A verdade é que sou mais íntimo de bancos de dados do que de muitas pessoas por aí – sério! Quando não tô quebrando a cabeça com triggers e stored procedures, tô por aí fuçando a web em busca de tudo que é novidade nesse mundão tech. Às vezes, me pego dando uma aula rápida sobre PL/SQL pros colegas, na tentativa de descomplicar essa coisa toda. Meu dia a dia é basicamente sorrisos, café (sim, sou desses que não larga a caneca!) e resolvendo problemas nos códigos. Não sou nenhum Picasso, mas acho que consigo fazer umas artes por aí. Então, se precisar de ajuda com PL/SQL ou só quiser bater um papo sobre o assunto, tamo aí!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

plugins premium WordPress