Donnerstag, März 28, 2013

CPU-Kosten von Compression im SQL Server

Thomas Kejser hat vor ein paar Tagen ein paar Bemerkungen zu den Wirkungen von Page-Compression auf die Performance von Selects und Updates aufgeschrieben. Hier noch mal eine kurze Definition der Page-Compression, basierend auf den Aussagen der Dokumentation - demnach besteht Page Compression aus drei Teilen:
  • row compression: verwendet den kleinsten geeigneten Datentyp zur Speicherung der Daten
  • prefix compression: wiederholte prefix Werte (einzelner Spalten) werden in einer compress information (CI) Struktur direkt hinter dem page header eingefügt und an den passenden Stellen referenziert
  • dictionary compression: wiederholte Werte der page werden in die CI area eingefügt und an den passenden Stellen referenziert (wobei sich diese Ersetzung Spalten-übergreifend erfolgt)
Das Verfahren weist demnach recht massive Ähnlichkeiten zu Oracles compression auf und stellt ebenfalls eine Deduplication durch Ersetzung wiederholter Token dar (wobei Oracle im Fall von Tabellen keine prefix compression durchführt).

Beim Herrn Kejser wird eine recht große Tabelle ("the TPC-H LINEITEM table at scale factor 10. That is about 6.5GB of data.") gelesen bzw. per update geändert und im Ergebnis sind die Operationen auf dem komprimierten Objekt deutlich langsamer als die auf einer entsprechenden Tabelle ohne Komprimierung. Das Fazit lautet:
Quoting a few of my tests from my presentation, I have shown you that PAGE compression carries a very heavy CPU cost for each page access. Of course, not every workload is dominated by accessing data in pages – some are more compute heavy on the returned data. However, in these days when I/O bottlenecks can easily be removed, it is worth considering if the extra CPU cycles to save space are worth it.
It turns out that it is possible to also show another expected results: that locks are held longer when updating compressed pages (Thereby limiting scalability if the workload contains heavily contended pages).
Ein ähnlicher Versuch mit einer Oracle 11.1.0.7-Test-Datenbank liefert mir ein verwandtes Ergebnis:

drop table t1;

create table t1
as
select round(rownum/1000) col1
     , mod(rownum, 1000) col2
     , round(rownum/100) col3
     , mod(rownum, 100) col4
     , round(rownum/10) col5
     , mod(rownum, 10) col6
  from dual
connect by level <= 1000000;

insert into t1
select * from t1;

insert into t1
select * from t1;

insert into t1
select * from t1;

insert into t1
select * from t1;

drop table t2;

create table t2 compress
as
select * from t1;

exec dbms_stats.gather_table_stats(user, 'T1')
exec dbms_stats.gather_table_stats(user, 'T2')

select segment_name
     , blocks
     , round(bytes/1024/1024) mbyte 
  from dba_segments
 where segment_name in ('T1', 'T2');

SEGMENT_NAME             BLOCKS      MBYTE
-------------------- ---------- ----------
T1                        30720        480
T2                        17920        280

In diesem Fall ist der Größenunterschied zwischen der komprimierten und der nicht-komprimierten Version nicht gewaltig (Reduzierung auf 58,33% der Basisgröße), aber beim lesenden Zugriff ergibt sich eine (stabil) messbare Erhöhung von CPU_TIME und Gesamtlaufzeit für den Fall der komprimierten Tabelle T2:

select /* test t1 */
       sum(col1)
     , sum(col2)
     , sum(col3)
     , sum(col4)
     , sum(col5)
     , sum(col6)
  from t1;

select /* test t2 */
       sum(col1)
     , sum(col2)
     , sum(col3)
     , sum(col4)
     , sum(col5)
     , sum(col6)
  from t2;

select substr(sql_text, 1, 20) sql_text
     , disk_reads
     , buffer_gets
     , elapsed_time
     , cpu_time
     , user_io_wait_time
  from v$sql
 where sql_id in ('1whhzus1w5j57', '123rusnujf8dp');

