Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Oracle SQL: Understanding the behavior of SYS_GUID() when present in an inline view?

Tags:

sql

oracle

Here is the example SQL in question; The SQL should run on any Oracle DBMS (I'm running 11.2.0.2.0).

Note how the UUID values are different (one has 898 the other has 899) in the resultset despite being built from within the inline view/with clause. Further below you can see how DBMS_RANDOM.RANDOM() does not have this side effect.

SQL:

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

Output:

UUID                                      UUID_1
F8FCA4B4D8982B55E0440000BEA88F11      F8FCA4B4D8992B55E0440000BEA88F11

In Contrast DBMS_RANDOM the results are the same

SQL:

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

Output:

RAND    RAND_1
92518726    92518726

Even more interesting is I can change the behavior / stabilize sys_guid by including calls to 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 That Stabilizes SYS_GUID: http://sqlfiddle.com/#!4/d41d8/29409

SQL Fiddle That shows the odd SYS_GUID behavior: http://sqlfiddle.com/#!4/d41d8/29411

like image 588
Brian Avatar asked May 09 '14 19:05

Brian


People also ask

What is Sys_guid () function in Oracle?

SYS_GUID generates and returns a globally unique identifier ( RAW value) made up of 16 bytes. On most platforms, the generated identifier consists of a host identifier, a process or thread identifier of the process or thread invoking the function, and a nonrepeating value (sequence of bytes) for that process or thread.

What is inline view in Oracle SQL?

Answer: The inline view is a construct in Oracle SQL where you can place a query in the SQL FROM, clause, just as if the query was a table name. Oracle has long supported the notion of an 'in-line view,' whereby a subquery can be placed in the FROM clause, just as if it were a table name.

What is inline function in Oracle and its purpose?

The function is created in-line, inside the query. It takes a NUMBER as input, it returns a NUMBER and its implementation invokes a procedure to to the actual work. This procedure is also defined in-line.

What is inline view in SQL with example?

An inline view is a SELECT statement in the FROM-clause of another SELECT statement to create a temporary table that could be referenced by the SELECT statement. Inline views are utilized for writing complex SQL queries without join and subqueries operations.


2 Answers

The documentation gives a reason as to why you may see a discrepancy (emphasis mine):

Caution:

Because SQL is a declarative language, rather than an imperative (or procedural) one, you cannot know how many times a function invoked by a SQL statement will run—even if the function is written in PL/SQL, an imperative language. If your application requires that a function be executed a certain number of times, do not invoke that function from a SQL statement. Use a cursor instead.

For example, if your application requires that a function be called for each selected row, then open a cursor, select rows from the cursor, and call the function for each row. This technique guarantees that the number of calls to the function is the number of rows fetched from the cursor.

Basically, Oracle doesn't specify how many times a function will be called inside a sql statement: it may be dependent upon the release, the environment, the access path among other factors.

However, there are ways to limit query rewrite as explained in the chapter Unnesting of Nested Subqueries:

Subquery unnesting unnests and merges the body of the subquery into the body of the statement that contains it, allowing the optimizer to consider them together when evaluating access paths and joins. The optimizer can unnest most subqueries, with some exceptions. Those exceptions include hierarchical subqueries and subqueries that contain a ROWNUM pseudocolumn, one of the set operators, a nested aggregate function, or a correlated reference to a query block that is not the immediate outer query block of the subquery.

As explained above, you can use ROWNUM pseudo-column to prevent Oracle from unnesting a subquery:

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

UUID                             UUID
-------------------------------- --------------------------------
1ADF387E847F472494A869B033C2661A 1ADF387E847F472494A869B033C2661A
like image 110
Vincent Malgrat Avatar answered Oct 17 '22 04:10

Vincent Malgrat


The NO_MERGE hint "fixes" it. Prevents Oracle from re-writing the inline view.

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

From the docs:

The NO_MERGE hint instructs the optimizer not to combine the outer query and any inline view queries into a single query.This hint lets you have more influence over the way in which the view is accessed.

SQL Fiddle with the NO_MERGE hint applied:

I'm still struggling to understand/articulate how the query is being re-written in such a way that sys_guid() would be called twice. Perhaps it is a bug; but I tend to assume it is a bug in my own thoughts/code.

like image 33
Brian Avatar answered Oct 17 '22 05:10

Brian