Slow SELECT query over DBLink - Oracle - sql

I'm trying to use to following query over an Oracle DBLink to retrieve some data from Oracle EBS to another system.
WITH
--Este CTE ira receber todos os fornecedores
cteallvendors AS (
SELECT DISTINCT
asu.vendor_name,
apv.vendor_id,
ssa.address_line1,
ssa.address_line2,
ssa.address_line3,
ssa.address_line4,
ssa.city,
ssa.state,
ssa.global_attribute10
|| ''
|| ssa.global_attribute11
|| ''
|| ssa.global_attribute12 cnpj
FROM
apps.ap_suppliers#k2prd asu
LEFT JOIN apps.ap_vendors_v#k2prd apv ON apv.vendor_id = asu.vendor_id
LEFT JOIN apps.ap_supplier_sites_all#k2prd ssa ON apv.vendor_id = ssa.vendor_id
AND asu.vendor_id = ssa.vendor_id
)
SELECT
mmt.transaction_id,
cffea.document_type "TIPO_DOCUMENTO",
rt.vendor_id "NUMERO_FORNECEDOR",
vendors.vendor_name "NOME_FORNECEDOR",
cfi.invoice_num "NUMERO_NOTA",
cfi.series "SERIE",
mp.organization_code "OI",
mmt.subinventory_code "SUBINVENTARIO",
msib.segment1 "CODIGO_ITEM",
mmt.transaction_uom "UOM",
msib.description "DESCRICAO",
mmt.creation_date,
rt.transaction_type
FROM
apps.mtl_material_transactions#k2prd mmt
LEFT JOIN apps.rcv_transactions#k2prd rt ON mmt.rcv_transaction_id = rt.transaction_id
LEFT JOIN apps.cll_f189_invoice_lines#k2prd cfil ON rt.organization_id = cfil.organization_id
AND rt.po_line_location_id = cfil.line_location_id
LEFT JOIN apps.cll_f189_invoices#k2prd cfi ON cfil.invoice_id = cfi.invoice_id
LEFT JOIN apps.cll_f189_invoice_types#k2prd cfit ON cfi.invoice_type_id = cfit.invoice_type_id
LEFT JOIN apps.cll_f189_fiscal_entities_all#k2prd cffea ON cfi.entity_id = cffea.entity_id
LEFT JOIN apps.cll_f189_fiscal_operations#k2prd cffo ON cfil.cfo_id = cffo.cfo_id
LEFT JOIN cteallvendors vendors ON rt.vendor_id = vendors.vendor_id
LEFT JOIN apps.mtl_parameters#k2prd mp ON mmt.organization_id = mp.organization_id
LEFT JOIN apps.mtl_system_items_b#k2prd msib ON msib.inventory_item_id = mmt.inventory_item_id
AND msib.organization_id = mmt.organization_id
LEFT JOIN apps.mtl_transaction_types#k2prd mtt ON mmt.transaction_type_id = mtt.transaction_type_id
WHERE
nvl(mmt.attribute1, '0') = '0'
AND ( ( rt.transaction_type = 'DELIVER'
AND cfit.credit_debit_flag = 'D' )
OR ( rt.transaction_type = 'RETURN TO RECEIVING'
AND cfit.credit_debit_flag = 'C' ) )
AND cffo.cfo_code IN (
1101,
2101,
3101
)
AND upper(mtt.transaction_type_name) IN (
'PO RECEIPT',
'RETURN TO VENDOR'
)
ORDER BY
transaction_id
But the execution times are horrible over DBLink.
It usually takes a few milliseconds to run it on the origin database (around 0.500 to one second when a data load is going, this is the usual time), but when i try to run it from the DBLink, it doesn't bring any results. I left it running for over an hour, other queries over the same DBLink work normally, also, other DBLinks work fine as well.
Could someone help me to solve this situation? Is the query poorly optimized or might be an infrastructure issue going on.

Related

SQL- basic but still finding it complicated

