STATIC SQL vs DYNAMIC SQL with BIND Variables - ORACLE

A STATIC SQL vs DYNAMIC SQL with BIND Variables in Oracle

March 27, 2023
Oracle DBA
oracle dba oracle database management database management system database oracle performance tuning oracle sql learn sql learn personal injury attorney new york mesothelioma lawyers mesothelioma lawyers new york mesothelioma lawyer the stock market plumbing retirement planning barclays stock broker financial advisor personal retirement financial advisor

Not long ago I did note that quite many developers are using in Oracle database packages SQL statements as the dynamic SQL. They have learned in somewhere that the bind variables will make the query run faster and save some perfomance. To make clear some basics about Oracle database I wrote the following examples. Please don’t understand me incorrectly the bind variables are fast with dynamic SQL but only in external programming languages like ProC, C or Java. To store your code into a database the dynamic SQL is needed only in some extreme circumnstanses. To keep your queries as a static way in your prodecures and packages will save the compiling time before executing and any missing column or table will be raised as an Oracle exception during you are compiling the code.

To make sure all SQL queries have the same “starting point” and none of them will be cached empty the share_pool. Do it before running any of the following queries. You may need to use your SYS user to execute it.

 ALTER SYSTEM FLUSH SHARED_POOL;

oracle dba oracle system database management database management system oracle performance tuning oracle dynamic sql oracle dynamic sql in oracle sql dynamic oracle sql dynamic in oracle sql oracle bind sql bind sql oracle bind sql in oracle sql bind oracle sql bind in oracle sql database learn sql learn database retirement planning retirement oracle bind variables bind oracle execute dynamic sql execute oracle

The first PL/SQL anonymous block will be executed 50000 times with SQL query “SELECT rownum INTO v_cnt FROM dual WHERE rownum = 1;” and to make sure we will get the closest timing we will execute the block 5 times. To measure the execution time we are using SYSDATE and not some fancy procedure that can have bugs. In other words we will keep the block as simple as possible.

DECLARE 
  v_starttime DATE; 
  v_endtime DATE; 
BEGIN 
  v_starttime := SYSDATE; 
  FOR i IN 1..50000 
  LOOP 
    DECLARE 
     v_cnt PLS_INTEGER; 
    BEGIN 
      SELECT rownum 
        INTO v_cnt 
        FROM dual 
       WHERE rownum = 1; 
    END; 
  END LOOP; 
  v_endtime := SYSDATE; 

  dbms_output.put_line('time in seconds:'||((v_endtime - v_starttime) * 86400)); 
END;

oracle dba oracle system database management database management system oracle performance tuning oracle dynamic sql oracle dynamic sql in oracle sql dynamic oracle sql dynamic in oracle sql oracle bind sql bind sql oracle bind sql in oracle sql bind oracle sql bind in oracle sql database learn sql learn database retirement planning retirement oracle bind variables bind oracle execute dynamic sql execute oracle

The output shows execution time in seconds as 4, 4, 4, 5 and 4 and that makes in average total: 4.2.

The second code is written as a dynamic SQL query without the bind variables and we will execute the same statement as above.

DECLARE 
  v_starttime DATE; 
  v_endtime DATE; 
BEGIN 
  v_starttime := SYSDATE; 
  FOR i IN 1..50000 
  LOOP 
    EXECUTE IMMEDIATE 'DECLARE v_cnt PLS_INTEGER;  
                       BEGIN SELECT rownum 
                               INTO v_cnt 
                               FROM dual 
                              WHERE rownum = '|| 1 ||';  
                       END;'; 
  END LOOP; 
  v_endtime := SYSDATE; 

  dbms_output.put_line('time in seconds:'||((v_endtime - v_starttime) * 86400)); 
END;

oracle dba oracle system database management database management system oracle performance tuning oracle dynamic sql oracle dynamic sql in oracle sql dynamic oracle sql dynamic in oracle sql oracle bind sql bind sql oracle bind sql in oracle sql bind oracle sql bind in oracle sql database learn sql learn database retirement planning retirement oracle bind variables bind oracle execute dynamic sql execute oracle

The SQL output is very different from the first anonymous block and the times are 9, 9, 10, 9 and 9. That makes the average total: 9.2.

The third anonymous block is a dynamic sql with the bind variables and the query statement is same as previous examples.

DECLARE 
  v_starttime DATE; 
  v_endtime DATE; 

BEGIN 
  v_starttime := SYSDATE; 
  FOR i IN 1..50000 
  LOOP 
    DECLARE 
      v_cnt PLS_INTEGER; 
    BEGIN 
      EXECUTE IMMEDIATE 'SELECT rownum 
                           FROM dual 
                          WHERE rownum = :v' INTO v_cnt USING 1; 
    END; 
  END LOOP; 
  v_endtime := SYSDATE; 

  dbms_output.put_line('time in seconds:'||((v_endtime - v_starttime) * 86400)); 
END;

oracle dba oracle system database management database management system oracle performance tuning oracle dynamic sql oracle dynamic sql in oracle sql dynamic oracle sql dynamic in oracle sql oracle bind sql bind sql oracle bind sql in oracle sql bind oracle sql bind in oracle sql database learn sql learn database retirement planning retirement oracle bind variables bind oracle execute dynamic sql execute oracle

The third output shows 4, 5, 4, 4 and 5 and the average is 4.4. The last average is not so far from the first anonymous block with a static SQL but still in long run it will make some difference and even less sense makes to write all your queries dynamically into the database procedures or packages.

