Oracle query optimization for select - java

Below is my query and i want to know if any optimization is possible in this query or not ?
FYI, I have applied index on C_NUMBER , CA_NUMBER and D_TIMESTAMP column.
SELECT
NAM, RSON, URL
FROM TM_CAM
WHERE C_NUMBER = A_C_NUMBER
AND CA_NUMBER = A_CA_NUMBER
AND (SYSTIMESTAMP) <= D_TIMESTAMP
ORDER BY D_TIMESTAMP DESC
FETCH FIRST 1 ROWS ONLY
There is a ORDER BY so i think its not good from a performance perspective.
I tried below but it has degraded performance.
SELECT
NAM, RSON, URL
FROM TM_CAM
WHERE D_TIMESTAMP = (
SELECT MAX(D_TIMESTAMP )
FROM TM_CAM
)
AND C_NUMBER = A_C_NUMBER
AND CA_NUMBER = A_CA_NUMBER
AND (SYSTIMESTAMP) <= D_TIMESTAMP
Any inputs please ?

Sorting slows things down, that's for sure.
Your 1st query looks OK to me; how many rows are involved? What kind of optimization do you expect? I guess you're concerned about execution time; if so, how long does that query take? Did you check explain plan?
Meanwhile, try
WITH
temp
AS
(SELECT nam,
rson,
url,
ROW_NUMBER () OVER (ORDER BY d_timestamp DESC) rn
FROM tm_nam
WHERE c_number = a_c_number
AND ca_number = a_ca_number
AND SYSTIMESTAMP <= d_timestamp)
SELECT nam, rson, url
FROM temp
WHERE rn = 1;
or
WITH
temp
AS
( SELECT nam, rson, url
FROM tm_nam
WHERE c_number = a_c_number
AND ca_number = a_ca_number
AND SYSTIMESTAMP <= d_timestamp
ORDER BY d_timestamp DESC)
SELECT nam, rson, url
FROM temp
WHERE ROWNUM = 1;

Your first and second queries are not the same as the second query is the equivalent of:
SELECT NAM, RSON, URL
FROM TM_CAM
WHERE C_NUMBER = A_C_NUMBER
AND CA_NUMBER = A_CA_NUMBER
AND SYSTIMESTAMP <= D_TIMESTAMP
ORDER BY D_TIMESTAMP DESC
FETCH FIRST ROW WITH TIES
You could rewrite it using ROWNUM:
SELECT *
FROM (
SELECT NAM, RSON, URL
FROM TM_CAM
WHERE C_NUMBER = A_C_NUMBER
AND CA_NUMBER = A_CA_NUMBER
AND SYSTIMESTAMP <= D_TIMESTAMP
ORDER BY D_TIMESTAMP DESC
)
WHERE ROWNUM = 1;
But if you compare the execution plan you will probably find that Oracle uses very similar (if not identical) plans for FETCH FIRST ROW ONLY, filtering on ROWNUM = 1 or for filtering on the ROW_NUMBER() analytic function so it is likely that you can pick whichever query is easiest to maintain and use that.
fiddle

Related

Best way for text extraction (classification) over a SQL query in java

