corner image
home ·Fragmentierung in Oracle


letzte Änderung:
TCP-States
Netzwerk
Links
Australien
Wertpapiere

Fragmentierung einer Oracle-Datenbank

Ein kleiner Arikel was mit "Fragmentierung" innerhalb von Oracle gemeint ist, verschiedene Meinungen dazu und einige SQL's

Die Fragmentierung von Datenbank-Objekten (Tabellen, Indexe)

{Beschreibung}
Unter Fragmentierung von Datenbank-Objekten versteht man normalerweise, das ein Datenbank-Objekt (z.B: Tabelle oder Index) nicht mehr in das INITIAL_EXTENT passt.
Das kann passieren wenn das Datenbank-Objekt mit den falschen Storage-Parametern erzeugt wird (INITIAL_EXTENT zu klein) oder wenn das Datenbank-Objekt wächst.
In beiden fällen reicht das INITIAL_EXTENT nicht aus um alle Daten des Datenbank-Objekts zu speichern, daher werden weitere extents angelegt.

Für mich ist das eigendlich keine "Fragmentierung" da keine "Löcher" entstehen die nicht wieder mit Daten gefüllt werden könnten, und ich schliese mich daher der Meinung von Tom Kyte an:

"In fact, some of mine (Tables) are nearing 1,000 extents and I am perfectly happy. If having hundreds of extents was a problem -- I would not be happy. Since having lots of extents is not a problem, I have no problems with this situation.

This is not fragmentation. Fragmentation is when you have lots of irregular "holes" in a tablespace. In your system tablespace -- since space is never released, only allocated, you cannot have fragmentation. You do not have any HOLES in system -- just lots of stuff.

It should NEVER be your goal to absolutely minimize extents. That is a myth.

siehe Ask Tom Forum

Bei einem Index ist es ähnlich ( siehe auch hier im Ask Tom Forum)

{Identifikation}
Mit folgendem SQL können die Datenbank-Objekte idendifiziert werden, die mehr als zehn extents haben:

select * from dba_segments where extents > 10;

{Beseitigung}
Eine Möglichkeit diese Extents wieder in eim Extent zusammenzufassen ist ein Export und ein anschließender Import

  • Export der tabelle mit der COMPRESS=Y option
  • Drop der Tabelle (oder TRUNCATE)
  • Anschließender Import.

In der 10g Dokumentation habe ich den Befehl

ALTER TABLE MOVE TABLESPACE

gefunden, mit dem es möglich sein
sollte eine Tabelle in ein neues Tablespace zu verschieben und dabei die Storage-Parameter zu ändern ohne alle Foreign-keys und Tabellen-Trigger zu verlieren
(Dazu habe ich leider keine endgültige Aussage in der Oracle-Doku gefunden und daher sollte das getestet werden bevor man es einsetzt).
Allerdings muss auch hier genug Platz zur Verfügung stehen, da die Tabelle dupliziert wird.

Ab 9i exitstiert das package DBMS_REDEFINITION mit dem es möglich ist die logische oder physikalische Struktur zu verändern.
Währen dieser redefinition kann ganz normal auf die Tabelle zugegriffen werden. Ein Lock auf die Tabelle ist unabhängig von der größe nur für einen kurzen Zeitraum notwendig. Es wird auch hier mindestens der doppelte Speicherplatz benötigt. (PCTFREE)
Auch hier sollte es kein Problem mit Triggern und Foreign-Keys geben aber in der Doku habe ich auch hier keine eindeutige Aussage gefunden.

Wie ein Index neu erzeugt werden kann habe ich in Anhang beschrieben.

{Probleme}

  • Eine Tabelle zu droppen birgt viele Risiken, da bei diese Aktion alle an der Tabelle "hängenden" Objekte auch mitgelöscht werden, z.B: Trigger und Foreign Keys
  • Doppelter Plattenplatz, da die Tabelle auf jeden fall dupliziert werden muss (Auch bei ALTER TABLE MOVE).
  • Auch ein Recreate eines Indexes ist nicht risikolos, falls Unique- oder Primary Indexes gedropt werden. In diesem Fall ist die Datenbank nicht mehr in der Lage ist auf Eindeutigkeit oder Korrektheit zu prüfen und es ist daher möglich inkonsistente Daten in den dazugehörigen Tabellen abzulegen.

Fragmentiete Tablespaces

{Beschreibung}
Ein fragmentiertes Tablespace ist ein Tablespace in dem verschieden Objekte angelegt werden/wurden, die unterschiedliche Extentgrößen haben (oder PCTINCREASE verwenden) solange diese Objekte nicht gelöscht werden haben wir auch keine Fragmentierung. Falls aber Objekte (Tabellen, Indexe ..) gelöscht entstehen "Löcher", was erst einmal nicht weiter schlimm ist.
Falls diese "Löcher" aber unterschiedliche Größen haben können, passen die nächsten Extents von wachsenden Tabellen, oder neue Objekte nicht in die "Löcher".

