Ich will nicht behaupten, dass es mich tief erschüttert hätte, dass
Tom Kyte vor einigen Tagen eine Auszeit angekündigt und seine AskTom-Seite an Chris Saxon und Connor McDonald übergeben hat - aber völlig unberührt gelassen, hat es mich jedenfalls nicht. Meine Beschäftigung mit Oracle-Datenbanken hat im Jahr 2000 begonnen und AskTom war gerade in den ersten Jahren der Ort, an dem ich nach Erklärungen suchte für alle Verhaltensweisen des RDBMS, die ich nicht verstanden hatte - und das waren zunächst ziemlich viele. Die Bücher, die der Herr Kyte im Lauf der Jahre veröffentlicht hat, stehen immer in Griffweite im Regal und obwohl ich AskTom in den letzten Jahren nur noch selten besucht habe - unter anderem, weil die interessanten Threads irgendwann unendlich lang wurden - bedauere ich Toms Abschied; und freue mich andererseits darüber, dass er plant, weitere Bücher zu schreiben, und dass er so kompetente Nachfolger für die Weiterführung von AskTom gefunden hat.
Was mich zum eigentlichen Thema bringt: in seinem eigenen Blog (den ich auch seit vielen Jahren verfolge) hat
Connor McDonald (von dem hier auch noch irgendwo ein Buch steht) vor kurzem einen Artikel zu einem interessanten neuen Feature in 12c veröffentlicht: dem SQL Loader Express. Dieser leistet etwas ganz Simples: er erlaubt ein vereinfachtes Einlesen von csv-Dateien - ein Feature, das mir bei Oracle seit vielen Jahren gefehlt hat, weil dieses Einlesen in anderen RDBMS schon seit langer Zeit sehr viel einfacher durchzuführen war. Dazu ein minimales Beispiel (das noch deutlich minimaler ist als das des Herrn McDonald und die entsprechenden Erläuterungen des von ihm verlinkten White Paper):
-- csv-Datei emp.txt mit folgenden Daten
7902,FORD,ANALYST
7844,TURNER,SALESMAN
7788,SCOTT,ANALYST
7654,MARTIN,SALESMAN
7566,JONES,MANAGER
7369,SMITH,CLERK
7876,ADAMS,CLERK
7900,JAMES,CLERK
7698,BLAKE,MANAGER
7782,CLARK,MANAGER
7521,WARD,SALESMAN
7934,MILLER,CLERK
7499,ALLEN,SALESMAN
7839,KING,PRESIDENT
-- Anlage einer entsprechenden Tabelle emp im Schema test
create table emp(
empno number(4,0),
ename varchar2(10),
job varchar2(9)
);
-- Aufruf des sqlldr im Verzeichnis, in dem sich die csv-Datei befindet
sqlldr userid=test/test data=emp.txt table=emp
SQL*Loader: Release 12.1.0.2.0 - Production on Fri Oct 3 00:57:18 2014
Copyright (c) 1982, 2014, Oracle and/or its affiliates. All rights reserved.
Express Mode Load, Table: EMP
Path used: External Table, DEGREE_OF_PARALLELISM=AUTO
Table EMP:
14 Rows successfully loaded.
Check the log files:
emp.log
emp_%p.log_xt
for more information about the load.
Das zugehörige Log zeigt sehr detailliert, was im Hintergrund geschieht:
Express Mode Load, Table: EMP
Data File: emp.txt
Bad File: emp_%p.bad
Discard File: none specified
(Allow all discards)
Number to load: ALL
Number to skip: 0
Errors allowed: 50
Continuation: none specified
Path used: External Table
Table EMP, loaded from every logical record.
Insert option in effect for this table: APPEND
Column Name Position Len Term Encl Datatype
------------------------------ ---------- ----- ---- ---- ---------------------
EMPNO FIRST * , CHARACTER
ENAME NEXT * , CHARACTER
JOB NEXT * , CHARACTER
Generated control file for possible reuse:
OPTIONS(EXTERNAL_TABLE=EXECUTE, TRIM=LRTRIM)
LOAD DATA
INFILE 'emp.txt'
APPEND
INTO TABLE EMP
FIELDS TERMINATED BY ","
(
EMPNO,
ENAME,
JOB
)
End of generated control file for possible reuse.
created temporary directory object SYS_SQLLDR_XT_TMPDIR_00000 for path /home/oracle
enable parallel DML: ALTER SESSION ENABLE PARALLEL DML
creating external table "SYS_SQLLDR_X_EXT_EMP"
CREATE TABLE "SYS_SQLLDR_X_EXT_EMP"
(
"EMPNO" NUMBER(4),
"ENAME" VARCHAR2(10),
"JOB" VARCHAR2(9)
)
ORGANIZATION external
(
TYPE oracle_loader
DEFAULT DIRECTORY SYS_SQLLDR_XT_TMPDIR_00000
ACCESS PARAMETERS
(
RECORDS DELIMITED BY NEWLINE CHARACTERSET US7ASCII
BADFILE 'SYS_SQLLDR_XT_TMPDIR_00000':'emp_%p.bad'
LOGFILE 'emp_%p.log_xt'
READSIZE 1048576
FIELDS TERMINATED BY "," LRTRIM
REJECT ROWS WITH ALL NULL FIELDS
(
"EMPNO" CHAR(255),
"ENAME" CHAR(255),
"JOB" CHAR(255)
)
)
location
(
'emp.txt'
)
)REJECT LIMIT UNLIMITED
executing INSERT statement to load database table EMP
INSERT /*+ append parallel(auto) */ INTO EMP
(
EMPNO,
ENAME,
JOB
)
SELECT
"EMPNO",
"ENAME",
"JOB"
FROM "SYS_SQLLDR_X_EXT_EMP"
dropping external table "SYS_SQLLDR_X_EXT_EMP"
Table EMP:
14 Rows successfully loaded.
Demnach umfasst die Operation folgende Schritte:
- Generierung eines wiederverwendbaren sqlldr control files.
- Erzeugung eines temporären directories für das Verzeichnis, in dem die csv-Datei liegt und in dem der sqlldr-Aufruf erfolgte.
- Aktivierung von parallel dml für die Session.
- Anlage einer external table basierend auf der Struktur der csv-Datei.
- parallelisiertes Insert Append zur Übertragung der Daten der External Table in die Zieltabelle.
- Drop der External Table.
Das Verfahren erspart eine Menge Definitionsaufwand und kann als External Table Generator verwendet werden (wie David Aldridge in seinem Kommentar bemerkt).
Nachtrag 14.09.2015: offenbar auch wieder ein Thema, das aktuell ein gewisses Interessae hervorruft - jedenfalls hat auch
Oren Nakdimon ein schönes entsprechendes Beispiel veröffentlicht.