SELECT /*+ PARALLEL(cfe, 6) */
dpd.f_p_descr,
ef.t_a_code,
pd.p_name,
ef.t_q
FROM e_fact ef
INNER JOIN d_dim dd
ON ef.t_d_key = dd.d_key
INNER JOIN f_e cfe
ON ef.ref_id = cfe.t_id
AND ef.r_version = cfe.t_version
INNER JOIN d_dim dpd
ON dpd.d_key = ef.d_key
INNER JOIN p_dim pd
ON pd.p_key = ef.b_p_key
INNER JOIN r_dim rd
ON rd.r_key = ef.t_r_key
INNER JOIN f_t_dim ftd
ON ftd.t_key = cfe.t_key
WHERE dd.d_value = '19-OCT-2012'
AND dpd.f_d = 'XYZ'
AND ftd.s_id IN (201, 209)
AND rd.r_n = 'ABC'
I got this query from production, problem is optimizer refuses to use the index on f_e even when the hint is added (/*+ index(e.c_fact_idx12) */. What should be my approach and what all things I need to check for this. Is there any other way to tune this query? New to query tuning so help would be appreciated.
You are using e.c_fact_idx12, but the table alias e is not defined anywhere in the query !
Related
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
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.
I'm trying to pass this query to inner join, but it does not know how?
This is the query I want to use InnerJoin with these values where
SELECT
ticket.id_ticket,
ticket.id_rede,
historico.id_historico,
historico.id_ticket,
centro.id_centro,
eqpto.id_eqpto,
eqpto.nome,
centro.sigla_centro,
interface.id_interface,
interface.id_eqpto,
interface.desig,
tecnologia.descricao,
interface.id_tecnologia,
tecnologia.id_tecnologia,
eqpto.id_centro,
eqpto.id_rede
FROM
app_gpa_ticket.ticket,
app_gpa_ticket.historico,
dados_v3.centro,
dados_v3.eqpto,
dados_v3.interface,
dados_v3.tecnologia
WHERE
ticket.id_ticket = historico.id_ticket AND
centro.id_centro = eqpto.id_centro AND
eqpto.id_eqpto = interface.id_eqpto AND
eqpto.id_rede = ticket.id_rede AND
tecnologia.id_tecnologia = interface.id_tecnologia;
Thank you!
I think you are trying to go to the standard (explicit) syntax. What you need to do is take what would be your JOIN operators in the WHERE clause and move them near the table itself. What you need to know is what tables on the left (Before the INNER JOIN operator you are joining to the right (After the INNER JOIN operator)
SELECT
ticket.id_ticket,
ticket.id_rede,
historico.id_historico,
historico.id_ticket,
centro.id_centro,
eqpto.id_eqpto,
eqpto.nome,
centro.sigla_centro,
interface.id_interface,
interface.id_eqpto,
interface.desig,
tecnologia.descricao,
interface.id_tecnologia,
tecnologia.id_tecnologia,
eqpto.id_centro,
eqpto.id_rede
FROM app_gpa_ticket.ticket
INNER JOIN app_gpa_ticket.historico ON ticket.id_ticket = historico.id_ticket
INNER JOIN dados_v3.eqpto ON eqpto.id_rede = ticket.id_rede
INNER JOIN dados_v3.interface ON eqpto.id_eqpto = interface.id_eqpto
INNER JOIN dados_v3.centro ON centro.id_centro = eqpto.id_centro
INNER JOIN dados_v3.tecnologia ON tecnologia.id_tecnologia = interface.id_tecnologia
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..
I am running the following query:
SELECT fat.*
FROM Table1 fat
LEFT JOIN modo_captura mc ON mc.id = fat.modo_captura_id
INNER JOIN loja lj ON lj.id = fat.loja_id
INNER JOIN rede rd ON rd.id = fat.rede_id
INNER JOIN bandeira bd ON bd.id = fat.bandeira_id
INNER JOIN produto pd ON pd.id = fat.produto_id
INNER JOIN loja_extensao le ON le.id = fat.loja_extensao_id
INNER JOIN conta ct ON ct.id = fat.conta_id
INNER JOIN banco bc ON bc.id = ct.banco_id
LEFT JOIN conciliacao_vendas cv ON fat.empresa_id = cv.empresa_id AND cv.chavefato = fat.chavefato AND fat.rede_id = cv.rede_id
WHERE 1 = 1
AND cv.controle_upload_arquivo_id = 6906
AND fat.parcela = 1
ORDER BY fat.data_venda, fat.data_credito limit 20
But very slowly. Here the Explain plan: http://explain.depesz.com/s/DnXH
Try this rewritten version:
SELECT fat.*
FROM Table1 fat
JOIN conciliacao_vendas cv USING (empresa_id, chavefato, rede_id)
JOIN loja lj ON lj.id = fat.loja_id
JOIN rede rd ON rd.id = fat.rede_id
JOIN bandeira bd ON bd.id = fat.bandeira_id
JOIN produto pd ON pd.id = fat.produto_id
JOIN loja_extensao le ON le.id = fat.loja_extensao_id
JOIN conta ct ON ct.id = fat.conta_id
JOIN banco bc ON bc.id = ct.banco_id
LEFT JOIN modo_captura mc ON mc.id = fat.modo_captura_id
WHERE cv.controle_upload_arquivo_id = 6906
AND fat.parcela = 1
ORDER BY fat.data_venda, fat.data_credito
LIMIT 20;
JOIN syntax and sequence of joins
In particular I fixed the misleading LEFT JOIN to conciliacao_vendas, which is forced to act as a plain [INNER] JOIN by the later WHERE condition anyways. This should simplify query planning and allow to eliminate rows earlier in the process, which should make everything a lot cheaper. Related answer with detailed explanation:
Explain JOIN vs. LEFT JOIN and WHERE condition performance suggestion in more detail
USING is just a syntactical shorthand.
Since there are many tables involved in the query and the order the rewritten query joins tables is optimal now, you can fine-tune this with SET LOCAL join_collapse_limit = 1 to save planning overhead and avoid inferior query plans. Run in a single transaction:
BEGIN;
SET LOCAL join_collapse_limit = 1;
SELECT ...; -- read data here
COMMIT; -- or ROOLBACK;
More about that:
Sample Query to show Cardinality estimation error in PostgreSQL
The fine manual on Controlling the Planner with Explicit JOIN Clauses
Index
Add some indexes on lookup tables with lots or rows (not necessary for just a couple of dozens), in particular (taken from your query plan):
Seq Scan on public.conta ct ... rows=6771
Seq Scan on public.loja lj ... rows=1568
Seq Scan on public.loja_extensao le ... rows=16394
That's particularly odd, because those columns look like primary key columns and should already have an index ...
So:
CREATE INDEX conta_pkey_idx ON public.conta (id);
CREATE INDEX loja_pkey_idx ON public.loja (id);
CREATE INDEX loja_extensao_pkey_idx ON public.loja_extensao (id);
To make this really fat, a multicolumn index would be of great service:
CREATE INDEX foo ON Table1 (parcela, data_venda, data_credito);