SQL_TEXT             DISK_READS BUFFER_GETS ELAPSED_TIME   CPU_TIME USER_IO_WAIT_TIME
-------------------- ---------- ----------- ------------ ---------- -----------------
select /* test t1 */      30293       30302      6180032    6176061            568945
select /* test t2 */      17400       17405      7694043    7668834            328810

Zwar sinkt die USER_IO_WAIT_TIME, aber gegenüber der CPU_TIME fällt sie kaum ins Gewicht.  Anscheinend also wieder mal ein Fall, der für SQL Server und Oracle ein ähnliches Verhalten zeigt - wobei ich (ohne länger darüber nachzudenken) annehme, dass die Locking Probleme des SQL Servers bei Oracle keine Rolle spielen.

Kommentare:

  1. Hallo,
    einen tollen und interessanten Blog führen Sie –
    man trifft im Internet selten auf so fundiertes Wissen. Danke dafür.
    Ich bin selber Student und baue auch eine Seite zum Thema Datenbanken(Datenbanken-verstehen.de)auf,
    welche allerdings nicht so tiefgehende Inhalte wie ihre Seite vermittelt,
    sondern eher die Grundlagen. Würde mich gegebenenfalls über eine Verlinkung oder einen Linktausch freuen.
    Gruß, Markus

    AntwortenLöschen
  2. Danke für das positive Feedback. Ich habe einen Blick auf Datenbanken-verstehen.de geworfen und die Seite gefällt mir gut (und ist jetzt auch in meiner Link-Sammlung drin: http://martinpreiss.blogspot.de/2011/09/deutschsprachige-oracle-webseiten.html). Ich würde vielleicht als kleine Ergänzung vorschlagen, Versionsinformationen dort hinzuzufügen, wo sie relevant sind: im Fall des SQL Servers etwa sind die analytischen Funktionen LAG und LEAD meiner Erinnerung nach erst seit Release 2012 unterstützt. Jonathan Lewis hat gelegentlich seine Kriterienliste für relevante Informationen im Internet vorgelegt (zu der mir der Link gerade fehlt) und da gehören zu den wichtigsten Anforderungen eine Datierung und eine Versionsangabe (was mir völlig einleuchtet, obwohl ich selbst die Version auch immer mal wieder unterschlage...)

    Dieser Tage hat Eddie Awad seinen Oracle New Aggregator (OraNA) aufgeräumt und dabei die Anzahl durch die Entfernung inaktiver Seiten von 508 auf 323 reduziert (http://awads.net/wp/2013/03/25/oracle-news-aggregator-orana-no-longer-powered-by-google-reader). Dabei merkt er an: "I guess the enthusiasm for long form blogging has fizzled out over the years. Lazy bloggers (including yours truly) find it much easier and quicker to “micro” blog using Twitter, Facebook or Google+." Vermutlich hat er damit recht, was ich bedauere, weil ich in aller Regel aus einem soliden Blog-Artikel mehr lerne als aus einem Halbsatz bei Twitter. Insofern freue ich mich sehr über eine lebendige deutschsprachige DB-Seite mit wachsendem Content.

    Gruß

    Martin

    AntwortenLöschen
    Antworten
    1. Hallo Martin,

      vielen Dank für die Verlinkung.
      Ich glaube auch, dass Du schon in unserem Forum tätig bist oder?
      Ich würde mich sehr freuen, wenn Du den Anfängern dort unter die Arme greifen würdest.
      Falls Du Zeit und Lust hast natürlich...

      Beste Grüße,
      Markus

      Löschen
    2. Hallo Markus,

      tätig ist zu viel gesagt, aber angemeldet habe ich mich - mal sehen, ob ich es auch noch schaffe, Kommentare abzugeben.

      Gruß

      Martin

      Löschen