I have several SQL queries like this (about 10.000):
SELECT (COLUMN BODY)
FROM (TABLES BODY)
WHERE...
The where part is optional.
I need to extract the "COLUMN BODY" AND "TABLES BODY" from the query, but those are dynamic (I have found SQL functions and subqueries a lot)
Think as getting an vector with the divided query or something like that:
String result = [SELECT, "COLUMN BODY", FROM, "TABLES BODY", WHERE, ... ]
The purpose, I'm working in an "SQL translator" and I need extract those parts from that dynamic queries. I have tried string splitting and other but the result is so frustrating, so I'm looking for an alternative to achieve that. I'm working on a java project.
What is the best way to get that?
Edit
Those are examples of the queries:
SELECT COMPANIA, ANO, TIPO_COBRO, CODIGO, DESCRIPCION FROM SF_DESCRIPCIONES_ESTAND
SELECT AUT_FAMILIARES.COMPANIA, AUT_FAMILIARES.DCTO_EMPLEADO, AUT_FAMILIARES.SUCURSAL_EMPLEADO, AUT_FAMILIARES.IDENTIFICACION, AUT_FAMILIARES.SUCURSAL, AUT_FAMILIARES.CONSECUTIVO, AUT_FAMILIARES.DCTO_IDENTIDAD, AUT_FAMILIARES.PARENTESCO, AUT_FAMILIARES.NOMBRE, AUT_FAMILIARES.FECHANCTO, AUT_FAMILIARES.SEXO, AUT_FAMILIARES.OBSERVACIONES, AUT_FAMILIARES.POLIZA, AUT_FAMILIARES.SALUD, AUT_FAMILIARES.PORCENTAJE, AUT_FAMILIARES.OCUPACION, AUT_FAMILIARES.TELEFONO, AUT_FAMILIARES.POS, AUT_FAMILIARES.AUXILIO_EDUCATIVO, AUT_FAMILIARES.APELLIDO1, AUT_FAMILIARES.APELLIDO2, AUT_FAMILIARES.DIRECCION, AUT_FAMILIARES.ESTADO_ACTUAL, AUT_FAMILIARES.DCTO_IDENTIDAD_A, AUT_FAMILIARES.PARENTESCO_A, AUT_FAMILIARES.NOMBRE_A, AUT_FAMILIARES.SEXO_A, AUT_FAMILIARES.OBSERVACIONES_A, AUT_FAMILIARES.POLIZA_A, AUT_FAMILIARES.SALUD_A, AUT_FAMILIARES.PORCENTAJE_A, AUT_FAMILIARES.OCUPACION_A, AUT_FAMILIARES.TELEFONO_A, AUT_FAMILIARES.POS_A, AUT_FAMILIARES.AUXILIO_EDUCATIVO_A, AUT_FAMILIARES.APELLIDO1_A, AUT_FAMILIARES.APELLIDO2_A, AUT_FAMILIARES.DIRECCION_A, AUT_FAMILIARES.ESTADO_ACTUAL_A, AUT_FAMILIARES.ESTADO, AUT_FAMILIARES.DESTINATARIO, AUT_FAMILIARES.SUCURSAL_DESTINATARIO, AUT_FAMILIARES.TIPO_SOLICITUD, AUT_FAMILIARES.FECHA_APROBACION, AUT_FAMILIARES.ENVIADO, AUT_FAMILIARES.ACTUALIZADO, AUT_FAMILIARES.RUTA, AUT_FAMILIARES.CREATED_BY, AUT_FAMILIARES.DATE_CREATED, AUT_FAMILIARES.MODIFIED_BY, AUT_FAMILIARES.DATE_MODIFIED, AUT_FAMILIARES.N_IDENTIFICACION, AUT_FAMILIARES.EDAD, AUT_FAMILIARES.EDAD_A FROM AUT_FAMILIARES
SELECT DISTINCT CARGOS.ID_DE_CARGO, CARGOS.NOMBRE_DEL_CARGO FROM EV_EVALUADOR_EVALUADO EVAL INNER JOIN CARGOS ON EVAL.COMPANIA = CARGOS.COMPANIA AND EVAL.CARGO_EVALUADO = CARGOS.ID_DE_CARGO WHERE EVAL.COMPANIA = :COMPANIA AND EVAL.CLASE_EVALUACION = :CLASEEVALUACION AND CARGOS.ID_DE_CARGO >= :CODIGO ORDER BY CARGOS.ID_DE_CARGO
SELECT ROWNUM CODIGO, DECODE (ROWNUM, 1,'Activo',2,'Pensionado',3,'Retirado',4,'Suspensión Preventiva',5,'Activarlo para Ajustes Liquidación',6,'Comisión',7,'Encargos')NOMBRE FROM DUAL CONNECT BY ROWNUM < 8
SELECT * FROM ( SELECT A.*, ROWNUM RNUM FROM(SELECT * FROM (SELECT INVENTARIO.CODIGOELEMENTO, INVENTARIO.NOMBRELARGO FROM INVENTARIO WHERE INVENTARIO.COMPANIA = :COMPANIA AND INVENTARIO.TIPO NOT IN ('C') ORDER BY INVENTARIO.COMPANIA, INVENTARIO.CODIGOELEMENTO) WHERE (CASE WHEN CODIGOELEMENTO IS NULL THEN ' ' ELSE UPPER(CODIGOELEMENTO) END) LIKE UPPER(:CODIGOELEMENTO || '%') AND (CASE WHEN NOMBRELARGO IS NULL THEN ' ' ELSE UPPER(NOMBRELARGO) END) LIKE UPPER( '%' || :NOMBRELARGO || '%') ) A WHERE ROWNUM <= (:PAGINICIO + :PAGTAMANIO)) WHERE RNUM > :PAGINICIO

org.hibernate.exception.SQLGrammarException: could not execute query using scroll

