29. Oktober 2007

XML Dokumente speichern: Ein Blick unter die Motorhaube ...

Nun, woher kommen die Unterschiede bei Performance- und Speicherverbrauch?
Je nachdem, welche Speicherungsform man wählt, hat die Datenbank unterschiedliche Informationen über die XML-Strukturen. Bei der objektrelationalen Speicherungsform werden die XML-Dokumente als Objekte abgelegt - der Datenbank sind die XML-Strukturen also bekannt und sie kann diese zur Abfrageoptimierung nutzen. Erfolgt nun eine XML-Abfrage auf eine solche Tabelle, so schreibt die Datenbank diese Abfrage vor Ausführung um (Query Rewrite). Tatsächlich ausgeführt wird eine andere Abfrage - und dies lässt sich nachvollziehen.
Übrigens: Mit dem Query Rewrite für Materialized Views oder Function Based Indizes hat dieses XML Query Rewrite nichts zu tun - es wird daher auch keine besondere Init-Parameter-Einstellung und auch kein Systemprivileg (QUERY REWRITE) benötigt.
Zunächst schauen wir uns die Abfrage auf die Tabelle mit objektrelationaler Speicherung an:
select 
  extractvalue(object_value, '/test-xml/name/text()') as kunde_name,
  extractvalue(object_value, '/test-xml/datum/text()') as kauf_datum,
  extractvalue(value(st), '/stueck/id/text()') as stueck_id
from xml_or,
  table(xmlsequence(extract(object_value, '/test-xml/gekaufte-stuecke/stueck'))) (+)  st
Daraus macht die Datenbank vor Ausführung in etwa sowas hier ...
SELECT 
  "SYS_ALIAS_1"."SYS_NC00009$" "KUNDE_NAME",
  "SYS_ALIAS_1"."SYS_NC00008$" "KAUF_DATUM",
  SYS_OP_ATG( [...] ) "STUECK_ID" 
FROM 
  "SCOTT"."XML_OR" "SYS_ALIAS_1",
  TABLE( [...] )
Die Datenbank verwendet also in Wirklichkeit SYS_NC...-Spalten; de-facto wird eine relationale Abfrage ausgeführt. Die EXTRACTVALUE-Funktionen und die XPath-Ausdrücke sind komplett verschwunden - daher wird auch kein XML-Parsing mehr ausgeführt. Das liegt daran, dass die XML-Dokumente tatsächlich als Objekte und diese wiederum in normalen, relationalen Tabellenspalten abgelegt werden. Die Oracle-Datenbank beachtet dabei allerdings alle XML-Besonderheiten, so dass sich die Oracle XML DB doch massiv von einem "naiven XML-Nach-Relational-Mapping" unterscheidet. Schauen wir uns im Gegensatz dazu nun die Abfrage auf die textbasiert gespeicherten Dokumente an. Hierbei kann kein Query Rewrite stattfinden - die Datenbank hat gar keine Objektstrukturen und damit auch keine SYS_NC...-Spalten, mit deren Hilfe die Abfrage optimiert werden könnte. Tatsächlich ausgeführt wird also ...
SELECT 
  EXTRACTVALUE(SYS_MAKEXML("XML_TEXT"."XMLDATA"),'/test-xml/name/text()') "KUNDE_NAME",
  EXTRACTVALUE(SYS_MAKEXML("XML_TEXT"."XMLDATA"),'/test-xml/datum/text()') "KAUF_DATUM",
  EXTRACTVALUE(VALUE(K),'/stueck/id/text()') "STUECK_ID"
 FROM 
  "SCOTT"."XML_TEXT" "XML_TEXT",
  TABLE(
   "SYS"."XMLSEQUENCE"(
     EXTRACT(
      SYS_MAKEXML("XML_TEXT"."XMLDATA"),
      '/test-xml/gekaufte-stuecke/stueck'
     )
   )
  ) "K"
... was der Originalabfrage entspricht. Zur Erinnering: Die sah so aus:
select
  extractvalue(object_value, '/test-xml/name/text()') as kunde_name,
  extractvalue(object_value, '/test-xml/datum/text()') as kauf_datum,
  extractvalue(value(st), '/stueck/id/text()') as stueck_id
from xml_text,
  table(xmlsequence(extract(object_value, '/test-xml/gekaufte-stuecke/stueck'))) (+) st
Die EXTRACTVALUE-Funktionen sind noch da - bei Ausführung der Abfrage findet also ein XML Parsing statt, was die Performance und den Speicherverbrauch (letzter Post) erkärt. Schauen wir uns nun noch die in Oracle11g neue Speicherungsform Binary XML an. Zunächst die Original-Abfrage ...
select
  extractvalue(object_value, '/test-xml/name/text()') as kunde_name,
  extractvalue(object_value, '/test-xml/datum/text()') as kauf_datum,
  extractvalue(value(st), '/stueck/id/text()') as stueck_id
from xml_binary,
  table(xmlsequence(extract(object_value, '/test-xml/gekaufte-stuecke/stueck'))) (+) st
Daraus macht die Datenbank im Rahmen des Query Rewrite in etwa dies hier:
SELECT 
  SYS_XMLTYPE2SQL("P"."C_02$") "KUNDE_NAME",
  SYS_XMLTYPE2SQL("P"."C_01$") "KAUF_DATUM",
  SYS_XMLTYPE2SQL("P1"."C_01$") "STUECK_ID" 
FROM 
  "SCOTT"."XML_BINARY" "XML_BINARY",
  XPATHTABLE( [...] ) "P",
  XPATHTABLE( [...] ) "P1"
Auch hier verschwinden die EXTRACTVALUE-Funktionen vollständig. Die durch Query Rewrite veränderte Query führt ebenfalls kein XML-Parsing mehr durch, vielmehr nutzt sie die im binären XML enthaltenen Strukturinformationen zur Ausführung und erreicht so eine bessere Performance. Spitzenreiter ist jedoch, wie im letzten Post schon festgestellt, die objektrelationale Variante. Wie man dies auch mit Ausführungsplänen feststellen kann und was das für die Indizierung von XML bedeutet ... Stay tuned!

Keine Kommentare:

Beliebte Postings