Tuesday, August 16, 2016

Date Filters and their impact over Index

I was discussing with my friend on date filters and how they impact the performance, thought this topic is worth blogging.

 With tables holding historic data, you would see columns 'Effective Date or termination date' which would logically mark the record as inactive and also helps to pick the current active record. Again few store NULL or any futuristic date in these columns to determine the active status. Now from this perspective let us see how date formatting can impact the optimizer decisions

  Let us walk through a set of SQL which has date filters,
select * from tbl_objects where effective_end_ts > systimestamp
  
 Plan hash value: 2402742835
  
 ---------------------------------------------------------------------------------
 | Id  | Operation         | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
 ---------------------------------------------------------------------------------
 |   0 | SELECT STATEMENT  |             |       |       |   563 (100)|          |
 |*  1 |  TABLE ACCESS FULL| TBL_OBJECTS |  4454 |   695K|   563   (1)| 00:00:01 |
 ---------------------------------------------------------------------------------
  At the very first look was not convinced with the plan, because i know the total number of active records where 26721 and not 4454, so let us see what is actual and expected.
 select /*+ gather_plan_statistics */ * from tbl_objects where 
 effective_end_ts > systimestamp
  
 Plan hash value: 2402742835
  
 -------------------------------------------------------------------------------------------
 | Id  | Operation         | Name        | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
 -------------------------------------------------------------------------------------------
 |   0 | SELECT STATEMENT  |             |      1 |        |  26721 |00:00:00.14 |    2539 |
 |*  1 |  TABLE ACCESS FULL| TBL_OBJECTS |      1 |   4454 |  26721 |00:00:00.14 |    2539 |
 -------------------------------------------------------------------------------------------
 Yes the actual cardinality is 26721. Now am not going to SQL Profiles to go further to validate the plan because my first bet is always on the data,application design, the first question is why this SQL and what use the operator '>' . 

         The SQL intent is to pick active trades whose end timestamp is 01-01-9999, so let us say this to Oracle and see how this overcomes the trouble created by the operator '> systimestamp'  that is sky is the limit :)   

Now with effective end timestamp values  
select * from tbl_objects where effective_end_ts = timestamp 
'9999-01-01 00:00:00'
 
Plan hash value: 1709553517
 
---------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |             |       |       |     2 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| TBL_OBJECTS |     1 |   160 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | IDX_EFF_TS  |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
    Though the cardinality is still not right, we could see a change in the access method - index is used.

Now same query with a different date formatting
select * from tbl_objects where effective_end_ts = 
 (to_timestamp('01/01/9999 00:00:00','dd/mm/yyyy hh24:mi:ss'))
  
 Plan hash value: 1709553517
  
 ---------------------------------------------------------------------------------------------------
 | Id  | Operation                           | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
 ---------------------------------------------------------------------------------------------------
 |   0 | SELECT STATEMENT                    |             |       |       |     2 (100)|          |
 |   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| TBL_OBJECTS |     1 |   160 |     2   (0)| 00:00:01 |
 |*  2 |   INDEX RANGE SCAN                  | IDX_EFF_TS  |     1 |       |     1   (0)| 00:00:01 |
 ---------------------------------------------------------------------------------------------------
    Both timestamp and to_timestamp yield the same results in terms of access path.  So avoid using sky limit (> systimestamp) in your SQL's if you know what you are looking for. SQL's like these do they impact partitions, watch out for the next post.    

Wednesday, June 15, 2016

Oracle 12c - Pattern Matching Part 1

Oracle 12c Pattern Matching





Big SQL :)

Before getting into Oracle 12c Pattern Matching - the set of questions which came across after looking at Oracle 12c Patern Matching - MATCH_RECOGNIZE are 
  1. With SQL we have many possible solution, what could be that one scenario which cannot be handled or may not be an optimal solution via SQL until Oracle 11g which lead to SQL Pattern Matching
  2. It looks big, Very BIG
  3. So many key words
  4. Complex
           Pattern Matching comes examples like V/W patterns in stock market, suspicious financial transaction and you will find much more online, But let us get into basic question why not in 11g, Demystifying the unknown usually helps so lets begin. Am going to walk you through multiple scenarios comparing regular expression and analytical SQL. 