I have the following query,
When I tried to execute it using hibernate I get the following exception :
org.hibernate.exception.SQLGrammarException: could not execute query
using scroll.
In my code I have scroll has FORWARD_ONLY.
Can anyone please provide a perfect solution.
select * from (SELECT account_no AS accountno,rownum r FROM sc_dcm_postpaid_index WHERE groupid = 'SBG-2012'
and concat(trim(TO_CHAR(bill_date,'MONTH')),concat('-',TO_CHAR(bill_date,'YY')))='JUNE-12'
AND ROWID IN (SELECT MAX(ROWID) AS row_no ; FROM sc_dcm_postpaid_index
WHERE groupid= 'SBG-2012' and concat(trim(TO_CHAR(bill_date,'MONTH')),concat('-',TO_CHAR(bill_date,'YY')))='JUNE-12'
GROUP BY account_no HAVING COUNT (account_no) >= 1 ) ORDER BY account_no)where r >= 11 and r <= 21..
Also when I change the query to
SELECT account_no AS accountno,rownum r FROM sc_dcm_postpaid_index WHERE rownum >= 11 and rownum <= 21 groupid = 'SBG-2012'
and concat(trim(TO_CHAR(bill_date,'MONTH')),concat('-',TO_CHAR(bill_date,'YY')))='JUNE-12'
AND ROWID IN (SELECT MAX(ROWID) AS row_no ; FROM sc_dcm_postpaid_index
WHERE groupid= 'SBG-2012' and concat(trim(TO_CHAR(bill_date,'MONTH')),concat('-',TO_CHAR(bill_date,'YY')))='JUNE-12'
GROUP BY account_no HAVING COUNT (account_no) >= 1 ) ORDER BY account_no
And this is my Query:
SQLQuery mainQuery = (SQLQuery) session.createSQLQuery(strReportQuery);
ScrollableResults itrDataList = mainQuery.scroll(ScrollMode.FORWARD_ONLY);
Here strReportQuery is my query
It executes fine but it works only from rownum 1 to 10.
From next rownum it gives resultset as empty.
Thanks in Advance,
Bhargavi T.

How to join 2 row_numbers

Im trying to do a query where I want to join the row_numbers RN and RN1 so as to remove the duplicate rows as shown BOLD in the result set.
WITH CTE AS (
SELECT
PrevEndDate = LAG(edate,1) OVER (PARTITION BY id ORDER BY id)
, PrevStartDate = LAG(sdate,1) OVER (PARTITION BY id ORDER BY id)
, p.id, p.edate
, ROW_NUMBER() OVER (PARTITION BY p.id ORDER BY p.id) as RN1
FROM table p
)
SELECT
t.id, t.sdate, t.edate
, (ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY t.id)) AS RN
, CTE.RN1
, CASE
WHEN CTE.PrevEndDate > t.sdate
THEN DATEDIFF(day,CTE.PrevStartDate,t.sdate)
ELSE
DATEDIFF(day,t.sdate,t.edate)
END
FROM table t
INNER JOIN CTE ON CTE.id= t.id AND CTE.edate= t.edate
--AND RN1 = RN
Thanks in Advance!
You can't define an alias in the select and then use it in from (or where for that matter). You can move it into a subquery. Something like:
with cte as (. . .)
SELECT . . .
FROM (SELECT t.*, ROW_NUMBER() OVER (PARTITION BY t.PRTCPNT_DCN ORDER BY t.PRTCPNT_DCN) as RN
FROM PRTCPNT_ELIG_SPAN_T t
) t INNER JOIN
CTE
ON CTE.PRTCPNT_DCN = t.PRTCPNT_DCN AND
CTE.PRTCPNT_ELIG_END_DATE = t.PRTCPNT_ELIG_END_DATE AND
CTE.RN1 = t.RN;

Hibernate: Joining Criteria

Hi I need to do the following using Criteria
Select * from product pd, (Select productID pd1 from ... where ...) tpd1,
(Select productID pd2 from ... where ...) tpd2
where pd.productID = tpd1.pd1 and pd.productID = tpd1.pd2
May I know if it is possible?
The original SQL was using IN conditions
Select * from product pd where productID in (Select productID pd1 from ... where ...) and
productID in (Select productID pd2 from ... where ...)
but it takes too long to get the result, using the join SQL statement I was able to obtain my result faster.
any help?
Given you're using Hibernate, you may have to do something like this, which should work ok if the number of expected matches are relatively low:
select *
from product pd
where pd.productID in
(select productID
from product pd2
join tpd1 on (pd2.productID = tpd1.pd1)
join tpd2 on (pd2.productID = tpd2.pd2)
where tpd1....
and tpd2....
);
I assume there is a unique index on product.productID.
Alternatively, you could try the EXISTS formulation which may or may not work better than your original query:
select *
from product pd
where EXISTS
(select null from tpd1 where pd.productID = tpd1.pd1 and ...)
and EXISTS
(select null from tpd2 where pd.productID = tpd2.pd2 and ...)
;

