Montag, Mai 05, 2014

Komprimierungseffektivität bestimmen mit dbms_compression.get_compression_ratio

Heute wurde im OTN Forum die Frage diskutiert, ob dbms_compression.get_compression_ratio für bereits komprimierte Tabellen eine Aussage zur Effektivität der Komprimierung liefert: also ob sich durch Updates so viele Entpackungen von Datensätzen ergeben haben, dass eine erneute Komprimierung sinnvoll wäre. Ich habe zur Beantwortung mein Standardverfahren eingesetzt:
  1. Nachdenken
  2. Zu keinem eindeutigen Ergebnis kommen
  3. Test erstellen und ausprobieren
Der Test in 11.2.0.1 dazu sah etwa folgendermaßen aus - und bediente sich aus ähnlichen Beispielen von Christian Antognini und Neil Johnson (die, hätte ich sie sorgfältig gelesen, die im Raum stehende Frage bereits beantwortet hätten):

-- Test mit einem User mit DBA-Rechten

-- Anlage eines Tablespace für temporäre Testobjekte
create tablespace scratch datafile 'E:\ORACLE_DATA\TEST\SCRATCH.DBF' size 50M;

-- Anlage einer Test-Tabelle
drop table t;

create table t 
as
select rownum id
     , lpad('*', 50, '*') compressable_col
  from dual
connect by level <= 1000000;

exec dbms_stats.gather_table_stats(user, 'T')  

-- Aufruf der Prozedur zur Bestimmung der Komprimierungseffekte
DECLARE
  l_blkcnt_cmp       BINARY_INTEGER;
  l_blkcnt_uncmp     BINARY_INTEGER;
  l_row_cmp          BINARY_INTEGER;
  l_row_uncmp        BINARY_INTEGER;
  l_cmp_ratio        NUMBER;
  l_comptype_str     VARCHAR2(100);
BEGIN
      dbms_compression.get_compression_ratio(
        -- input parameters
        scratchtbsname   => 'SCRATCH',                           -- scratch tablespace
        ownname          => user,                                -- owner of the table
        tabname          => 'T',                                 -- table name
        partname         => NULL,                                -- partition name
        comptype         => dbms_compression.comp_for_oltp,      -- compression algorithm
        subset_numrows   => 1000000,
        -- output parameters
        blkcnt_cmp       => l_blkcnt_cmp,    -- number of compressed blocks
        blkcnt_uncmp     => l_blkcnt_uncmp,  -- number of uncompressed blocks
        row_cmp          => l_row_cmp,       -- number of rows in a compressed block
        row_uncmp        => l_row_uncmp,     -- number of rows in an uncompressed block
        cmp_ratio        => l_cmp_ratio,     -- compression ratio
        comptype_str     => l_comptype_str   -- compression type
      );
      dbms_output.put_line('type: '|| l_comptype_str);
      dbms_output.put_line('blocks comp: '|| l_blkcnt_cmp);
      dbms_output.put_line('blocks uncomp: '|| l_blkcnt_uncmp);
      dbms_output.put_line('ratio: '|| to_char(l_cmp_ratio,'99.999'));
END;
/

type: "Compress For OLTP"
blocks comp: 203
blocks uncomp: 1024
ratio:   5.000

select blocks from dba_segments where segment_name = 'T';

    BLOCKS
----------
      9216

Die "blocks uncomp" haben also nichts mit der tatsächlichen Größe des Basisobjekts zu tun - und bereits die erforderliche Angabe des "scratchtbsname" konnte vermuten lassen, dass hier temporäre Objekte und Sampling im Spiel sind. Diese Annahme bestätigt dann auch das zugehörige SQL-Trace:

create table "TEST".DBMS_TABCOMP_TEMP_UNCMP tablespace "SCRATCH" nologging as
  select /*+ FULL("TEST"."T") */ *  from "TEST"."T"  sample block( 22) mytab
 
create table "TEST".DBMS_TABCOMP_TEMP_CMP organization heap  tablespace
  "SCRATCH" compress for oltp nologging as select /*+ FULL("TEST"."T") */ *
  from "TEST".DBMS_TABCOMP_TEMP_UNCMP mytab

Hier wird also via CTAS eine nicht komprimierte Tabelle aus einem Sample des Quellobjekts erzeugt und zu diesem Sample wird dann anschließend eine komprimierte Version angelegt. Ungefähr so hätte ich das wahrscheinlich auch gemacht, wenn ich einen entsprechenden Test manuell durchgeführt hätte. Zur Beantwortung der ursprünglichen Frage könnte die Procedure demnach nur indirekt dienen.

Keine Kommentare:

Kommentar veröffentlichen