Assume we have data stored in a comma separated format in a column like below

with tbl_reg as
(
select 'Linda' as customer, 'TV,BIKE,MOBILE,CAR' as Buying_Pattern from dual
union
select 'Lorena' as customer, 'TV,BIKE,MOBILE' as Buying_Pattern from dual
union
select 'Mark' as customer, 'TV,BIKE,BIKE,MOBILE' as Buying_Pattern from dual
)
SELECT * from tbl_reg;

CUSTOM BUYING_PATTERN
------ -------------------
Linda  TV,BIKE,MOBILE,CAR
Lorena TV,BIKE,MOBILE
Mark   TV,BIKE,BIKE,MOBILE

Scenario/Pattern 1- Data Format = CSV


           Now if we have to look out for buying pattern  like 'TV,BIKE,MOBILE,CAR', then would straight away jump to regular expressions,
SQL
with tbl_reg as
(
select 'Linda' as customer, 'TV,BIKE,MOBILE,CAR' as Buying_Pattern from dual
union
select 'Lorena' as customer, 'TV,BIKE,MOBILE' as Buying_Pattern from dual
union
select 'Mark' as customer, 'TV,BIKE,BIKE,MOBILE' as Buying_Pattern from dual
)
SELECT * FROM TBL_REG WHERE REGEXP_LIKE(REPLACE(Buying_Pattern,',',' '),'TV BIKE MOBILE CAR');


CUSTOM BUYING_PATTERN
------ -------------------
Linda  TV,BIKE,MOBILE,CAR


          With proper Data Modeling in place the data is not gonna be stored in CSV format, so let us re-iterate the requirement to identifying the pattern

Scenario/Pattern 1 - Data Format = Rows

                    With Anaytical function - LEAD the same can be achived 
SQL
WITH PRDT_ORDER AS
(SELECT
BP.*
,LEAD(PRODUCT) OVER (PARTITION BY CUSTOMER ORDER BY BUY_DT) NEXT_PRDT
,LEAD(PRODUCT,2) OVER (PARTITION BY CUSTOMER ORDER BY BUY_DT) SECOND_NEXT_PRDT
,LEAD(PRODUCT,3) OVER (PARTITION BY CUSTOMER ORDER BY BUY_DT) THIRD_NEXT_PRDT
FROM BUYING_PATTERN BP
)
SELECT CUSTOMER,BUY_DT,PRODUCT FROM PRDT_ORDER
WHERE
PRODUCT='TV'
AND NEXT_PRDT = 'BIKE'
AND SECOND_NEXT_PRDT = 'MOBILE'
AND THIRD_NEXT_PRDT = 'CAR';

CUSTOMER   BUY_DT      PRODUCT
-------- ------------------------------ -----------
LINDA     15-JUN-16 07.51.48.812559 AM     TV



Scenario 2 - Pattern 1 + Pattern 2 - Data Format = CSV


       If we want to look out for another pattern along with existing one , .ie along with pattern 1 = TV,BIKE,MOBILE,CAR, check for pattern 2 = TV,BIKE,BIKE,MOBILE  it is just a simple change to the existing SQL

with tbl_reg as
(
select 'Linda' as customer, 'TV,BIKE,MOBILE,CAR' as Buying_Pattern from dual
union
select 'Lorena' as customer, 'TV,BIKE,MOBILE' as Buying_Pattern from dual
union
select 'Mark' as customer, 'TV,BIKE,BIKE,MOBILE' as Buying_Pattern from dual
)
SELECT * FROM TBL_REG WHERE REGEXP_LIKE(REPLACE(Buying_Pattern,',',' '),'TV BIKE MOBILE CAR|TV BIKE BIKE MOBILE');