ROW_NUMBER() not sequencing records correctly

I had to copy the data from oracle tables to files.
I have a join query which fetches 800k records so i used row_number() function along with order by clause to generate 4 files containing 200k each.
Query :
SELECT * FROM (
SELECT ROW_NUMBER() OVER ( order by FILE_KEY desc ) rn,
FILE_KEY, ROUTING_NO, INTLROUT_TYPE, ABBR_COUNTRY_CODE_2D, HO_CATALOG_NO
FROM BANK_INTL_ROUT_TBL rout, BANK_INTL_LOC_TBL loc
WHERE loc.CATALOG_NO = rout.FILE_KEY)
WHERE rn BETWEEN start AND end;
Parameters:
For 1st File : start =1 ,end = 200000
For 2nd File : start =200001 ,end = 400000
For 3rd File : start =400001 ,end = 600000
For 4th File : start =600001 ,end = 800000
But when i checked last 10 row using this query in sql query browser and last 10 rows of file are different that is sequence is different in file and sql query browser.
SELECT * FROM (
SELECT ROW_NUMBER() OVER( order by FILE_KEY desc ) rn,
FILE_KEY,ROUTING_NO,INTLROUT_TYPE,ABBR_COUNTRY_CODE_2D,HO_CATALOG_NO
FROM BANK_INTL_ROUT_TBL rout, BANK_INTL_LOC_TBL loc
WHERE loc.CATALOG_NO=rout.FILE_KEY)
WHERE rn BETWEEN 709990 AND 80000;
This can be because you have something like this
row_number file_key
799998 same_number
799999 same_number
800000 same_number
800001 same_number
800002 same_number
800003 same_number
800004 same_number
because you order by file_key.
How do you observed that are different data? from your other columns. So, you can use:
SELECT ROW_NUMBER() OVER(order by FILE_KEY desc, ROUTING_NO, INTLROUT_TYPE, ABBR_COUNTRY_CODE_2D, HO_CATALOG_NO ) rn
Or(second cause), your base table had been changen between your querys.
UDPDATE: you can use the use_hash hint to speed up your query. 5 hours is too much for this query.
SELECT * FROM (
SELECT /*+use_hash(rout loc)*/
ROW_NUMBER() OVER(order by FILE_KEY desc, ROUTING_NO, INTLROUT_TYPE, ABBR_COUNTRY_CODE_2D, HO_CATALOG_NO ) rn,
FILE_KEY, ROUTING_NO, INTLROUT_TYPE, ABBR_COUNTRY_CODE_2D, HO_CATALOG_NO
FROM BANK_INTL_ROUT_TBL rout, BANK_INTL_LOC_TBL loc
WHERE loc.CATALOG_NO = rout.FILE_KEY)
WHERE rn BETWEEN start AND end;
In the over clause, order by a unique field in BANK_INTL_LOC_TBL:
SELECT * FROM (
SELECT ROW_NUMBER() OVER ( order by loc.**LOC_KEY** desc ) rn,
FILE_KEY, ROUTING_NO, INTLROUT_TYPE, ABBR_COUNTRY_CODE_2D, HO_CATALOG_NO
FROM BANK_INTL_ROUT_TBL rout, BANK_INTL_LOC_TBL loc
WHERE loc.CATALOG_NO = rout.FILE_KEY)
WHERE rn BETWEEN start AND end
ORDER BY rn;
UPDATE: according to #Shannon Severance comment
add the order by clause
If you have disk to spare on your Oracle installation (which you should!), then instead of running the inner query 4 times it may end up being faster to do the following
CREATE TABLE bank_data
NOLOGGING
PARALLEL 4
AS SELECT ROW_NUMBER() OVER ( order by FILE_KEY desc ) rn,
FILE_KEY, ROUTING_NO, INTLROUT_TYPE, ABBR_COUNTRY_CODE_2D, HO_CATALOG_NO
FROM BANK_INTL_ROUT_TBL rout, BANK_INTL_LOC_TBL loc
WHERE loc.CATALOG_NO = rout.FILE_KEY);
The amount of parallelism to use (the number 4 in my example here) will depend on how much concurrent work your database can handle, mostly dependent on the number of CPUs.
After that has finished, (which should take noticably less than 5 hours!) you can then run simple selects on the bank_dump table to pull the records you desire
SELECT *
FROM bank_dump
where rn < 200000
for your first data set, for example.

Categories