25. Oktober 2013

JSON und die Oracle-Datenbank ...? Mehr auf der DOAG2013!

This event is about the DOAG2013, a german-language conference and therefore in german only.
Heute geht es nochmal um die in etwa 4 Wochen stattfindende DOAG-Konferenz. Seit heute steht fest, dass auf der DOAG2013 ein hochinteressanter Vortrag stattfinden wird, den ich der Entwicklercommunity hiermit wärmstens ans Herz legen möchte: JSON and the Oracle Database: Storage, Query and more ... von Mark Drake, Produktmanager für die Oracle XML DB aus den USA.
Im Vortrag, der am ersten Konferenztag (19.11.2013) um 12:00 Uhr im Raum "Hong Kong" stattfindet, geht es um neueste Entwicklungen und Pläne des Development-Teams für das native Zusammenspiel von JSON und der Oracle-Datenbank. Auf der diesjährigen Oracle Open World war SQL/JSON ebenfalls ein Thema, wie man im Blog Posting von Marco Gralike nachlesen kann. Wer also wissen möchte, was sich bei JSON und der Oracle-Datenbank tun wird ... DOAG2013.

23. Oktober 2013

Webseminare im Herbst und ... DOAG2013!

This blog posting is about upcoming events in German language and therefore in German only.
Der Herbst ist, wie jedes Jahr, die Zeit der Veranstaltungen. Hier ist eine kleine Zusammenstellung der in Kürze stattfindenden Veranstaltungen, an denen ich mitwirken darf ...
  • Das Thema HTML5 tritt bei meiner Arbeit mit APEX- und PL/SQL Kunden immer häufiger auf. Und die Möglichkeiten, die sich mit HTML5 für die Gestaltung von Webanwendungen ergeben, sind in der Tat sehr vielfältig und interessant. Daher führe ich am 8. November 2013 um 11:00 Uhr ein Webseminar zum Thema APEX und HTML5: Anwendungen der nächsten Generation durch. Im Webseminar werde ich vorstellen, welche Features des HTML5 Standards sich in APEX recht einfach und schnell nutzen lassen. Die Teilnahme ist kostenlos - mehr Informationen finden sich hier.
  • Dass die Oracle-Datenbank gerade dem Entwickler mehr bietet als Tabellen, SELECT- und DML-Operationen, ist doch den meisten bekannt. Aber den kompletten Überblick über die Möglichkeiten, Dinge direkt in der Datenbank zu erledigen, zu behalten, ist extrem schwierig. Ein wenig dabei helfen soll das Webseminar Datenbankfunktionen für PL/SQL und APEX-Entwickler: Inkl. Oracle12c Update am 4. Dezember 2013, ebenfalls um 11:00 Uhr.
  • Schon nächste Woche, am 30. Oktober 2013, stellt mein Kollege die seit kurzer Zeit verfügbare APEX-Anwendung für das Self Service Provisioning von Oracle12c Pluggable Databases vor. Es gibt einen Überblick über das neue Oracle12c Multitenant Feature und einen Einblick in die Self-Service Applikation, die übrigens auch aus dem OTN heruntergeladen werden kann.
Und wie jedes Jahr findet am 19. bis zum 21. November die DOAG2013 statt. Dort werde ich ebenfalls mit Vorträgen vertreten sein. Und ich freue mich jetzt schon auf das Wiedersehen, die Gespräche und den Austausch mit der Community.

7. Oktober 2013

Oracle12c: Identity Columns und Sequence By Default

Oracle12c Identity Columns and Sequence By Default
Heute geht es nochmals um ein neues Feature in Oracle 12.1: Die neue Datenbankversion bringt neue Möglichkeiten mit, eine Primärschlüsselspalte automatisch mit Werten zu befüllen. Bislang blieb einem da nur das manuelle Erzeugen einer Sequence und eines Triggers, wie folgt.
create table tab_trigger_sql(
  id    number 
)
/

create sequence seq_trigger_sql
/

create trigger tr_trigger_sql 
before insert on tab_trigger_sql
for each row
begin
  select seq_trigger_sql.nextval into :new.id from dual;
end;
/
sho err
Oracle11g erlaubte es dann, das select ... into im Trigger durch eine einfache PL/SQL-Zuweisung zu ersetzen - schneller war das aber, wie wir noch sehen werden, eigentlich nicht; sieht im Code aber zumindest besser aus.
create table tab_trigger_plsql(
  id    number 
)
/

create sequence seq_trigger_plsql
/

create trigger tr_trigger_plsql 
before insert on tab_trigger_plsql
for each row
begin
  :new.id := seq_trigger_plsql.nextval;
end;
/
sho err
Ab Oracle 12.1 kann man die Sequence der Tabellenspalte als Default zuweisen. Der Trigger fällt weg.
create sequence seq_default
/

create table tab_default(
  id    number default seq_default.nextval
)
/
Wie immer, gibt das Data Dictionary Auskunft über den hinterlegten Default.
SQL> select column_name, data_default from user_tab_columns where table_name='TAB_DEFAULT'