CUSTOM BUYING_PATTERN
------ -------------------
Linda  TV,BIKE,MOBILE,CAR
Mark   TV,BIKE,BIKE,MOBILE


Now the same in rows

Scenario 2 - Pattern 1+Pattern 2 - Data Format = Rows


pattern 1 = TV,BIKE,MOBILE,CAR,
pattern 2 = TV,BIKE,BIKE,MOBILE


WITH PRDT_ORDER AS
(SELECT 
BP.*
,LEAD(PRODUCT) OVER (PARTITION BY CUSTOMER ORDER BY BUY_DT) NEXT_PRDT
,LEAD(PRODUCT,2) OVER (PARTITION BY CUSTOMER ORDER BY BUY_DT) SECOND_NEXT_PRDT
,LEAD(PRODUCT,3) OVER (PARTITION BY CUSTOMER ORDER BY BUY_DT) THIRD_NEXT_PRDT
FROM BUYING_PATTERN BP
)
SELECT CUSTOMER,BUY_DT,PRODUCT FROM PRDT_ORDER 
WHERE 
PRODUCT='TV'
AND NEXT_PRDT = 'BIKE'
AND SECOND_NEXT_PRDT = 'MOBILE'
AND THIRD_NEXT_PRDT = 'CAR'
union
SELECT CUSTOMER,BUY_DT,PRODUCT FROM PRDT_ORDER 
WHERE 
PRODUCT='TV'
AND NEXT_PRDT = 'BIKE'
AND SECOND_NEXT_PRDT = 'BIKE'
AND THIRD_NEXT_PRDT = 'MOBILE';

USTOMER         BUY_DT    PRODUCT
----------- -----------------------------------  ---------------------
LINDA       15-JUN-16 07.51.48.812559 AM           TV
MARK       15-JUN-16 07.51.48.812559 AM           TV


Scenario 3 - Pattern 3 - Data Format = CSV

       Pattern 3 is some like when you think sky is the limit i.e really not sure how many of them could repeat within a pattern. For an example - All 1,2,3 from the below picture are of same pattern XYZA


with tbl_reg as
(
select 'Linda' as customer, 'TV,BIKE,MOBILE,CAR' as Buying_Pattern from dual
union
select 'Lorena' as customer, 'TV,BIKE,MOBILE' as Buying_Pattern from dual
union
select 'Mark' as customer, 'TV,BIKE,BIKE,MOBILE' as Buying_Pattern from dual
union
select 'RAJINI' as customer, 'TV,TV,BIKE,BIKE,BIKE,MOBILE,CAR' as Buying_Pattern from dual
)
SELECT customer, buying_pattern  FROM TBL_REG WHERE REGEXP_LIKE(REPLACE(Buying_Pattern,','),'(TV(.*)BIKE(.*)MOBILE(.*)CAR(.*))');

CUSTOM BUYING_PATTERN
------ -------------------------------
Linda  TV,BIKE,MOBILE,CAR
RAJINI TV,TV,BIKE,BIKE,BIKE,MOBILE,CAR


Scenario 3 - Pattern 3 -  Data Format = ROWS

                  We have two sets of data, one has a fixed pattern while other has got a subset, ie, Looking out for buying pattern, matching the order - "TV(.*) BIKE(.*) MOBILE CAR". Both 1 and 2 in the below picture belong to the same pattern "TV BIKE MOBILE CAR"
























               Untill 11g if this has to be written in a single SQL, it becomes pretty tough to have it in a single optimal SQL. Oracle 12c - Pattern Matching has got the answer, when you want to perform a pattern recognition in a sequence of rows - it is MATCH_RECOGNIZE

