Oracle Performance Problem

Zugriffe auf eine einzelne Tabelle eines Oracle Datenbank-Clusters bereiten mir gerade etwas Kopfschmezen. Die Tabelle ist so etwas wie ein Dictionary und hat zwei Spalten. Abfragen haben die Form

SELECT value
FROM myTable
WHERE key='...';

Da die Daten in dieser Tabelle nur über einen kurzen Zeitraumhinweg gültig sind, gibt es sehr viele INSERT-/DELETE-Operationen und die Festplatte schafft den i/o-traffic nicht. Die Festplatte ist genaugenommen ein RAID Storage, bei meiner Frage geht es mir nicht um Hardware-tuning.

Vielmehr möcht ich wissen, ob es mit Oracle möglich ist, die i/o-Zugriffe zu reduzieren. Mir schwebt so etwas wie eine Tabelle im Hauptspeicher vor, die ohne Festplattenzugriffe auskommt. Im Falle eines Crashs wären die Daten zwar verloren, da diese ohnehin nur kurze Zeit gültig sind, kann ich das verschmerzen. Da auch noch andere Tabellen existieren, kann ein Tablespac nicht ohne weiteres auf einer RAM-Disk abgelegt werden, da Oracle nach einen Start nicht mehr die passenden redo-logs zu der (nun leeren) RAM-Disk hat.

Ich habe schon über temporäre Tabellen nachgedacht, die sind aber Session-spezifisch. Für die Client-Anwendungen soll die Änderung auf der DB transparent geschehen, d.h. SELECT, INSERT und UPDATE sollen ohne Änderung in der App weiterhin funktionieren. Die Zugriffe auf die Tabelle erfolgen sowohl lesend als auch schreibend.

Hat jemand schon einmal mit einem ähnlichen Problem zu tun gehabt und kann mir einen Tipp geben?

Markus

Hallo Markus!

Erstmal würde ich die Tabelle - wenn sie sich lastmässig und strukturmässig so stark von den anderen Segmenten im Tablespace unterscheidet - in einen eigenen Tablespace legen. Dito gilt natürlich für alle eventuell existierenden Indizes für die Tabelle (die natürlich wie immer getrennt von der Tabelle selbst sein sollten).
Falls möglich solltest du dann diesen Tablespace auf ein(e) eigene(s) Platte(nsystem) legen. Weiters empfehle ich dringend über die Sinnhaftigkeit jedes einzelnen eventuell existierenden Indexes für die Tabelle nachzudenken, die beanspruchen bei höher INSERT/UPDATE/DELETE Häufigkeit einen durchaus bemerkenswerten Teil der Last.
Weiters empfehle ich darüber nachzudenken, ob das Logging für die betreffende Tabelle nicht ausgeschaltet werden sollte - eine Wiederherstellbarkeit zu einem belibigen Zeitpunkt ist ja scheinbar nicht so wichtig.

Ich hoffe zumindest einer der Punkte hilft dir weiter. Für mehr bräuchte ich dann schon die genaue Architektur (DB-Version, Application Server j/n, Infos zu den Instance Parametern wie Archive Log Mode, Log Buffers, Block Buffers, Verhältnis zwischen Änderungen in der Tabelle und Abfragen und alles was dir sonst noch einfällt, was interessant sein könnte).

Gruß
Martin

Hi,

Martins Ausführunge pflichte ich bei. ZUsätzlich noch eine oder zwei Ideen:

Vielmehr möcht ich wissen, ob es mit Oracle möglich ist, die
i/o-Zugriffe zu reduzieren. Mir schwebt so etwas wie eine
Tabelle im Hauptspeicher vor, die ohne Festplattenzugriffe
auskommt.

Du kannst bei der Tabellenerstellung die CACHE-Klausel verwenden. Dabei wird versucht, den Inhalt der Tabelle in den Hauptspeicher zu halten; zwar gibt es dafür keine Garantie, aber wenn die Tabelle nicht allzu groß ist und der Server über entsprechende Resourcen verfügt, sollte das tun. Aber Achtung: CACHE und NOLOGGING schließen sich gegenseitig aus; du solltest versuchen herauszufinden, was bei dir schneller läuft.

http://www.cs.nott.ac.uk/TSG/manuals/databases/oracl…

Eine andere Idee wäre, eine index-organized table zu verwenden, wenn das möglich ist. Das scheint mir aufgrund deines SQLs der Fall zu sein.

http://www.dbasupport.com/oracle/ora8/iot.shtml

Ich habe schon über temporäre Tabellen nachgedacht, die sind
aber Session-spezifisch.

Es gibt ab 8i „global temporary“-Tabellen; welche Version verwendest du?

Gruß

Hallo,

bist Du sicher, dass das wirklich Dein Problem ist? Ein RAID mit INSERT und DELETE auszubremsen ist gar nicht so einfach (wenn es den Namen verdient)

Du solltest auf jeden Fall mal nachschauen, ob Deine Tabelle stark fragmentiert ist. Ausserdem könntest Du noch über PCTFREE und PCTUSED optimieren, um möglichst viele Datensätze pro Zugriff zu erhalten.

Hast Du mal ein ANALYZE über die Tabelle laufen lassen und dir den Ausführungsplan während des Laufens angesehen. Da erlebt man manches.