COLUMN_NAME     DATA_DEFAULT
--------------- ----------------------------------------
ID              "IDENT"."SEQ_DEFAULT"."NEXTVAL"
Noch weiter geht das Identity Column Feature. Hier wird auch die Sequence nicht mehr gebraucht - Oracle erstellt sie automatisch.
create table tab_identity(
  id number generated always as identity
)
/

create table tab_identity(
  id number generated always as identity start with 1 increment by 1 maxvalue 999999999 nocycle
)
/
Wie man sieht, wird die Definition der Sequence direkt ins CREATE TABLE Kommando übernommen - mit der bekannten Syntax werden die Details des automatisch generierten Wertes bestimmt. Identity Columns werden im Data Dictionary mit eigenen Views abgebildet.
SQL> select * from USER_TAB_IDENTITY_COLS

TABLE_NAME   COLUMN_NAME GENERATION IDENTITY_OPTIONS
------------ ----------- ---------- ------------------------------
TAB_IDENTITY ID          ALWAYS     START WITH: 1, INCREMENT BY: 1
                                    , MAX_VALUE: 999999999, MIN_VA
                                    LUE: 1, CYCLE_FLAG: N, CACHE_S
                                    IZE: 20, ORDER_FLAG: N

1 Zeile wurde ausgewählt.
Nun stellt sich natürlich die Frage, ob da nicht doch eine Sequence im Hintergrund entstanden ist .. ein Blick in USER_SEQUENCES liefert den "Anfangsverdacht" ...
 
SQL> select * from USER_SEQUENCES;

SEQUENCE_NAME    MIN_VALUE  MAX_VALUE INCREMENT_BY C O CACHE_SIZE LAST_NUMBER PARTITION_COUNT S K
--------------- ---------- ---------- ------------ - - ---------- ----------- --------------- - -
ISEQ$$_91957             1  999999999            1 N N         20           1                 N N

1 Zeile wurde ausgewählt.
.. und ein Blick in DATA_DEFAULT in USER_TAB_COLUMNS bestätigt diesen.
SQL> select table_name, column_name, data_default from user_tab_columns;

TABLE_NAME   COLUMN_NAME DATA_DEFAULT
------------ ----------- ----------------------------------------
TAB_IDENTITY ID          "IDENT"."ISEQ$$_91957".nextval

1 Zeile wurde ausgewählt.
Technisch ist eine Identity Column als eine Sequence By Default, welche jedoch im CREATE TABLE Kommando definiert und im Dictionary separat verwaltet wird. Das Erzeugen der Sequence-Objekte wird der Datenbank überlassen. Das bedeutet auch, dass die Datenbank die Sequences löscht, nachdem die Tabelle gelöscht wurde (probiert es aus). Von der Performance her sollten sich Sequences By Default und Identity Columns also ähnlich verhalten. Und einen solchen Performance-Test wollen wir nun machen - in alle vier Tabellen werden 10.000 Werte eingefügt. Die Zahlen hängen natürlich stark vom verwendeten System ab - aber eine Indikation bekommt man.
begin
  for i in 1..10000 loop
    insert into {table-name} values (default);
  end loop;
end;
/
Es ergeben sich folgende Zahlen ...
*** Table with Trigger and sequence assigned with SQL

PL/SQL-Prozedur erfolgreich abgeschlossen.

Abgelaufen: 00:00:09.36
*** Table with Trigger and sequence assigned with PL/SQL

PL/SQL-Prozedur erfolgreich abgeschlossen.

Abgelaufen: 00:00:10.04
*** Table with Sequence by Default feature

PL/SQL-Prozedur erfolgreich abgeschlossen.

Abgelaufen: 00:00:06.16
*** Table with Sequence by Identity Column

PL/SQL-Prozedur erfolgreich abgeschlossen.

Abgelaufen: 00:00:05.97
Im Beispiel sind die beiden Varianten mit Trigger in etwa gleich schnell. Bei wiederholten Tests ergab es sich, dass mal der Trigger mit dem SELECT ... INTO schneller war, mal war die PL/SQL Zuweisung schneller - ein klares Bild ergibt sich hier nicht. Sehr deutlich erkennbar ist jedoch der Vorteil des Sequence By Default - die Tatsache, dass kein Trigger mehr aufgerufen wird (und kein Context Switch zu PL/SQL mehr nötig ist), macht sich deutlich bemerkbar. Und wie vermutet, sind die Identity Columns in etwa ähnlich schnell ...
Alles in allem halte ich dieses neue Feature für eines, welches wohl sehr schnell adaptiert werden wird. Wer die Sequence-Objekte noch selbst kontrollieren möchte, wählt dann eher ein Sequence By Default, andere überlassen mit der Definition einer Identity Column gleich alles der Datenbank.
This blog posting is about another new Feature in Oracle 12.1: The new release allows to populate (Primary Key) columns automatically. In the past, we needed to create explicit sequence and trigger objects for this, as follows ...
create table tab_trigger_sql(
  id    number 
)
/