Here it is
SELECT *
FROM BUYING_PATTERN
MATCH_RECOGNIZE ( PARTITION BY CUSTOMER ORDER BY BUY_DT
  MEASURES
    FIRST(A.PRODUCT) first_ITEM,
    FIRST(A.BUY_DT) first_ITEM_DT,
    NVL(LAST(C.PRODUCT),LAST(B.PRODUCT)) LAST_ITEM_BEFORE_X,
    LAST(D.PRODUCT) LAST_ITEM,
    LAST(D.BUY_DT) LAST_ITEM_DT
    ,COUNT(*) CNT    
  one ROW PER MATCH   
  PATTERN (A* B* C D)
  DEFINE   
  A AS A.PRODUCT='TV',
  B AS B.PRODUCT='BIKE',
  C AS C.PRODUCT='MOBILE',
  D AS D.PRODUCT='CAR'
);


CUSTOMER    FIRST_ITEM    FIRST_ITEM_DT     LAST_ITEM_BEFORE_X     LAST_ITEM LAST_ITEM_DT                CNT
----------- ------------------ -------------------------  ------------------   -------------- -------------------------------- ----
LINDA     TV      15-JUN-16 07.51.48.812559 AM     MOBILE     CAR  15-JUN-16 07.54.48.812559 AM 4
RAJINI     TV      15-JUN-16 03.22.24.354595 PM     MOBILE     CAR  15-JUN-16 03.25.24.354595 PM 7


Once we know why it is required, where we can apply,  we are half way through in Pattern Matching - MATCH_RECOGNIZE. Rest to follow in upcoming post.

Saturday, October 24, 2015

Excited ! -
Oracle OpenWorld is just around the corner - Have one presentation at OOW this year -

Topic - Harness the Power of Big Data with Oracle
Time - 25 Oct 12 Noon
Location - Mascone South 102

Hope to meet you guys

Thursday, June 11, 2015

You would have never thought that this feature would help in Tuning

The word "Tuning" should be in discussion right at the initial stage of your design and not just after shipping you code to production. In most of the environments have worked, The attitude to ship the code first - meet the timelines and tune later was prominent.  Let us see once such use case now,  


SQL> select * from tblchk tbl1 where exists
  2  (select 1 from tblchk tbl2 where tbl1.id=tbl2.id and tbl2.id_val='ORACLE');

no rows selected

 
And the Plan
-----------------------------------------------------------------------------------------------------------------------------                         
| Id  | Operation            | Name   | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |                         
-----------------------------------------------------------------------------------------------------------------------------                         
|   0 | SELECT STATEMENT     |        |      1 |        |      0 |00:00:00.01 |     487 |     12 |       |       |          |                         
|*  1 |  HASH JOIN RIGHT SEMI|        |      1 |    190K|      0 |00:00:00.01 |     487 |     12 |  1645K|  1645K|  488K (0)|                         
|*  2 |   TABLE ACCESS FULL  | TBLCHK |      1 |  36663 |      0 |00:00:00.01 |     487 |     12 |       |       |          |                         
|   3 |   TABLE ACCESS FULL  | TBLCHK |      0 |    220K|      0 |00:00:00.01 |       0 |      0 |       |       |          |                         
-----------------------------------------------------------------------------------------------------------------------------                         
                                                                                                                                                      
Predicate Information (identified by operation id):                                                                                                   
---------------------------------------------------                                                                                                   
                                                                                                                                                      
   1 - access("TBL2"."ID"="TBL1"."ID")                                                                                                                
   2 - filter("TBL2"."ID_VAL"='ORACLE')                                                                                                                

