Frage Oracle SQL: Was ist das Verhalten von SYS_GUID () in einer Inline-Ansicht?


Hier ist das Beispiel SQL in Frage; Die SQL sollte auf jedem Oracle DBMS laufen (ich verwende 11.2.0.2.0).

Beachten Sie, dass die UUID-Werte in der Ergebnismenge unterschiedlich sind (die eine hat 898, die andere 899), obwohl sie aus der Inline-View / with-Klausel heraus erstellt wurde. Weiter unten können Sie sehen, wie DBMS_RANDOM.RANDOM () diesen Nebeneffekt nicht hat.

SQL:

WITH data AS (SELECT SYS_GUID () uuid FROM DUAL)
    SELECT uuid, uuid
      FROM data

Ausgabe:

UUID                                      UUID_1
F8FCA4B4D8982B55E0440000BEA88F11      F8FCA4B4D8992B55E0440000BEA88F11

Im Gegensatz DBMS_RANDOM  Die Ergebnisse sind gleich

SQL:

WITH data AS (SELECT DBMS_RANDOM.RANDOM() rand FROM DUAL)
SELECT rand, rand
  FROM data

Ausgabe:

RAND    RAND_1
92518726    92518726

Noch interessanter ist, ich kann das Verhalten ändern / stabilisieren sys_guid durch Aufrufe von DBMS_RANDOM.RANDOM:

WITH data AS (
        SELECT SYS_GUID () uuid, 
        DBMS_RANDOM.random () rand 
        FROM DUAL)
SELECT uuid a,
       uuid b,
       rand c,
       rand d
  FROM data

SQL Fiddle, das SYS_GUID stabilisiert: http://sqlfiddle.com/#!4/d41d8/29409

SQL Fiddle Zeigt das seltsame Verhalten von SYS_GUID: http://sqlfiddle.com/#!4/d41d8/29411


18
2018-05-09 19:36


Ursprung


Antworten:


Das Dokumentation gibt einen Grund warum Sie eine Diskrepanz sehen können (Hervorhebung von mir):

Vorsicht:

Da SQL eine deklarative Sprache ist und nicht zwingend (oder prozedural), Sie können nicht wissen, wie oft eine von einer SQL-Anweisung aufgerufene Funktion ausgeführt wird- auch wenn die Funktion in PL / SQL geschrieben ist, einer imperativen Sprache.   Wenn Ihre Anwendung erfordert, dass eine Funktion eine bestimmte Anzahl von Malen ausgeführt wird, rufen Sie diese Funktion nicht aus einer SQL-Anweisung auf. Verwenden Sie stattdessen einen Cursor.

Wenn Ihre Anwendung beispielsweise erfordert, dass für jede ausgewählte Zeile eine Funktion aufgerufen wird, öffnen Sie einen Cursor, wählen Sie Zeilen aus dem Cursor aus und rufen Sie die Funktion für jede Zeile auf. Diese Technik garantiert, dass die Anzahl der Aufrufe der Funktion die Anzahl der vom Cursor abgerufenen Zeilen ist.

Grundsätzlich gibt Oracle nicht an, wie oft eine Funktion innerhalb einer SQL-Anweisung aufgerufen wird: Sie hängt unter Umständen von der Version, der Umgebung, dem Zugriffspfad und anderen Faktoren ab.

Es gibt jedoch Möglichkeiten, das Umschreiben von Abfragen zu beschränken, wie im Kapitel erläutert Unnested von verschachtelten Unterabfragen:

Unterabfragen werden nicht verschachtelt und der Rumpf der Unterabfrage wird in den Hauptteil der Anweisung, die ihn enthält, zusammengeführt, sodass der Optimierer sie bei der Auswertung von Zugriffspfaden und Joins zusammen berücksichtigen kann. Der Optimierer kann die meisten Unterabfragen neu definieren. mit einigen Ausnahmen. Zu diesen Ausnahmen gehören hierarchische Unterabfragen und Unterabfragen, die eine ROWNUM-Pseudospalte, einen der Mengenoperatoren, eine verschachtelte Aggregatfunktion oder eine korrelierte Referenz auf einen Abfrageblock enthalten, der nicht der unmittelbare äußere Abfrageblock der Unterabfrage ist.

Wie oben erläutert, können Sie verwenden ROWNUM Pseudospalte, um zu verhindern, dass Oracle eine Unterabfrage nesting:

SQL> WITH data AS (SELECT SYS_GUID() uuid FROM DUAL WHERE ROWNUM >= 1)
  2  SELECT uuid, uuid FROM data;

UUID                             UUID
-------------------------------- --------------------------------
1ADF387E847F472494A869B033C2661A 1ADF387E847F472494A869B033C2661A

6
2018-05-14 14:52



Der NO_MERGE-Hinweis "behebt" es. Verhindert, dass Oracle die Inline-Ansicht neu schreibt.

WITH data AS (SELECT /*+ NO_MERGE */
                    SYS_GUID () uuid FROM DUAL)
SELECT uuid, uuid
  FROM data

Aus den Dokumenten:

Der NO_MERGE-Hinweis weist den Optimierer an, die äußere Verknüpfung nicht zu kombinieren   Abfrage und alle Inline-View-Abfragen in einer einzigen Abfrage. Dieser Hinweis lässt   Sie haben mehr Einfluss auf den Zugriff auf die Ansicht.

SQL Fiddle mit dem NO_MERGE-Hinweis angewendet:

Ich habe immer noch Schwierigkeiten zu verstehen, wie die Abfrage so umgeschrieben wird, dass sys_guid() würde zweimal angerufen werden. Vielleicht ist es ein Fehler; aber ich neige dazu anzunehmen, dass es ein Fehler in meinen eigenen Gedanken / Code ist.


2
2018-05-12 18:52



Sehr interessant.

Wir können den materialize-Hinweis verwenden, um es zu beheben.

WITH data AS (SELECT /*+materialize*/SYS_GUID () uuid FROM DUAL)
    SELECT uuid, uuid
      FROM data;

1   F9440E2613761EC8E0431206460A934C    F9440E2613761EC8E0431206460A934C

Aus meiner Sicht, wenn wir das Ergebnis einer Abfrage nur durch Hinzufügen eines Hinweises ändern können, gibt es einen Oracle-Fehler. Vielleicht müssen wir Metalink darum bitten, es zu überprüfen ...


2
2018-05-13 14:41