create sequence seq_trigger_sql
/

create trigger tr_trigger_sql 
before insert on tab_trigger_sql
for each row
begin
  select seq_trigger_sql.nextval into :new.id from dual;
end;
/
sho err
Starting with Oracle11g, it was possible to replace the select ... into statement by a simple PL/SQL assignment within the trigger. This cleans up the code, but (as we'll see) it will not run much faster.
create table tab_trigger_plsql(
  id    number 
)
/

create sequence seq_trigger_plsql
/

create trigger tr_trigger_plsql 
before insert on tab_trigger_plsql
for each row
begin
  :new.id := seq_trigger_plsql.nextval;
end;
/
sho err
The new release, Oracle 12.1, allows to assign the sequence's next value as the column default (Sequence By Default). The trigger is no longer needed.
create sequence seq_default
/

create table tab_default(
  id    number default seq_default.nextval
)
/
And as always, we can look into the data dictionary in order to get information ...
SQL> select column_name, data_default from user_tab_columns where table_name='TAB_DEFAULT'

COLUMN_NAME     DATA_DEFAULT
--------------- ----------------------------------------
ID              "IDENT"."SEQ_DEFAULT"."NEXTVAL"
The Identity Column Feature goes a step further: An explicit sequence is no longer needed - we just declare the "identity column". If needed, the sequence details can be directly added to the column definition.
create table tab_identity(
  id number generated always as identity
)
/

create table tab_identity(
  id number generated always as identity start with 1 increment by 1 maxvalue 999999999 nocycle
)
/
The syntax itself does not change: The definition, which was previously part of the CREATE SEQUENCE command, is now part of CREATE TABLE. The data dictionary contains a new view with information about identity columns.
SQL> select * from USER_TAB_IDENTITY_COLS

TABLE_NAME   COLUMN_NAME GENERATION IDENTITY_OPTIONS
------------ ----------- ---------- ------------------------------
TAB_IDENTITY ID          ALWAYS     START WITH: 1, INCREMENT BY: 1
                                    , MAX_VALUE: 999999999, MIN_VA
                                    LUE: 1, CYCLE_FLAG: N, CACHE_S
                                    IZE: 20, ORDER_FLAG: N
Of course, we now want to know, if there is kind of a "hidden" or "system" sequence object ... and after having a look into USER_SEQUENCES, there is an "initial suspicion" ...
 
SQL> select * from USER_SEQUENCES;

SEQUENCE_NAME    MIN_VALUE  MAX_VALUE INCREMENT_BY C O CACHE_SIZE LAST_NUMBER PARTITION_COUNT S K
--------------- ---------- ---------- ------------ - - ---------- ----------- --------------- - -
ISEQ$$_91957             1  999999999            1 N N         20           1                 N N
... which will be confirmed after looking into DATA_DEFAULT of USER_TAB_COLUMNS.
SQL> select table_name, column_name, data_default from user_tab_columns;

TABLE_NAME   COLUMN_NAME DATA_DEFAULT
------------ ----------- ----------------------------------------
TAB_IDENTITY ID          "IDENT"."ISEQ$$_91957".nextval
From a technical point of view, an Identity Column is a Sequence By Default. It allows to simplify DDL scripts by having the sequence details in the CREATE TABLE statement. Developers does not have to care about sequence objects any more: The database will maintain them automatically - which includes dropping them after the table has been dropped (try it). Regaring performance, both variants should behave similar - and finally we'll do a (very) simple performance test by inserting 10.000 values into the table. The exact numbers will depend on the system, but the indication we'll get, should apply in general.
begin
  for i in 1..10000 loop
    insert into {table-name} values (default);
  end loop;
end;
/
And here are the results:
*** Table with Trigger and sequence assigned with SQL

PL/SQL procedure successfully completed.

Elapsed: 00:00:09.64
*** Table with Trigger and sequence assigned with PL/SQL

PL/SQL procedure successfully completed.

Elapsed: 00:00:10.01
*** Table with Sequence by Default feature

PL/SQL procedure successfully completed.

Elapsed: 00:00:07.14
*** Table with Sequence by Identity Column

PL/SQL procedure successfully completed.

Elapsed: 00:00:05.91
In this example, the performance of the trigger variants is roughly equal. Some times the trigger with the PL/SQL assignment was faster, other times, the SELECT .. INTO was - there was no clear picture. But Identity Columns or columns having Sequence as Default are significantly faster - we can clearly see the cost of calling the Trigger and having the context switch from SQL to PL/SQL.
Summarized, I think that this new feature will be adopted rather quickly - DDL scripts can be much cleaner with Oracle12c. Those who still want to control the "number generator", can use Sequence By Default and create their sequence objects manually. The others might use Identity Columns, handing sequence maintenance completely over to the database.

Beliebte Postings