Wie oft greifst Du denn auf die Tabelle zu? Du wirst ja auch etwas anderes als Lesen und Schreiben machen. Ich vermute, darin liegt das Problem. Nicht im I/O, sondern im SELECT. Lass mal den TKPROF mitlaufen und schau Dir die Kosten an.

Gruß

Peter

Hallo,

bist Du sicher, dass das wirklich Dein Problem ist? Ein RAID
mit INSERT und DELETE auszubremsen ist gar nicht so einfach
(wenn es den Namen verdient)

Es handelt sich um ein Software RAID und auf die Tabelle wird fortlaufend schreibend zugegriffen. Das verursacht auf dem Storage eine sehr hohe i/o-Last und somit für Verzögerungen. Auf einer lokalen Platte ist das i/o vernachlässigbar, durch den Betrieb im Cluster und eine zusätzliche Spiegelung ist es aber definitiv der bremsende Faktor.

Du solltest auf jeden Fall mal nachschauen, ob Deine Tabelle
stark fragmentiert ist. Ausserdem könntest Du noch über
PCTFREE und PCTUSED optimieren, um möglichst viele Datensätze
pro Zugriff zu erhalten.

Pro Zugriff wird im Best-Case genau ein Datensatz selektiert, im worse-case keiner. Der Index auf der Tabelle sorgt dafür, dass die Keys unique bleiben. Ohne Index ist die Tabelle auch nicht wesentlich schneller. Ggf. hilft ein tree-based table weiter, imho ist das aber nur feintuning.

Hast Du mal ein ANALYZE über die Tabelle laufen lassen und dir
den Ausführungsplan während des Laufens angesehen. Da erlebt
man manches.

Alles geprüft, das Problem ist definitiv iowait. Im Prinzip ist die Tabelle nur ein Dictionary, da die Daten nur kurze Zeit (Minuten) aktuell sind und dann gelöscht werden, ist die DB eher eine definierte Schnittstelle zum Zugriff. Echte persistenz ist eigentlich nicht erforderlich.
(Das RAID ist sub-optimal konfiguriert, das bekommen wir aber noch in den Griff)

Wie oft greifst Du denn auf die Tabelle zu? Du wirst ja auch
etwas anderes als Lesen und Schreiben machen. Ich vermute,
darin liegt das Problem. Nicht im I/O, sondern im SELECT. Lass
mal den TKPROF mitlaufen und schau Dir die Kosten an.

SELECT ist unproblemeatisch und findet im getesteten Szenario gar nicht statt (kommst im nächsten Schritt dazu). Aktuell sind es über 100 Schreib-Zugriffe pro Sekunde auf diese Tabelle.

Gruß Markus

Hallo,

da bleibt Dir wohl nichts anderes als eine temporäre Tabelle übrig. Auf die können doch alle Benutzer zugreifen. Kannst Du den Zugriff nicht so gestalten, das dieser immer in einer Session passiert?

Ich bin aber trotzdem nicht ganz überzeugt: 100 Schreibzugriffe / Sekunde sind doch lächerlich wenig. Lass es 1000 sein. Wenn jede Zeile 100 Byte Daten enthält, dann hast Du 100 kByte/sec. Selbst mit einem gewissen Overhead durch die Log-Dateien erscheint mir das seltsam.

Ich hatte mal ähnliche Symptome bei einem Join. 2 Minuten auf der Festplatte. Nach der Optimierung - mehrere Tage hats gedauert und dann waren es 3 Zeilen - waren es nur noch Sekundenbruchteile.

Du könntest ausprobieren, inwieweit Du in einem Package eine globale Tabellenwertige Variable anlegen kannst. (Ich weiss aber nicht, ob das für andere Benutzer sichtbar gemacht werden kann und wie lange die Daten darin leben.) Experimentier mal.

Vielleicht kann dir Thomas Kyte von Oracle weiterhelfen. Den findest Du unter http://asktom.oracle.com.

Hallo,

da bleibt Dir wohl nichts anderes als eine temporäre Tabelle
übrig. Auf die können doch alle Benutzer zugreifen. Kannst Du
den Zugriff nicht so gestalten, das dieser immer in einer
Session passiert?

Leider nicht, da eine Reihe von Applikationen auf diese Tabelle zugreifen, es kommen Connection-Pools zu Einsatz. Vielleicht kann ich die temp. Tabelle in eine andere Instanz verlegen, so dass der Zugriff transparent über einen link erfolgt.

Ich bin aber trotzdem nicht ganz überzeugt: 100
Schreibzugriffe / Sekunde sind doch lächerlich wenig. Lass es
1000 sein. Wenn jede Zeile 100 Byte Daten enthält, dann hast
Du 100 kByte/sec. Selbst mit einem gewissen Overhead durch die
Log-Dateien erscheint mir das seltsam.

Grundsätzlich schafft die DB die antworten ja auch, allerdings sind die Antwortzeiten zu lang. Das ganze spielt sich im Bereich einiger hundert ms ab, Laufzeiten auf dem Netz spielen hier bereits mit ein.

Du könntest ausprobieren, inwieweit Du in einem Package eine
globale Tabellenwertige Variable anlegen kannst. (Ich weiss
aber nicht, ob das für andere Benutzer sichtbar gemacht werden
kann und wie lange die Daten darin leben.) Experimentier mal.

Ich werde diesen Ansatz weiterverfolgen.

Vielleicht kann dir Thomas Kyte von Oracle weiterhelfen. Den
findest Du unter http://asktom.oracle.com.

Danke für den Tipp!

Gruß Markus