How to optimize Sybase Sql query? - sql

I have one SQL query that fetches data from Sybase database. In the where clause we use text columns based on the requirement (BU IN ('CMBS','MBS') AND RU='GBR'). These clauses are killing the performance. The tables used have large number of rows.
Any suggestions to improve performance?
Below is the SQL-
SELECT [COLUMN LIST]
from dealer_Key dk,
INNER JOIN d_posting dp ON dk.deal_key_id = dp.deal_key_id,
INNER JOIN d_p_v dpv ON dp.posting_id = dpv.posting_id,
INNER JOIN snapInfo s ON dpv.snapshot_start_id = s.snapshot_id,
INNER JOIN psgl_ratemeter r ON (dp.gl_currency = r.from_currency),
INNER JOIN psgl_ratemeter_value rv (ON r.psgl_rate_id = rv.psgl_rate_id AND rv.refdate = dpv.gl_transaction_effective_date)
where
r.snapshot_end_id is null
and r.to_currency = 'AUD'
and (dp.snapshot_end_id is null or dp.snapshot_end_id > dpv.snapshot_start_id)
and dpv.gl_transaction_effective_date > '20140930'
and dpv.gl_transaction_effective_date < '20150901'
and gl_business_unit IN ('CTCMB')
and gl_currency='CAD'
and gl_counterparty='IMCLIMTR'
and gl_location='SYD'
and gl_department='LTFSY'
and gl_product='FEES'

Related

Speed up SQL query performance with nested queries