no records, let us check the 10046 trace to dig further
PARSING IN CURSOR #140069498436864 len=112 dep=0 uid=143 oct=3 lid=143 tim=47991926417 hv=368497245 ad='74031300' 
sqlid='7w4sr0cazdnkx'
select * from TBLCHK tbl1 where EXISTS
(select 1 from tblchk tbl2 where tbl2.id=tbl1.id and tbl2.id_val='ORACLE')
END OF STMT
PARSE #140069498436864:c=37000,e=37341,p=0,cr=52,cu=0,mis=1,r=0,dep=0,og=1,plh=1090576670,tim=47991926414
EXEC #140069498436864:c=0,e=57,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1090576670,tim=47991926538
WAIT #140069498436864: nam='SQL*Net message to client' ela= 4 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=47991926621
WAIT #140069498436864: nam='Disk file operations I/O' ela= 51 FileOperation=2 fileno=10 filetype=2 obj#=96213 tim=47991928267
WAIT #140069498436864: nam='db file sequential read' ela= 18 file#=10 block#=24289 blocks=1 obj#=96213 tim=47991928350
WAIT #140069498436864: nam='db file sequential read' ela= 10 file#=10 block#=24296 blocks=1 obj#=96213 tim=47991928573
WAIT #140069498436864: nam='db file sequential read' ela= 9 file#=10 block#=24298 blocks=1 obj#=96213 tim=47991928655
WAIT #140069498436864: nam='db file scattered read' ela= 15 file#=10 block#=24335 blocks=2 obj#=96213 tim=47991928977
WAIT #140069498436864: nam='db file sequential read' ela= 13 file#=10 block#=24375 blocks=1 obj#=96213 tim=47991930095
WAIT #140069498436864: nam='db file sequential read' ela= 57 file#=10 block#=24427 blocks=1 obj#=96213 tim=47991930962
WAIT #140069498436864: nam='db file sequential read' ela= 11 file#=10 block#=24429 blocks=1 obj#=96213 tim=47991931099
WAIT #140069498436864: nam='db file sequential read' ela= 10 file#=10 block#=24434 blocks=1 obj#=96213 tim=47991931216
WAIT #140069498436864: nam='db file sequential read' ela= 10 file#=10 block#=24438 blocks=1 obj#=96213 tim=47991931313
WAIT #140069498436864: nam='db file sequential read' ela= 16 file#=10 block#=24560 blocks=1 obj#=96213 tim=47991933732
WAIT #140069498436864: nam='db file sequential read' ela= 14 file#=10 block#=24687 blocks=1 obj#=96213 tim=47991935137
FETCH #140069498436864:c=9000,e=8564,p=12,cr=487,cu=0,mis=0,r=0,dep=0,og=1,plh=1090576670,tim=47991935230
STAT #140069498436864 id=1 cnt=0 pid=0 pos=1 obj=0 op='HASH JOIN RIGHT SEMI (cr=487 pr=12 pw=0 time=8566 us cost=207 size=2280096 card=190008)'
STAT #140069498436864 id=2 cnt=0 pid=1 pos=1 obj=96213 op='TABLE ACCESS FULL TBLCHK (cr=487 pr=12 pw=0 time=8425 us cost=103 size=219978 card=36663)'
STAT #140069498436864 id=3 cnt=0 pid=1 pos=2 obj=96213 op='TABLE ACCESS FULL TBLCHK (cr=0 pr=0 pw=0 time=0 us cost=103 size=1320000 card=220000)'
*** 2015-05-28 13:29:31.638
WAIT #140069498436864: nam='SQL*Net message from client' ela= 18769385 driver id=1413697536 #bytes=1 p3=0 obj#=96213 tim=48010704804
CLOSE #140069498436864:c=0,e=16,dep=0,type=0,tim=48010704946

TkProf

select * from TBLCHK tbl1 where EXISTS
(select 1 from tblchk tbl2 where tbl2.id=tbl1.id and tbl2.id_val='ORACLE')

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.03       0.03          0         52          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00         12        487          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.04       0.04         12        539          0           0

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 143  
Number of plan statistics captured: 1

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
         0          0          0  HASH JOIN RIGHT SEMI (cr=487 pr=12 pw=0 time=8566 us cost=207 size=2280096 card=190008)
         0          0          0   TABLE ACCESS FULL TBLCHK (cr=487 pr=12 pw=0 time=8425 us cost=103 size=219978 card=36663)
         0          0          0   TABLE ACCESS FULL TBLCHK (cr=0 pr=0 pw=0 time=0 us cost=103 size=1320000 card=220000)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  Disk file operations I/O                        1        0.00          0.00
  db file sequential read                        10        0.00          0.00
  db file scattered read                          1        0.00          0.00
  SQL*Net message from client                     1       18.76         18.76