I am working on SQL query which should return the list of Managers and the staff who reports to them.
Unfortunately there is no separate table for Employee or Staff but a single 'resource' table called ahsresources.
The managers are identified with a relation called 'C0'.
Even after trying various Joins, I am unable to extract the list. The idea is that a manager will run the report to see his reportees, as well as those staff who report to his own reportees
Example -
Now, if lets say HDY is running the query, then its should return him the below result
Below is the query I have created, but for the matter of understanding the issue, you can use the above example.
select a.description as manager1,a.rel_value as MGID,a.resource_id as Reportee1_MGR2,r.name,a.date_to as date, r.date_to,a1.resource_id as MG3ID,r1.name as Rep3Name,
a2.resource_id as MG4ID,r2.name as Rep4Name
from ahsrelvalue a
LEFT OUTER JOIN ahsresources r
ON r.resource_id = a.resource_id and r.client = a.client and a.date_to='12/31/2099'
LEFT OUTER JOIN ahsrelvalue a1
ON a1.rel_Value = a.resource_id and a1.client = a.client and a1.date_to = '12/31/2099'
LEFT OUTER JOIN ahsrelvalue a2
ON a2.rel_Value = a1.resource_id and a2.client = a1.client and a2.date_to = '12/31/2099'
LEFT OUTER JOIN ahsresources r1
ON r1.resource_id = a1.resource_id and r1.client = a1.client and a1.date_to='12/31/2099'
LEFT OUTER JOIN ahsresources r2
ON r2.resource_id = a2.resource_id and r2.client = a2.client and a2.date_to='12/31/2099'
where a.rel_Value = '$?resid' and a.rel_attr_id='C0' and r.date_to = '12/31/2099' and r1.date_to ='12/31/2099'
and r.status !='C' and r1.status!='C' and r2.status!='C'
In SQL Server, you can use a recursive query to traverse this hierarchical dataset:
with cte as (
select t.* from mytable where managerID = 6
union all
select t.*
from cte c
inner join mytable t on t.managerID = c.staffID
)
select * from cte

How can i do a conditional where clause in SQL, for missed back ups?

I have a pretty standard query for a back up aging report. What I want / need to do is have it report on missed back ups. I will need to see the last full database back up older than 2 days. I will also need to see any differential back ups older than the last day and any log back ups older than 30 mins. I'm not sure how to do the conditional where clause.
here's my basic query
SELECT
A.[Server],
A.database_name,
A.last_db_backup_date,
B.backup_type,
B.backup_start_date,
B.expiration_date,
B.backup_size,
B.logical_device_name,
B.physical_device_name,
B.backupset_name,
B.description
FROM
(
SELECT
CONVERT(CHAR(100), SERVERPROPERTY('Servername')) AS Server,
msdb.dbo.backupset.database_name,
MAX(msdb.dbo.backupset.backup_finish_date) AS last_db_backup_date
FROM msdb.dbo.backupmediafamily
INNER JOIN msdb.dbo.backupset ON msdb.dbo.backupmediafamily.media_set_id = msdb.dbo.backupset.media_set_id
GROUP BY
msdb.dbo.backupset.database_name
) AS A
LEFT JOIN
(
SELECT
CONVERT(CHAR(100), SERVERPROPERTY('Servername')) AS Server,
msdb.dbo.backupset.database_name,
msdb.dbo.backupset.backup_start_date,
msdb.dbo.backupset.backup_finish_date,
msdb.dbo.backupset.expiration_date,
msdb.dbo.backupset.backup_size,
msdb.dbo.backupmediafamily.logical_device_name,
msdb.dbo.backupmediafamily.physical_device_name,
msdb.dbo.backupset.name AS backupset_name,
msdb.dbo.backupset.description,
CASE msdb..backupset.type
WHEN 'D' THEN 'Full Database'
WHEN 'L' THEN 'Log'
WHEN 'I' THEN 'Differential'
WHEN 'F' THEN 'File Level'
WHEN 'G' THEN 'File Level Differential'
WHEN 'P' THEN 'Partial'
WHEN 'Q' THEN 'Differential partial'
END AS backup_type
FROM msdb.dbo.backupmediafamily
INNER JOIN msdb.dbo.backupset ON msdb.dbo.backupmediafamily.media_set_id = msdb.dbo.backupset.media_set_id
) AS B
ON A.[server] = B.[server] AND A.[database_name] = B.[database_name] AND A.[last_db_backup_date] = B.[backup_finish_date]
ORDER BY
A.database_name
Use a CASE statement. I'll paste an example from my own work:
SELECT
cplnt.complainant_type AS complainant_type,
cpt.date_received AS complaint_received,
CASE WHEN cpt.date_closed IS NULL
THEN (CURRENT_DATE - cpt.date_received)
ELSE (cpt.date_closed - cpt.date_received)
END AS complaint_age,
cpt.id AS complaint_id,
cs.date_case_received AS case_received,
cs.case_status AS case_stage,
stg.stage AS complaint_stage,
tm.name AS team,
trg.date_completed AS triage_date,
trg.method AS triage_method,
cpt.date_closed AS resolution_date,
cpt.status AS closure_type,
cpt.resolution_type AS resolution_type,
cpt.estimated_time_spent AS CLO_time_investment
FROM
complaints_complaint AS cpt
INNER JOIN
complaints_complainant AS cplnt
ON
cpt.complainant_id = cplnt.id
LEFT OUTER JOIN
complaints_case AS cs
ON
cpt.case_id = cs.id
INNER JOIN
complaints_stage AS stg
ON
cpt.stage_id = stg.id
INNER JOIN
community_team AS tm
ON
cpt.team_id = tm.id
LEFT OUTER JOIN
schemes_scheme AS sc
ON
cs.scheme_id = sc.id
LEFT OUTER JOIN
(SELECT
t1.*,
MIN(date_completed) OVER(PARTITION BY complaint_id) AS seq
FROM
complaints_triage AS t1) AS trg
ON
trg.complaint_id = cpt.id AND trg.date_completed = trg.seq;