Could anyone help me speed this query up? It currently take 17 minutes to run but does return the correct data and it populates a subform in MS Access. Functions in the rest of the VBA are declared as long to try to speed up more.
Here's the full query:
SELECT lots of things
FROM (((((((((((((((ngstest
INNER JOIN patients
ON ngstest.internalpatientid = patients.internalpatientid)
INNER JOIN referral
ON ngstest.referralid = referral.referralid)
INNER JOIN checker
ON ngstest.bookby = checker.check1id)
INNER JOIN ngspanel
ON ngstest.ngspanelid = ngspanel.ngspanelid)
LEFT JOIN ngspanel AS ngspanel_1
ON ngstest.ngspanelid_b = ngspanel_1.ngspanelid)
INNER JOIN status
ON ngstest.statusid = status.statusid)
INNER JOIN dbo_patient_table
ON patients.patientid = dbo_patient_table.patienttrustid)
LEFT JOIN dna
ON ngstest.dna = dna.dnanumber)
INNER JOIN status AS status_1
ON patients.s_statusoverall = status_1.statusid)
LEFT JOIN gw_gendertable
ON dbo_patient_table.genderid = gw_gendertable.genderid)
LEFT JOIN ngswesbatch
ON ngstest.wesbatch = ngswesbatch.ngswesbatchid)
LEFT JOIN checker AS checker_1
ON ngstest.check1id = checker_1.check1id)
LEFT JOIN checker AS checker_2
ON ngstest.check2id = checker_2.check1id)
LEFT JOIN checker AS checker_3
ON ngstest.check3id = checker_3.check1id)
LEFT JOIN ngspanel AS ngspanel_2
ON ngstest.ngspanelid_c = ngspanel_2.ngspanelid)
LEFT JOIN checker AS checker_4
ON ngstest.check4id = checker_4.check1id
WHERE ((ngstest.referralid IN
(SELECT referralid FROM referral
WHERE grouptypeid = 14)
AND ngstest.ngstestid IN
(SELECT ngstest.ngstestid
FROM ngsanalysis
INNER JOIN ngstest
ON ngsanalysis.ngstestid = ngstest.ngstestid
WHERE ngsanalysis.pedigree = 3302) )
AND status.statusid = 1202218800)
ORDER BY ngstest.priority,
ngstest.daterequested;
The two nested queries are strings from elsewhere in the code so are called in the vba as " & includereferralls & " And " & ParentsStatusesFilter & "
They are:
ParentsStatusesFilter = "NGSTest.NGSTestID in
(SELECT NGSTest.NGSTestID
FROM NGSAnalysis
INNER JOIN NGSTest
ON NGSAnalysis.NGSTestID = NGSTest.NGSTestID
WHERE NGSAnalysis.Pedigree IN (3302,3303,3304)"
And
includereferrals = "NGSTest.ReferralID
(SELECT referralid FROM referral WHERE referral.grouptypeid = 14)"
The query needs to remain readable (and therefore editable) so can't use things like Distinct, Group By or contain any Unions. Have tried Exists instead of In for the nested queries but that stops it from actually filtering the results.
WHERE EXISTS (SELECT NGSTest.NGSTestID
FROM NGSAnalysis
INNER JOIN NGSTest
ON NGSAnalysis.NGSTestID = NGSTest.NGSTestID
WHERE NGSAnalysis.Pedigree IN (3302,3303,3304)
So the exist clause you have there isn't tied to the outer query which would run similar to just added 1 = 1 to the where clause. I took your where clause and converted it. It should look something like this...
WHERE EXISTS (
SELECT referralid
FROM referral
WHERE grouptypeid = 14 AND ngstest.referralid = referral.referralid)
AND EXISTS (
SELECT ngsanalysis.ngstestid
FROM ngsanalysis
WHERE ngsanalysis.pedigree IN (3302,3303,3304) AND ngstest.ngstestid = ngsanalysis.ngstestid
)
AND status.statusid = 1202218800
Adding exists will speed it up a bit, but the the bulk of the slowness is the left joins. Access does not handle the left joins as well as SQL Server does. Change all your joins to inner joins and you will see the query runs very fast. This is obviously not ideal since some relationships are optional. What I have done to get around this is add a default record that replaces a null relationship.
Here is what that looks like for you: In the checker table you could add a record that represents a null value. So put a record into the checker table with check1id of -1 or 0. Then default check1id, check2id, check3id on ngstest to -1 or 0. You will need to do that type of thing for all tables you need to left join on.

How to improve SQL inner join performance?

How improve this query performance second table CustomerAccountBrand inner join
taking long time. I have added Non clustered index that is not use. Is this is split two inner join after that able concatenate?. Please any one help to get that data.
SELECT DISTINCT
RA.AccountNumber,
RA.ShipTo,
RA.SystemCode,
CAB.BrandCode
FROM dbo.CustomerAccountRelatedAccounts RA -- Views
INNER JOIN dbo.CustomerAccount CA
ON RA.RelatedAccountNumber = CA.AccountNumber
AND RA.RelatedShipTo = CA.ShipTo
AND RA.RelatedSystemCode = CA.SystemCode
INNER JOIN dbo.CustomerAccountBrand CAB ---- Taking long time 4:30 mins
ON CA.AccountNumber = CAB.AccountNumber
AND CA.ShipTo = CAB.ShipTo
AND CA.SystemCode = CAB.SystemCode
ALTER VIEW [dbo].[CustomerAccountRelatedAccounts]
AS
SELECT
ca.AccountNumber, ca.ShipTo, ca.SystemCode, cafg.AccountNumber AS RelatedAccountNumber, cafg.ShipTo AS RelatedShipTo,
cafg.SystemCode AS RelatedSystemCode
FROM dbo.CustomerAccount AS ca
LEFT OUTER JOIN dbo.CustomerAccount AS cafg
ON ca.FinancialGroup = cafg.FinancialGroup
AND ca.NationalAccount = cafg.NationalAccount
AND cafg.IsActive = 1
WHERE CA.IsActive = 1
From my experience, the SQL server query optimizer often fails to pick the correct join algorithm when queries become more complex (e.g. joining with your view means that there's no index readily available to join on). If that's what's happening here, then the easy fix is to add a join hint to turn it into a hash join:
SELECT DISTINCT
RA.AccountNumber,
RA.ShipTo,
RA.SystemCode,
CAB.BrandCode
FROM dbo.CustomerAccountRelatedAccounts RA -- Views
INNER JOIN dbo.CustomerAccount CA
ON RA.RelatedAccountNumber = CA.AccountNumber
AND RA.RelatedShipTo = CA.ShipTo
AND RA.RelatedSystemCode = CA.SystemCode
INNER HASH JOIN dbo.CustomerAccountBrand CAB ---- Note the "HASH" keyword
ON CA.AccountNumber = CAB.AccountNumber
AND CA.ShipTo = CAB.ShipTo
AND CA.SystemCode = CAB.SystemCode

Improve query in stored procedure

I need to improve this query inside a stored procedure, the performance with lots of data broke the application. Is there any way to make it faster?
I need to collect certain columns from several tables to build a dashboard in my app web, others columns I collected in other query and joined in my controller through classes.
EDIT: this query is a part from dynamically transaction, they can change the database.
SELECT
a.fact_num as cotizacion, a.comentario, m.co_cli, k.cli_des,
m.co_ven, l.ven_des, m.fec_emis, m.fec_venc, m.campo8,
a.reng_num, a.co_art, g.art_des, a.co_alma, b.fact_num as pedido,
c.fact_num as factura, d.fact_num as despacho, e.cob_num as cobro,
f.fec_venc as fecha_venc, f.fec_emis as fecha_pedido,
h.odp_num as ord_produccion, h.co_ced as cedula, i.req_num as requisicion,
j.ent_num as cierre
FROM
reng_cac a
LEFT JOIN
cotiz_c m ON a.fact_num = m.fact_num
LEFT JOIN
reng_ped b ON a.co_art = b.co_art AND a.fact_num = b.num_doc AND b.tipo_doc = 'T'
LEFT JOIN
pedidos f ON b.fact_num = f.fact_num
LEFT JOIN
reng_fac c ON b.fact_num = c.num_doc AND a.co_art = c.co_art AND c.tipo_doc = 'P'
LEFT JOIN
reng_ndd d ON c.fact_num = d.num_doc AND a.co_art = d.co_art AND d.tipo_doc = 'F'
LEFT JOIN
reng_cob e ON c.fact_num = e.doc_num AND e.tp_doc_cob = 'FACT'
LEFT JOIN
art g ON a.co_art = g.co_art
LEFT JOIN
spodp h ON b.fact_num = h.doc_ori AND b.co_art = h.co_art
LEFT JOIN
spreqalm i ON h.odp_num = i.odp_num
LEFT JOIN
spcierre j ON h.odp_num = j.odp_num
LEFT JOIN
clientes k ON m.co_cli = k.co_cli
LEFT JOIN
vendedor l ON m.co_ven = l.co_ven
WHERE
a.fact_num BETWEEN '0' AND '999999999'
AND m.fec_emis BETWEEN '01/01/2012' AND '30/06/2012'
AND m.co_cli BETWEEN '' AND 'þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ'
ORDER BY
a.fact_num, a.reng_num ASC
As Nick commented, you always need to run your query in a execution plan. There are some points you need to consider. For instance, having a lot of LEFT JOINs will reduce the performance. Try to see if you can use INNER JOINs where possible. Check if you have proper indexes. If you can attach your execution plan to your question, you will get more helpful answers.

Is there a better way to write this Oracle SQL query?

I have been using Oracle SQL for around 6 months so still a beginner. I need to query the database to get information on all items on a particular order (order number is via $_GET['id']).
I have come up with the below query, it works as expected and as I need but I do not know whether I am over complicating things which would slow the query down at all. I understand there are a number of ways to do a single thing and there may be better methods to write this query since I am a beginner.
I am using Oracle 8i (due to this is the version an application we use is supplied with) so I believe that some JOIN etc. are not available in this version, but is there a better way to write a query such as the below?
SELECT auf_pos.auf_pos,
(SELECT auf_stat.anz
FROM auf_stat
WHERE auf_stat.auf_pos = auf_pos.auf_pos
AND auf_stat.auf_nr = ".$_GET['id']."),
(SELECT auf_text.zl_str
FROM auf_text
WHERE auf_text.zl_mod = 0
AND auf_text.auf_pos = auf_pos.auf_pos
AND auf_text.auf_nr = ".$_GET['id']."),
(SELECT glas_daten_basis.gl_bez
FROM glas_daten_basis
WHERE glas_daten_basis.idnr = auf_pos.glas1),
(SELECT lzr_daten.lzr_breite
FROM lzr_daten
WHERE lzr_daten.lzr_idnr = auf_pos.lzr1),
(SELECT glas_daten_basis.gl_bez
FROM glas_daten_basis
WHERE glas_daten_basis.idnr = auf_pos.glas2),
auf_pos.breite,
auf_pos.hoehe,
auf_pos.spr_jn
FROM auf_pos
WHERE auf_pos.auf_nr = ".$_GET['id']."
Thanks in advance to any Oracle gurus that could help this beginner out!
You could rewrite it using joins. If your subselects aren't expected to return any NULL values, then you can use INNER JOINS:
SELECT auf_pos.auf_pos,
auf_stat.anz,
auf_text.zl_str,
glas_daten_basis.gl_bez,
lzr_daten.lzr_breite,
glas_daten_basis.gl_bez,
auf_pos.breite,
auf_pos.hoehe,
auf_pos.spr_jn
FROM auf_pos
INNER JOIN auf_stat ON auf_stat.auf_pos = auf_pos.auf_pos AND auf_stat.auf_nr = ".$_GET['id'].")
INNER JOIN auf_text ON auf_text.zl_mod = 0 AND auf_text.auf_pos = auf_pos.auf_pos AND auf_text.auf_nr = ".$_GET['id'].")
INNER JOIN glas_daten_basis ON glas_daten_basis.idnr = auf_pos.glas1
INNER JOIN lzr_daten ON lzr_daten.lzr_idnr = auf_pos.lzr1
INNER JOIN glas_daten_basis ON glas_daten_basis.idnr = auf_pos.glas2
Or if there are cases where you wouldn't have matches on all the tables, you could replace the INNER joins with LEFT OUTER joins:
SELECT auf_pos.auf_pos,
auf_stat.anz,
auf_text.zl_str,
glas_daten_basis.gl_bez,
lzr_daten.lzr_breite,
glas_daten_basis.gl_bez,
auf_pos.breite,
auf_pos.hoehe,
auf_pos.spr_jn
FROM auf_pos
LEFT OUTER JOIN auf_stat ON auf_stat.auf_pos = auf_pos.auf_pos AND auf_stat.auf_nr = ".$_GET['id'].")
LEFT OUTER JOIN auf_text ON auf_text.zl_mod = 0 AND auf_text.auf_pos = auf_pos.auf_pos AND auf_text.auf_nr = ".$_GET['id'].")
LEFT OUTER JOIN glas_daten_basis ON glas_daten_basis.idnr = auf_pos.glas1
LEFT OUTER JOIN lzr_daten ON lzr_daten.lzr_idnr = auf_pos.lzr1
LEFT OUTER JOIN glas_daten_basis ON glas_daten_basis.idnr = auf_pos.glas2
Whether or not you see any performance gains is debatable. As I understand it, the Oracle query optimizer should take your query and execute it with a similar plan to the join queries, but this is dependent on a number of factors, so the best thing to do it give it a try..