hmm After all these waits events, it has figured that my data is not there. Instead of this can i have something similar to an ledger, which could be used to cross check and validate before even moving on to next step. After creating a ledger to hold the values take a look at the 10046 and TKProf below -- ledger :) scroll down to know more

PARSING IN CURSOR #140503816846712 len=112 dep=0 uid=143 oct=3 lid=143 tim=47001392270 hv=2403129567 ad='79a60d48' sqlid='a8sqfsu7mtq6z'
select * from tblchk tbl1 where exists
(select 1 from tblchk tbl2 where tbl1.id=tbl2.id and tbl2.id_val='ORACLE')
END OF STMT
PARSE #140503816846712:c=30000,e=30955,p=0,cr=58,cu=0,mis=1,r=0,dep=0,og=1,plh=2472364079,tim=47001392254
EXEC #140503816846712:c=0,e=107,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2472364079,tim=47001392773
WAIT #140503816846712: nam='SQL*Net message to client' ela= 8 driver id=1413697536 #bytes=1 p3=0 obj#=653 tim=47001393166
FETCH #140503816846712:c=0,e=16,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2472364079,tim=47001393231
STAT #140503816846712 id=1 cnt=0 pid=0 pos=1 obj=0 op='FILTER  (cr=0 pr=0 pw=0 time=10 us)'
STAT #140503816846712 id=2 cnt=0 pid=1 pos=1 obj=0 op='HASH JOIN RIGHT SEMI (cr=0 pr=0 pw=0 time=0 us cost=207 size=2280096 card=190008)'
STAT #140503816846712 id=3 cnt=0 pid=2 pos=1 obj=96213 op='TABLE ACCESS FULL TBLCHK (cr=0 pr=0 pw=0 time=0 us cost=103 size=219978 card=36663)'
STAT #140503816846712 id=4 cnt=0 pid=2 pos=2 obj=96213 op='TABLE ACCESS FULL TBLCHK (cr=0 pr=0 pw=0 time=0 us cost=103 size=1320000 card=220000)'

*** 2015-05-28 13:13:10.959
WAIT #140503816846712: nam='SQL*Net message from client' ela= 28632273 driver id=1413697536 #bytes=1 p3=0 obj#=653 tim=47030025871
CLOSE #140503816846712:c=0,e=17,dep=0,type=0,tim=47030025999
No db file sequential read wow And the TKProf looks like below -
select * from tblchk tbl1 where exists
(select 1 from tblchk tbl2 where tbl1.id=tbl2.id and tbl2.id_val='ORACLE')

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.01       0.01          0          0          0           0

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 143  
Number of plan statistics captured: 1

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
         0          0          0  FILTER  (cr=0 pr=0 pw=0 time=10 us)
         0          0          0   HASH JOIN RIGHT SEMI (cr=0 pr=0 pw=0 time=0 us cost=207 size=2280096 card=190008)
         0          0          0    TABLE ACCESS FULL TBLCHK (cr=0 pr=0 pw=0 time=0 us cost=103 size=219978 card=36663)
         0          0          0    TABLE ACCESS FULL TBLCHK (cr=0 pr=0 pw=0 time=0 us cost=103 size=1320000 card=220000)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  SQL*Net message from client                     1       28.63         28.63

So what is this Ledger - How could Oracle do this, with out even going to your data it would say you don't have it :)- it because of this
SQL> select distinct id_val from tblchk;

ID_VAL
-----------
  A
  B
  C
Since i know for sure am not going to hold ORACLE in id_val column , check constraint on ID_VAL column is added
alter table tblchk add CONSTRAINT check_idval CHECK (id_val in ('A','B','C'));
Our Ledger = Check Constraint which directed the optimizer in doing this. Though this looks soo cheap tactic, Isn't this helping me. Why should i do all the scan to just say you don't have it, when am pretty sure that i don't have it though.

Sunday, November 2, 2014