what is this code doing can not understand it

I am trying to figure out what a query is doing and I just do not understand why it would join its self to its self on multiple occassions highlighted bit is the piece i am talking about?
its the part that starts with the [SupplyStatusUpdated] = COALESCE( gas supply and gas supply history
USE [CRM];
SELECT gs.GasSupplyID,
[Account ID] = acc.AccountID,
[GMSReference] = cast(gms.SiteRefNum as varchar),
[AccountNumber] = cast(gms.AccountNum as varchar),
[Organisation Name] = prf.[Name] ,
con.DeclaredDate,
[Contract Date] = CAST(con.ContractDate AS DATE),
[Contract Version] = cv.Name,
[Contract Status] = cs.Name,
loa.ContractEndDate [LOA CED],
gs.CurrentSupplierEndDate [PrevSupplierEndDate],
loa.ContractEndDate,
con.StartDate,
[Supply Status] = gss.Name,
[SupplyStatusUpdated] = COALESCE(
(
SELECT TOP 1 MAX(gsh2.CreatedDate)
FROM GasSupply gs2
INNER JOIN GasSupplyHistory gsh2
ON gsh2.GasSupplyFK = gs2.GasSupplyID
WHERE gsh2.EventFK = 2
AND gsh2.Notes LIKE '%Gas Supply Status (%'
AND gsh2.GasSupplyFK = gs.GasSupplyID
GROUP BY gsh2.GasSupplyFK
),
(
SELECT TOP 1 MAX(gsh3.CreatedDate)
FROM GasSupplyHistory gsh3
INNER JOIN (
SELECT gsh4.GasSupplyFK, MAX(gsh4.EventFK) AS [MaxEvent]
FROM GasSupplyHistory gsh4
WHERE gsh4.GasSupplyFK = gs.GasSupplyID
GROUP BY gsh4.GasSupplyFK
HAVING MAX(gsh4.EventFK) = 1
) dt
ON dt.GasSupplyFK = gsh3.GasSupplyFK
)
),
[EAC] = gs.EstimatedAnnualConsumption,
[PreviousSupplier] = r.name,
[Branch] = b.name,
[LeadSource] = ls.name,
gs.UnitPrice,
gs.StandingCharge,
gs.WholesalePrice,
COALESCE(deal.weeknumber,DATEPART(ISOWK, con.[ContractDate])) AS [Week]
FROM acc.Account acc
INNER JOIN [Profile] prf
ON acc.ProfileFK = prf.ProfileID
INNER JOIN [Contract] con
ON acc.AccountID = con.AccountFK
INNER JOIN [loacontract] lo
ON lo.ContractFK = con.ContractID
LEFT join [LeadSource] ls
ON ls.LeadSourceID = con.LeadSourceFK
INNER JOIN [ContractStatus] cs
ON cs.ContractStatusID = con.ContractStatusFK
INNER JOIN [ContractVersion] cv
ON cv.ContractVersionID = con.ContractVersionFK
INNER JOIN GasSupply gs
ON gs.ContractFK = con.ContractID
INNER JOIN GasSupplyStatus gss
ON gss.GasSupplyStatusID = gs.GasSupplyStatusFK
LEFT JOIN Deal deal
ON deal.ContractFK = con.ContractID
OUTER APPLY GetGMSReferenceNumbers(con.ContractID) gms
LEFT JOIN Branch b
ON b.BranchID = deal.BranchFK
LEFT JOIN DealBroker bro
ON bro.DealFK = deal.DealID
AND bro.BrokerTypeFK = 36
LEFT JOIN Person p
ON p.PersonID = bro.EmployeeFK
LEFT JOIN Reseller r
ON r.ResellerID = gs.ResellerFK
LEFT JOIN (
SELECT l.contractfk,
MIN(l.contractenddate)[ContractEndDate]
FROM CRM.[contract].LOAContract l
GROUP BY l.ContractFK
) loa
ON loa.ContractFK = con.ContractID
WHERE acc.AccountID not in (
select AccountFK
from AccountOption
where OptionFK=9
)
AND cast(gms.SiteRefNum as varchar) IS NULL
COALESCE(Something, SomethingElse) says if the first argument is NULL, return the second argument (note that you can have more than 2 args and it'll just keep going down the list).
As such it's running the first sub-query, and if the result is NULL, returning the result of the second query. Why exactly is your business logic, which we can't answer :-)
(MSDN link on Coalesce)
COALESCE returns the first non-null value it finds, so if the GasSupply query returns a result it will use that: if that returns null it will see if the GasSupplyHistory query returns a result, and if so use that. If both queries return null then SupplyStatusUpdated will be null.
It joins to itself to get historical records from the same source as where it gets the current record.
Representation of historical data is is one common reason for using a BigData/NoSQL database instead of a SQL/Relational database.

Query Performance too Slow

Im having performance issues with this query. If I remove the status column it runs very fast but adding the subquery in the column section delays way too much the query 1.02 min. How can I modify this query so it runs fast getting the desired data.
The reason I put that subquery there its because I needed the status for the latest activity, some activities have null status so I have to ignore them.
Establishments: 6.5k rows -
EstablishmentActivities: 70k rows -
Status: 2 (Active, Inactive)
SELECT DISTINCT
est.id,
est.trackingNumber,
est.NAME AS 'establishment',
actTypes.NAME AS 'activity',
(
SELECT stat3.NAME
FROM SACPAN_EstablishmentActivities eact3
INNER JOIN SACPAN_ActivityTypes at3
ON eact3.activityType_FK = at3.code
INNER JOIN SACPAN_Status stat3
ON stat3.id = at3.status_FK
WHERE eact3.establishment_FK = est.id
AND eact3.rowCreatedDT = (
SELECT MAX(est4.rowCreatedDT)
FROM SACPAN_EstablishmentActivities est4
INNER JOIN SACPAN_ActivityTypes at4
ON est4.establishment_fk = est.id
AND est4.activityType_FK = at4.code
WHERE est4.establishment_fk = est.id
AND at4.status_FK IS NOT NULL
)
AND at3.status_FK IS NOT NULL
) AS 'status',
est.authorizationNumber,
reg.NAME AS 'region',
mun.NAME AS 'municipality',
ISNULL(usr.NAME, '') + ISNULL(+ ' ' + usr.lastName, '')
AS 'created',
ISNULL(usr2.NAME, '') + ISNULL(+ ' ' + usr2.lastName, '')
AS 'updated',
est.rowCreatedDT,
est.rowUpdatedDT,
CASE WHEN est.rowUpdatedDT >= est.rowCreatedDT
THEN est.rowUpdatedDT
ELSE est.rowCreatedDT
END AS 'LatestCreatedOrModified'
FROM SACPAN_Establishments est
INNER JOIN SACPAN_EstablishmentActivities eact
ON est.id = eact.establishment_FK
INNER JOIN SACPAN_ActivityTypes actTypes
ON eact.activityType_FK = actTypes.code
INNER JOIN SACPAN_Regions reg
ON est.region_FK = reg.code --
INNER JOIN SACPAN_Municipalities mun
ON est.municipality_FK = mun.code
INNER JOIN SACPAN_ContactEstablishments ce
ON ce.establishment_FK = est.id
INNER JOIN SACPAN_Contacts con
ON ce.contact_FK = con.id
--JOIN SACPAN_Status stat ON stat.id = actTypes.status_FK
INNER JOIN SACPAN_Users usr
ON usr.id = est.rowCreatedBy_FK
LEFT JOIN SACPAN_Users usr2
ON usr2.id = est.rowUpdatedBy_FK
WHERE (con.ssn = #ssn OR #ssn = '*')
AND eact.rowCreatedDT = (
SELECT MAX(eact2.rowCreatedDT)
FROM SACPAN_EstablishmentActivities eact2
WHERE eact2.establishment_FK = est.id
)
--AND est.id = 6266
ORDER BY 'LatestCreatedOrModified' DESC
Try moving that 'activiy' query to a Left Join and see if it speeds it up.
I solved the problem by creating a temporary table and creating an index to it, this removed the need of the slow subquery in the select statement. Then I join the temp table as I do with normal tables.
Thanks to all.

Microsoft SQL MAX() Not Including Rows with NULLs

I work in a law firm with a case management system which links an interface to a SQL db. I am writing queries in SSRS to run reports. I am trying to run a report on case information. Some of the information is right in the "cases" table (or vcases view), but I'm also trying to link information from a "demands_offers" table. Each case can have multiple demands and offers, so I am using a MAX function in a join to extract only the most recent demand record per case. Unfortunately, doing this eliminates cases which have no demands. I need all the cases to show up.
I have tried using a CASE statement nested in the MAX function to convert NULLS or empty fields to a random early date, but I still can't get all of the cases to appear in the report.
Any ideas? I am a relative newbie with SQL and have no formal training. Any help would be greatly appreciated. You can see the code below. (P.S. I don't think that I have the rights to create a temporary table.)
SELECT vc.case_number AS "Matter ID", vc.style, vc.atty2_name AS "Handling Attorney", m.max_demands_date, do.demands, do.demands_notes, sa.authorized,
(SELECT TOP 1 vl.computename
FROM vcases vca
LEFT OUTER JOIN case_parties cp
ON vca.case_sk = cp.case_sk
JOIN case_parties cpp
ON cp.parent_sk = cpp.case_parties_sk
JOIN vlegal_entity vl
ON vl.legal_entity_sk = cp.entity_sk
JOIN vlegal_entity vlp
ON vlp.legal_entity_sk = cpp.entity_sk
WHERE (vca.case_sk = vc.case_sk) AND (cpp.role_sk = '3557') AND (cp.role_sk = '3986') ) AS "Plaintiff//'s Attorney",
(SELECT cp.reference_number
FROM cases AS ca
LEFT OUTER JOIN case_parties AS cp
ON ca.case_sk = cp.case_sk
WHERE (cp.role_sk = '3706')
AND (ca.case_sk = vc.case_sk)) AS "Claim Number"
FROM
vcases vc
LEFT OUTER JOIN
case_parties cp ON vc.case_sk = cp.case_sk
LEFT OUTER JOIN
vlegal_entity vl ON cp.entity_sk = vl.legal_entity_sk
LEFT OUTER JOIN
settle_authority sa ON vc.case_sk = sa.case_sk
LEFT OUTER JOIN
demands_offers do ON vc.case_sk = do.case_sk
INNER JOIN
(SELECT DISTINCT max(
(CASE WHEN do.demands_date = '' THEN '1/1/1900 00:00:00'
ELSE do.demands_date
END)
) as "max_demands_date", vc.case_sk
FROM vcases AS vc
JOIN demands_offers AS do ON vc.case_sk = do.case_sk
GROUP BY vc.case_sk) AS m
ON vc.case_sk = m.case_sk AND
do.demands_date = m.max_demands_date
WHERE (vc.closed_ind = 'O') AND (cp.role_sk = '3816') AND (vl.client_number = 'EAS-01') AND (vc.lawtype_code <> 'FA')
ORDER BY vc.case_number
Your query can probably be written to be much more compact and better performing, but to start you off, this is the part that is removing the rows without demands:
INNER JOIN
(SELECT DISTINCT max(
(CASE WHEN do.demands_date = '' THEN '1/1/1900 00:00:00'
ELSE do.demands_date
END)
) as "max_demands_date", vc.case_sk
FROM vcases AS vc
JOIN demands_offers AS do ON vc.case_sk = do.case_sk
GROUP BY vc.case_sk) AS m
ON vc.case_sk = m.case_sk AND
do.demands_date = m.max_demands_date
It needs to be
LEFT JOIN
(SELECT DISTINCT max(
(CASE WHEN do.demands_date = '' THEN '1/1/1900 00:00:00'
ELSE do.demands_date
END)
) as "max_demands_date", vc.case_sk
FROM vcases AS vc
JOIN demands_offers AS do ON vc.case_sk = do.case_sk
GROUP BY vc.case_sk) AS m
ON vc.case_sk = m.case_sk AND
do.demands_date = m.max_demands_date
The reason is that an (A INNER JOIN B) keeps records only when it is possible to match rows in A to rows in B. When there is no demand, the derived table (subquery) returns NULL for max_demands_date, which cannot be matched by do.demands_date = m.max_demands_date. This causes the case record to get removed.