The following group of examples are done with Oracle INSERT statement and to try them on your database you would need to create a new table so it wouldn’t break anything existsing.

 CREATE TABLE my_oracle_test 
   (id   NUMBER(17) NOT NULL,  
    text VARCHAR2(2000));

oracle dba oracle system database management database management system oracle performance tuning oracle dynamic sql oracle dynamic sql in oracle sql dynamic oracle sql dynamic in oracle sql oracle bind sql bind sql oracle bind sql in oracle sql bind oracle sql bind in oracle sql database learn sql learn database retirement planning retirement oracle bind variables bind oracle execute dynamic sql execute oracle

The first insert is done to make sure the table has needed tablespace size taken and the INSERT statements would NOT loose any time by extending the tablespace. Once the insert is done we will delete all lines using TRUNCATE TABLE command and don’t worry about the COMMIT the TRUNCATE TABLE statement does commit.

BEGIN 

FOR i IN 1..150000 
LOOP 
  INSERT INTO my_oracle_test (id, text) 
  VALUES (i, 'This is My Row '||i); 
END LOOP;

END; 
/

TRUNCATE TABLE my_oracle_test;

oracle dba oracle system database management database management system oracle performance tuning oracle dynamic sql oracle dynamic sql in oracle sql dynamic oracle sql dynamic in oracle sql oracle bind sql bind sql oracle bind sql in oracle sql bind oracle sql bind in oracle sql database learn sql learn database retirement planning retirement oracle bind variables bind oracle execute dynamic sql execute oracle

Now we are ready to execute the first INSERT examples and this is static SQL inserting into just created my_oracle_test table and it does it 150000 times. We are keep measuring the time as on the example above and after the anonymous block is done it will truncate the table data. Once again I am running the test 5 times to get the average time.

DECLARE 
  v_starttime DATE; 
  v_endtime DATE; 
BEGIN 
  v_starttime := SYSDATE; 
  FOR i IN 1..150000 
  LOOP 
    INSERT INTO my_oracle_test (id, text) 
         VALUES (i, 'This is My Row '||i); 
  END LOOP; 
  v_endtime := SYSDATE; 

  dbms_output.put_line('time in seconds:'||((v_endtime - v_starttime) * 86400)); 
END; 
/ 

TRUNCATE TABLE my_oracle_test;

oracle dba oracle system database management database management system oracle performance tuning oracle dynamic sql oracle dynamic sql in oracle sql dynamic oracle sql dynamic in oracle sql oracle bind sql bind sql oracle bind sql in oracle sql bind oracle sql bind in oracle sql database learn sql learn database retirement planning retirement oracle bind variables bind oracle execute dynamic sql execute oracle

The output shows 15.99, 16.99, 14.99, 15.99 and 16.99 and that makes the average 16.19.

The second INSERT anonymous block is with a dynamic SQL and WITHOUT the bind variables. The insert statement will stay the same and we will do truncate on the rows after the block is done.

DECLARE 
  v_starttime DATE; 
  v_endtime DATE; 
BEGIN 
  v_starttime := SYSDATE; 
  FOR i IN 1..150000 
  LOOP 
    EXECUTE IMMEDIATE 'INSERT INTO my_oracle_test (id, text) 
                       VALUES ('||i||', ''This is My Row ''||'||i||')'; 
  END LOOP; 
  v_endtime := SYSDATE; 

  dbms_output.put_line('time in seconds:'||((v_endtime - v_starttime) * 86400)); 
END; 
/ 

TRUNCATE TABLE my_oracle_test;

oracle dba oracle system database management database management system oracle performance tuning oracle dynamic sql oracle dynamic sql in oracle sql dynamic oracle sql dynamic in oracle sql oracle bind sql bind sql oracle bind sql in oracle sql bind oracle sql bind in oracle sql database learn sql learn database retirement planning retirement oracle bind variables bind oracle execute dynamic sql execute oracle

The second insert is way slower than the static SQL and the times are 107, 107, 105, 105 and 105. The average in seconds is 105.8.

The third INSERT is a dynamic SQL and with the bind variables. The rest of code has left as on the previous INSERT examples above.

DECLARE 
  v_starttime DATE; 
  v_endtime DATE; 
BEGIN 
  v_starttime := SYSDATE; 
  FOR i IN 1..150000 
  LOOP 
    EXECUTE IMMEDIATE 'INSERT INTO my_oracle_test (id, text) 
                       VALUES (:v, ''This is My Row ''||:v)' using i, i; 
  END LOOP; 
  v_endtime := SYSDATE; 

  dbms_output.put_line('time in seconds:'||((v_endtime - v_starttime) * 86400)); 
END; 
/ 

TRUNCATE TABLE my_oracle_test;

oracle dba oracle system database management database management system oracle performance tuning oracle dynamic sql oracle dynamic sql in oracle sql dynamic oracle sql dynamic in oracle sql oracle bind sql bind sql oracle bind sql in oracle sql bind oracle sql bind in oracle sql database learn sql learn database retirement planning retirement oracle bind variables bind oracle execute dynamic sql execute oracle

The SQL output shows times as 15.99, 16.99, 16.99, 15.99 and 15.99. The average is 16.36 and again the timing is not so far from the static SQL (16.19) but we cannot say that a dynamic SQL with the bind variables is quicker than a static SQL.

In short, you should keep your code in database as static and don’t write it as dynamic unless this is something extreme and can’t be written any other way. When you are using C or Java application USE bind variables calling out the database procedure or in SQL queries.



See Also:
Oracle Select Oracle Substr Oracle Instr Home