I'm Speaking @ SANGAM14



Getting ready for the major event - SANGAM14 - AIOUG keeps all the techies under a single roof. I am presenting the below topics this year, If you happen to be attending, please stop by and say hello. We’d love to meet you and chat with the Oracle Community.

Oracle 12c In-database Analytic's


Its gonna be a 'WHAT IF SESSIONS',   

Sunday, February 2, 2014

Oracle 12c - With Clause Enhancements

5 Mins Blog

Until Oracle 12c, we have been using WITH Clause to replace  
  • Sub-query
  • Correlated Subqueries 
Now to this you can define PLSQL declarations in a WITH Clause statement from Oracle 12c. 
Blogged in the same chronological order,  I encountered errors 


In SQL-Developer

















Look what i get 























Oops, let try with Sqlplus











                   

 Isn't ";" the terminator for the SQL Statement,  


how about Update 













Is update not supported ?

hmm, Ok how about inside a plsql























Are these restrictions ?

Lets see one by one, 

         WITH Clause with inline PLSQL are supported only in SQL Developer Version 4.0, check this link to see the number of bugs fixed in SQL Developer 4.0 

WITH Clause with inline PLSQL query from - Sql Developer Version 4.0



























WITH Clause with PLSQL Declaration - "/" is the query terminator




















Update - WITH Clause with PLSQL Declaration -

       From Oracle Documentation 'If the top-level statement is a DELETE, MERGE, INSERT, or UPDATE statement, then it must have the WITH_PLSQL hint", 
















Note from Oracle Documentation:" Hint - /*+ WITH_PLSQL */  is not an optimizer hint, it is just to specify the WITH PLSQL Declaration clause within the statement "


WITH Clause with PLSQL Declaration inside a PLSQL Block
  
         You cannot execute WITH Clause with PLSQL Declaration directly inside a PLSQL Block, but can be executed as dynamic SQL























SQL's making use of functions, Functions !!!! which are yet not stored objects is the key benefit we get and can be of great use for one time data migration scripts, for which you really don't want write stored functions.

Thanks for reading, feel free to leave your comments. Let's see about performance benefits in the next post  

Sunday, January 19, 2014

Oracle 12c - PLSQL index by table to Java/SQL

My application front end is Java and DB is Oracle. What array should i use in my PLSQL - program parameters to enable JDBC application to invoke them ?

          Until Oracle 11g, The type has to be defined at the schema-level to enable JDBC applications to interface with PLSQL programs. Now in Oracle 12c this restriction is completely removed.

Let's do some blogging

Before we start with Oracle 12c, lets see these restrictions in Oracle 11g.

CREATE OR REPLACE PACKAGE pkg_plsql_12c
AS
TYPE subject IS TABLE OF VARCHAR2 (100) INDEX BY PLS_INTEGER;

TYPE Marks IS RECORD
  (Maths   NUMBER,
    Physics NUMBER );
    
  PROCEDURE input_is_boolean(
      p_name  IN VARCHAR2,
      p_print IN BOOLEAN);
  PROCEDURE print_subjects(
      p_subject IN subject);
  PROCEDURE print_marks(
      p_marks IN marks);
      
END pkg_plsql_12c;
/
CREATE OR REPLACE PACKAGE BODY pkg_plsql_12c
AS
PROCEDURE input_is_boolean(
    p_name  IN VARCHAR2,
    p_print IN BOOLEAN)
IS
BEGIN
  IF p_print THEN
    DBMS_OUTPUT.put_line (p_name);
  ELSE
    DBMS_OUTPUT.put_line ('I DINT PRINT YOUR NAME');
  END IF;
END input_is_boolean;

PROCEDURE print_subjects(
    p_subject IN subject)
IS
BEGIN
  FOR idx IN 1 .. p_subject.COUNT
  LOOP
    DBMS_OUTPUT.put_line ( p_subject (idx));
  END LOOP;
END print_subjects;

PROCEDURE print_marks(
    p_marks IN marks)