JOIN syntax and order for multiple tables

SQL Gurus,
I have a query that uses the "old" style of join syntax as follows using 7 tables (table and column names changed to protect the innocent), as shown below:
SELECT v1_col, p1_col
FROM p1_tbl, p_tbl, p2_tbl, p3_tbl, v1_tbl, v2_tbl, v3_tbl
WHERE p1_code = 1
AND v1_code = 1
AND p1_date >= v1_date
AND p_uid = p1_uid
AND p2_uid = p1_uid AND p2_id = v2_id
AND p3_uid = p1_uid AND p3_id = v3_id
AND v2_uid = v1_uid
AND v3_uid = v1_uid
The query works just fine and produces the results it is supposed to, but as an academic exercise, I tried to rewrite the query using the more standard JOIN syntax, for example, below is one version I tried:
SELECT V1.v1_col, P1.p1_col
FROM p1_tbl P1, v1_tbl V1
JOIN p_tbl P ON ( P.p_uid = P1.p1_uid )
JOIN p2_tbl P2 ON ( P2.p2_uid = P1.p1_uid AND P2.p2_id = V2.v2_id )
JOIN p3_tbl P3 ON ( P3.p3_uid = P1.p1_uid AND P3.p3_id = V3.v3_id )
JOIN v2_tbl V2 ON ( V2.v2_uid = V1.v1_uid )
JOIN v3_tbl V3 ON ( V3.v3_uid = V1.v1_uid )
WHERE P1.p1_code = 1
AND V1.v1_code = 1
AND P1.p1_date >= V1.v1_date
But, no matter how I arrange the JOINs (using MS SQL 2008 R2), I keep running into the error:
The Multi-part identifier "col-name" could not be bound,
where "col-name" varies depending on the order of the JOINs I am attempting...
Does anyone have any good examples on how use the JOIN syntax with this number of tables??
Thanks in advance!
When you use JOIN-syntax you can only access columns from tables in your current join or previous joins. In fact it's easier to write the old syntax, but it's more error-prone, e.g. you can easily forget a join-condition.
This should be what you want.
SELECT v1_col, p1_col
FROM p1_tbl
JOIN v1_tbl ON p1_date >= v1_date
JOIN v2_tbl ON v2_uid = v1_uid
JOIN v3_tbl ON v3_uid = v1_uid
JOIN p_tbl ON p_uid = p1_uid
JOIN p2_tbl ON p2_uid = p1_uid AND p2_id = v2_id
JOIN p3_tbl ON p3_uid = p1_uid AND p3_id = v3_id
WHERE p1_code = 1
AND v1_code = 1
You are not naming the tables in your join such that it doesn't know which column is from which table. Try something like:
SELECT a.v1_col, b.p1_col
FROM p1_tbl b
JOIN p_tbl a ON b.p_uid = a.p1_uid
WHERE b.p1_code = 1
From your query above, I am assuming a naming convention of p2_uid comes from p2_tbl. Below id my best interpretation of WHERE joins to using INNER joins.
SELECT
v1_col, p1_col
FROM
p1_tbl
INNER JOIN p1_tbl
ON p1_tbl.p1_date >= v1_tbl.v1_date
INNER JOIN p_tbl
ON p_tbl.p_uid = p1_tbl.p1_uid
INNER JOIN p2_tbl
ON p2_tbl.p2_uid = p1_tbl.p1_uid
INNER JOIN v2_tbl
ON p2_tbl.p2_id = v2_tbl.v2_id
INNER JOIN p3_tbl
ON p3_tbl.p3_uid = p1_tbl.p1_uid
INNER JOIN v3_tbl
ON p3_tbl.p3_id = v3_tbl.v3_id
INNER JOIN v1_tbl
ON v1_tbl.v1_uid = v2_tbl.v2_uid
AND v1_tbl.v1_uid = v3_tbl.v2_uid
WHERE
p1_code = 1
AND
v1_code = 1
Some general points I have found useful in SQL statements with many joins.
Always fully qualify the names. I.e dont use ID , rahter use
TableName.ID
Dont use aliases unless there is meaning. (I.e. joining a table to
its self where aliasing is needed.)