{Identifikation}
Fragmentierte Tablepaces liegen vor wenn ein neues Objekt nicht erzeugt werden kann (oder eine Tabelle/Index nicht erweitert werden kann obwohl in summe genug freier Platz zur Verfügung stehen würde

{Beseitigung}
Benutzung von LMT's (Locally Managed Tablespaces) oder erstellen aller Datenbankobjekte mit demselben NEXTEXTENT und einem INITIALEXTENT der ein Vielfaches des NEXTEXTENTS ist.
Dadurch ist es möglich die entstandenen "Löcher" wiederzuverwenden.

{Probleme}
Das Datenbank-Objekte (Tabelle, Index usw) in mehrere Extents verteilt sind hat (lt. Tom Kyte, DBAzine) auf die Performance keinen (oder nur marginalen) Einfluss. Da das Problem im Nachhinein nur durch eine Redefinition der Storage-Parameter der Datenbank-Objekte gelöst werde kann gilt hier das gleiche wie bereits im Kapitel Fragmentierung von Datenbank-Objekten gesagte.
Besser ist es bereits beim Datebank Design auf LMT's einzusetzen oder (und) beim Erstellen der Datenbank-Objekte auf konsistente Extentgrößen zu achten.

Ein Tablespace, in dem nie Datenbank-Objekte gelöscht werden fragmentiert nicht! (was nicht heißt das in diesem Tablespace kein Platz verschwendet werden kann)

Anhang

Einen Index neu erzeugen

Der einfachste Weg einen Index neu zu erzeugen ist:

Alter index <index-name> rebuild tablespace < index-tablespace>;

Diese Vorgehensweise hat außerdem den Vorzug, dass der Zugriff auf den Index während der regenerierung weiter möglich ist. Das Tablespace sollte angegeben werden, da der Index sonst im Default-Tablespace des Users angelegt wird.

Beim neu Erzeugen eines Indexes haben wir die Möglichkeit dem Index neue Storage-Parameter mitzugeben.

Falls der Index aber korrupt ist, bleibt uns nichts anders übrig als den Index zu droppen und wieder neu anzulegen.

  • Zuerst lassen wir uns die index Spalten anzeigen
    SELECT COLUMN_NAME FROM USER_IND_COLUMNS
    WHERE INDEX_NAME = 'index_name';

    SELECT TABLE_NAME, UNIQUENESS, TABLESPACE_NAME,
    INITIAL_EXENT, NEXT_EXTENT, MIN_EXTENTS, MAX_EXTENTS,
    PCT_INCREASE, PCT_FREE
    FROM USER_INDEXES WHERE INDEX_NAME = 'index_name';

    Das obige SQL liefert uns die Spalten aus denen der Index aufgebaut ist.
  • Drop index <index-name>;
    Create [UNIQUE] index <index-name>
    On <table-name>
    ( <column-1> [ , <column-n> ] )
    tablespace <tablespace>
    PCTFREE <pct-free>
    STORAGE (
    NEXT <size>K
    INITIAL <size>K
    PCTINCREASE <pct_increase>
    MIN_EXTENTS <min_extents>
    MAX_EXTENTS <max_extents> );
    {Hinweis}
    • Um die Anzahl der Extents zu reduzieren sollte das initial extent auf einen Wert gesetzt werden das der komplette Index hineinpasst.
      Die Größe des alten Indexes kann mit:
      Select sum(bytes) from dba_extents
      where segment_name='<index-name>';

      ermittelt werden.
    • Alternativ kann man auch die im nächsten Absatz beschriebenen Wege gehen.
    • Der Primary-Key sollte nicht auf diese weise gedropped or neu erzeugt werden. (Doppelte Einträge in der Tabelle da eine Überprüfung des UNIQUE oder PRIMAY nicht mehr möglich ist)

Informationen über einen Index ermitteln

Allgemeine Informationen über einen Index können mit folgen SQL's ermittelt werden:

Analyze index <index-name> compute statistics;

Select * from user_indexes
where index_name= '<index-name>';


Tiefergehende Informationen werden durch folgende Statements in die Tabelle INDEX_STATS geschrieben:

Analyze index <index-name> validate structure;
Oder Validate index <index-name>;

Diese Tabelle kann nur eine Zeile enthalten, in der ein Index beschrieben ist. Die folgenden SQL's verifizieren auch die Integrität jedes Datenblocks.
Um z.B die größe des Indexes zu erhalten:

validate index <index_name>; select name "INDEX NAME", blocks * 8192 "BYTES ALLOCATED",
btree_space "BYTES USED",
(btree_space / (blocks * 8192))*100 "PERCENT USED"
from index_stats;
Im obigen Beispiel wird davon ausgegangen, das ein DB-Block eine Größe von 8Kb (8192 bytes) hat.
Es zeigt die Anzahl von Bytes an die für den Index allokiert sind, und NICHT die Anzahl die momentan benutzt wird.

  ©2016· Claus Ebert · Emailemail senden