IS
BEGIN
  DBMS_OUTPUT.put_line ( 'MATHS--'||p_marks.MATHS);
  DBMS_OUTPUT.put_line ( 'PHYSICS--'||p_marks.PHYSICS);
END print_marks;
END pkg_plsql_12c;
/

In 11g
SQL> select * from v$version;
 
BANNER
--------------------------------------------------------------------------------
 
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE    11.2.0.1.0      Production
TNS for 32-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production


DECLARE
   lv varchar2(10) := 'ORACLE';
   lv_subjects   pkg_plsql_12c.subject;
   lv_marks   pkg_plsql_12c.marks;
BEGIN

  BEGIN
     EXECUTE IMMEDIATE
        'BEGIN pkg_plsql_12c.input_is_boolean(:Name, :Bool); END;'
        USING lv, TRUE; 
  END;
  
  BEGIN
   lv_subjects(1):='ORACLE ASSOCIATIVE ARRAY';   
   EXECUTE IMMEDIATE
      'BEGIN pkg_plsql_12c.print_subjects (:sub); END;'
      USING lv_subjects;   
  END;
  
  BEGIN
  lv_marks.maths := 100;
  lv_marks.physics := 99;
     
     EXECUTE IMMEDIATE
      'BEGIN pkg_plsql_12c.print_marks (:mark); END;'
      USING lv_marks;    
  END;    
END;
Error at line 3
ORA-06550: line 10, column 19:
PLS-00457: expressions have to be of SQL types
ORA-06550: line 8, column 6:
PL/SQL: Statement ignored
ORA-06550: line 17, column 13:
PLS-00457: expressions have to be of SQL types
ORA-06550: line 15, column 4:
PL/SQL: Statement ignored
ORA-06550: line 26, column 13:
PLS-00457: expressions have to be of SQL types
ORA-06550: line 24, column 6:
PL/SQL: Statement ignored

Script Terminated on line 3.

Until Oracle 11g, If an SQL has to be invoked from PLSQL, only SQL supported data types can be bound.The New feature in Oracle 12c is all about - " PLS-00457: expressions have to be of SQL types "

New in 12.1 -        
          Oracle as relaxed these rules, It is possible to

1. Bind a Boolean to an Anonymous Block
2. Bind Records and associative arrays to an Anonymous Block

Lets execute the same in Oracle 12c

SQL> select banner from v$version;

BANNER
-------------------------------------------------------------------------------

Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
PL/SQL Release 12.1.0.1.0 - Production
CORE    12.1.0.1.0      Production
TNS for 64-bit Windows: Version 12.1.0.1.0 - Production
NLSRTL Version 12.1.0.1.0 - Production

DECLARE
  lv VARCHAR2(10) := 'ORACLE';
  lv_subjects pkg_plsql_12c.subject;
  lv_marks pkg_plsql_12c.marks;
BEGIN
  -------BOOLEAN------------
  EXECUTE IMMEDIATE 'BEGIN pkg_plsql_12c.input_is_boolean(:Name, :Bool); END;' USING lv, TRUE;  
  
  ---ORACLE ASSOCIATIVE ARRAY---------
    lv_subjects(1):='ORACLE ASSOCIATIVE ARRAY';
    EXECUTE IMMEDIATE 'BEGIN pkg_plsql_12c.print_subjects (:sub); END;' USING lv_subjects;
  
  ----------RECORD-------------
    lv_marks.maths   := 100;
    lv_marks.physics := 99;
   EXECUTE IMMEDIATE 'BEGIN pkg_plsql_12c.print_marks (:mark); END;' USING lv_marks;    

END;
/
anonymous block completed
ORACLE
ORACLE ASSOCIATIVE ARRAY
MATHS--100
PHYSICS--99

From Oracle 12c - JDBC applications can call procedure with associative array parameters provided the associative array is declared in a package specification.. You can only index by PLS_INTEGER which must be positive and dense.


Thanks for reading, feel free to leave your comments.