Left join causing headache - sql

I am troubleshooting a process that is running a very long time, This select statemet runs for over 30 minutes, when i comment out various parts of it, it runs very fast. i have put a * next to the Tables that appear to be causing the issue , the one with two ** has a clustered index on Empid and ChangeDate(these columns are not next to each other) not sure if that matters, also none of these tables has more than 3000 rows. I am hoping there is some simple tweak hat needs to be made. Is there something i should look at in source tables? any suggestions would be appreciated. i have googled 'multiple out joins in single statement' with no luck. For troubleshooting purposes i put the with(nolock) in.
select
je.EmpID,
max(med.ChangeDate) as Max_Medical_ChangeDate,
max(den.ChangeDate) as Max_Dental_ChangeDate,
max(k.ChangeDate) as Max_401K_ChangeDate,
max(ltd.ChangeDate) as Max_LTD_ChangeDate,
max(std.ChangeDate) as Max_STD_ChangeDate,
max(life.ChangeDate) as Max_Life_ChangeDate,
max(sal.ChangeDate) as Max_Salary_ChangeDate,
max(ltdexe.ChangeDate) as Max_LTDEXE_ChangeDate
max(accid.ChangeDate) as Max_Accid_ChangeDate,
max(cancr.ChangeDate) as Max_Cancr_ChangeDate,
max(hosp.ChangeDate) as Max_Hosp_ChangeDate
from Judge_Emp je WITH(NOLOCK)
left join Medical med on je.EmpID = med.EmpID
left join Dental den on med.EmpID = den.EmpID
left join R401K k on den.EmpID = k.EmpID
left join STDIns std on k.EmpID = std.EmpID
left join LTDIns ltd on std.EmpID = ltd.EmpID
* left join LTDEXEIns ltdexe on ltd.EmpID = ltdexe.EmpID
** left join LifeIns life on ltdexe.EmpID = life.EmpID
* left join Salary sal on life.EmpID = sal.EmpID
left join AF_Accid accid on accid.EmpID=sal.EmpID
left join AF_Cancr cancr on cancr.EmpID=accid.EmpID
left join AF_Hosp hosp on hosp.EmpID=cancr.EmpID
group by je.EmpID
Thanks

This is too long for a comment.
If you are using left outer joins, your join conditions should refer to the first table in the chain. For instance:
from Judge_Emp je WITH(NOLOCK)
left join Medical med on je.EmpID = med.EmpID
left join Dental den on je.EmpID = den.EmpID
left join R401K k on je.EmpID = k.EmpID . . .
Rather than:
from Judge_Emp je WITH(NOLOCK)
left join Medical med on je.EmpID = med.EmpID
left join Dental den on med.EmpID = den.EmpID
left join R401K k on den.EmpID = k.EmpID . . .
The reasons is that med.EmptID could be NULL, which would cause the join to fail. (It doesn't make a difference for inner joins).
This probably doesn't affect the performance of the query, though. My guess is that these have multiple matching rows and are generating a Cartesian product for each customer.

Related

Access 'Join not supported' Moving LEFT Join

I've done some research here and I understand that in Access nested joins cause issues.
I believe that is the issue in the first example.
SELECT
Recipe_Classes.RecipeClassDescription,
Recipes.RecipeTitle,
Recipes.Preparation,
Ingredients.IngredientName,
Recipe_Ingredients.RecipeSeqNo,
Recipe_Ingredients.Amount,
Measurements.MeasurementDescription
FROM (((
Recipe_Classes
LEFT JOIN Recipes
ON Recipe_Classes.RecipeClassID = Recipes.RecipeClassID)
INNER JOIN Recipe_Ingredients
ON Recipes.RecipeID = Recipe_Ingredients.RecipeID)
INNER JOIN Ingredients
ON Ingredients.IngredientID = Recipe_Ingredients.IngredientID)
INNER JOIN Measurements
ON Measurements.MeasureAmountID = Recipe_Ingredients.MeasureAmountID
ORDER BY RecipeTitle, RecipeSeqNo;
I made an attempt to remove the nesting and created a right join in this example
SELECT
Recipe_Classes.RecipeClassDescription,
Recipes.RecipeTitle,
Recipes.Preparation,
Ingredients.IngredientName,
Recipe_Ingredients.RecipeSeqNo,
Recipe_Ingredients.Amount,
Measurements.MeasurementDescription
FROM (((
Ingredients
INNER JOIN Recipe_Ingredients
ON Ingredeints.IngredientID = Recipe_Ingredients.IngredientID)
INNER JOIN Measurements
ON Measurements.MeasureAmountID = Recipe_Ingredients.MeasureAmountID)
INNER JOIN Recipes
ON Recipes.RecipeID = Recipe_Ingredients.RecipeID)
RIGHT JOIN Recipe_Classes
ON Recipe_Classes.RecipeClassID = Recipes.RecipeClassID
ORDER BY RecipeTitle, RecipeSeqNo;
Can anyone point me in the right direction?
The issue may be the left join that is not needed. Try this from clause:
SELECT Recipe_Classes.RecipeClassDescription,
Recipes.RecipeTitle,
Recipes.Preparation,
Ingredients.IngredientName,
Recipe_Ingredients.RecipeSeqNo,
Recipe_Ingredients.Amount,
Measurements.MeasurementDescription
FROM (((Recipes LEFT JOIN
Recipe_Classes
ON Recipe_Classes.RecipeClassID = Recipes.RecipeClassID
) LEFT JOIN
Recipe_Ingredients
ON Recipes.RecipeID = Recipe_Ingredients.RecipeID
) LEFT JOIN
Ingredients
ON Ingredients.IngredientID = Recipe_Ingredients.IngredientID
) LEFT JOIN Measurements
ON Measurements.MeasureAmountID = Recipe_Ingredients.MeasureAmountID
ORDER BY RecipeTitle, RecipeSeqNo;
Once you start with LEFT JOINs, generally all the remaining joins should also be LEFT JOINs.
Since your main focal point table is Recipe_Ingredients, consider starting with this table in FROM and then JOIN the other parent tables and even nest the Recipes and Recipe_Classes pair:
SELECT
c.RecipeClassDescription,
r.RecipeTitle,
r.Preparation,
i.IngredientName,
ri.RecipeSeqNo,
ri.Amount,
m.MeasurementDescription
FROM
((Recipe_Ingredients ri
INNER JOIN (Recipes r
RIGHT JOIN Recipe_Classes c
ON c.RecipeClassID = r.RecipeClassID)
ON r.RecipeID = ri.RecipeID)
INNER JOIN Ingredients i
ON i.IngredientID = ri.IngredientID)
INNER JOIN Measurements m
ON m.MeasureAmountID = ri.MeasureAmountID
ORDER BY r.RecipeTitle, ri.RecipeSeqNo;
Of course this is untested without data. Due to Access' JOIN requirements like parnetheses, it is often recommended for new users to build complex queries with MS Access' GUI Query Design then modify generated SQL as needed.

Why my MariaDB query takes so long? How can I fix it?

SELECT
ps_customer.id_customer
CONCAT(ps_customer.firstname," ",ps_customer.lastname) AS "Fullname"
ps_customer.email
ps_customer.date_add
ps_orders.id_order
ps_orders.id_address_delivery
ps_orders.payment
ps_stripepro_transaction.status
ps_order_detail.id_shop
ps_order_detail.product_name
ps_address.address1
ps_address.address2
ps_address.postcode
ps_address.city
ps_address.phone
ps_address.phone_mobile
ps_vd_customer_dogs.name
ps_vd_customer_dogs.size
ps_vd_customer_dogs.breed
ps_vd_customer_dogs.toy_destroyer
ps_order_cart_rule.name
ps_order_cart_rule.value
ps_order_detail.product_quantity
ps_message.message
FROM ps_orders
LEFT JOIN ps_customer
ON ps_orders.id_customer = ps_customer.id_customer
LEFT JOIN ps_stripepro_transaction
ON ps_orders.id_order = ps_stripepro_transaction.id_order
LEFT JOIN ps_order_detail
ON ps_orders.id_order = ps_order_detail.id_order
LEFT JOIN ps_address
ON ps_orders.id_customer = ps_address.id_customer
LEFT JOIN ps_vd_customer_dogs
ON ps_orders.id_customer = ps_vd_customer_dogs.id_customer
LEFT JOIN ps_order_cart_rule
ON ps_orders.id_order = ps_order_cart_rule.id_order
LEFT JOIN ps_message
ON ps_orders.id_customer = ps_message.id_customer
ORDER BY ps_orders.id_order DESC
This is my query. If I shorten it and reduce it to the first 4 left joins, I get the results in 10 min, but when I add the other joins I have to wait over 3 hours.
How can I improve this? My objective is to create a CSV with all the data I'm selecting so that we can improve many people's job in my office who have to check many parameters for each client in our PrestaShop backoffice.

Postgresql - Conditional Join if data exist

My current query show the data from the table called "Buque" and has some references from another tables. The problem is when i execute the query it never shows the result because it consumes too much memory i guess.
The current query i have
select buq.buq_codigo, tbu.tbu_codigo, tbu.tbu_nombre, pai.pai_codigo, pai.pai_nombre,
pue.pto_codigo, pue.pto_nombre, lin.lin_codigo, lin.lin_nombre, tra.tra_codigo,
tra.tra_nombre, buq.buq_nombre, buq.buq_des, buq.num_trb, buq.num_eslora,
buq.max_tons, buq.reg_lloyd, buq.buq_codigo1, buq.codigo_omi,
case buq.buq_estado when 'A' then 'Activo' else 'Inactivo' end as buq_estado
from publico.mae_buque as buq, publico.mae_tipbuque as tbu, publico.mae_pais as pai,
publico.mae_puerto as pue, publico.mae_linea as lin, publico.mae_trafico as tra
where buq.tbu_codigo = tbu.tbu_codigo or
buq.pai_codigo = pai.pai_codigo or
buq.pto_codigo = pue.pto_codigo or
buq.lin_codigo = lin.lin_codigo or
buq.tra_codigo = tra.tra_codigo
I also tried with inner joins but the problem is it returns me the data that meets the conditions of the joins. In other words, if the join has data to compare, returns the name, if not, show the null data.
The query must return me 611 records, with inner joins returns 68 records.
Concerning your desired result, use left outer joins, which fill up any non-existing rows of the right hand side table with null-values;
Concerning the out of memory issue, note that you used or to connect your tables; this actually leads to the fact that almost every record of the involved tables is connected to almost every other record (almost a cross join / cartesian product); This can get very large if you connect 6 tables...
select buq.buq_codigo, tbu.tbu_codigo, tbu.tbu_nombre, pai.pai_codigo, pai.pai_nombre,
pue.pto_codigo, pue.pto_nombre, lin.lin_codigo, lin.lin_nombre, tra.tra_codigo,
tra.tra_nombre, buq.buq_nombre, buq.buq_des, buq.num_trb, buq.num_eslora,
buq.max_tons, buq.reg_lloyd, buq.buq_codigo1, buq.codigo_omi,
case buq.buq_estado when 'A' then 'Activo' else 'Inactivo' end as buq_estado
from publico.mae_buque as buq
left outer join publico.mae_tipbuque as tbu on buq.tbu_codigo = tbu.tbu_codigo
left outer join publico.mae_pais as pai on (buq.pai_codigo = pai.pai_codigo)
left outer join publico.mae_puerto as pue on (buq.pto_codigo = pue.pto_codigo)
left outer join publico.mae_linea as lin on (buq.lin_codigo = lin.lin_codigo)
left outer join publico.mae_trafico as tra on (buq.tra_codigo = tra.tra_codigo)
You have to use left outer join:
select *
from
publico.mae_buque as buq
left outer join publico.mae_tipbuque as tbu on (buq.tbu_codigo = tbu.tbu_codigo)
left outer join publico.mae_pais as pai on (buq.pai_codigo = pai.pai_codigo)
left outer join publico.mae_puerto as pue on (buq.pto_codigo = pue.pto_codigo )
left outer join publico.mae_linea as lin on (buq.lin_codigo = lin.lin_codigo)
left outer join publico.mae_trafico as tra on (buq.tra_codigo = tra.tra_codigo);

complex inner join sql

You are my last hope. I've spend all day but I haven't decided how to create this query.
This is my current database diagram
Every storage have 1 roster
Every roster consist from chief and worker. Information about them is on stuff table .
What I try to do? Get all storage(square adress), worker_name, worker_surname, chief_name, chief_surname.
What I have so far
select storage_address,
storage_square,
stuffs.stuff_name as chiefSurname,
stuffs.stuff_surname as chiefName from storages
inner join storageRoster on storageRoster.storageRoster_id=storages.storage_roster_id
inner join Chiefs on storageRoster.chief_id = Chiefs.chief_id
inner join stuffs on Chiefs.chief_stuff_id = stuffs.stuff_id
But in this query I can only get chiefs on every storage. Help please. I am desperate.
You need to join the stuff table twice, once for worker and once for chief:
select storage_address,
storage_square,
cs.stuff_name as chiefSurname,
cs.stuff_surname as chiefName,
ws.stuff_name as workerSurname,
ws.stuff_surname as workerName
from storages
inner join storageRoster on storageRoster.storageRoster_id=storages.storage_roster_id
inner join Chiefs on storageRoster.chief_id = Chiefs.chief_id
inner join stuffs cs on Chiefs.chief_stuff_id = cs.stuff_id
inner join Workers on storageRoster.worker_id = Workers.chief_id
inner join ws cs on Workers.worker_stuff_id = ws.stuff_id

How to improve the performance of a SQL query even after adding indexes?

I am trying to execute the following sql query but it takes 22 seconds to execute. the number of returned items is 554192. I need to make this faster and have already put indexes in all the tables involved.
SELECT mc.name AS MediaName,
lcc.name AS Country,
i.overridedate AS Date,
oi.rating,
bl1.firstname + ' ' + bl1.surname AS Byline,
b.id BatchNo,
i.numinbatch ItemNumberInBatch,
bah.changedatutc AS BatchDate,
pri.code AS IssueNo,
pri.name AS Issue,
lm.neptunemessageid AS MessageNo,
lmt.name AS MessageType,
bl2.firstname + ' ' + bl2.surname AS SourceFullName,
lst.name AS SourceTypeDesc
FROM profiles P
INNER JOIN profileresults PR
ON P.id = PR.profileid
INNER JOIN items i
ON PR.itemid = I.id
INNER JOIN batches b
ON b.id = i.batchid
INNER JOIN itemorganisations oi
ON i.id = oi.itemid
INNER JOIN lookup_mediachannels mc
ON i.mediachannelid = mc.id
LEFT OUTER JOIN lookup_cities lc
ON lc.id = mc.cityid
LEFT OUTER JOIN lookup_countries lcc
ON lcc.id = mc.countryid
LEFT OUTER JOIN itembylines ib
ON ib.itemid = i.id
LEFT OUTER JOIN bylines bl1
ON bl1.id = ib.bylineid
LEFT OUTER JOIN batchactionhistory bah
ON b.id = bah.batchid
INNER JOIN itemorganisationissues ioi
ON ioi.itemorganisationid = oi.id
INNER JOIN projectissues pri
ON pri.id = ioi.issueid
LEFT OUTER JOIN itemorganisationmessages iom
ON iom.itemorganisationid = oi.id
LEFT OUTER JOIN lookup_messages lm
ON iom.messageid = lm.id
LEFT OUTER JOIN lookup_messagetypes lmt
ON lmt.id = lm.messagetypeid
LEFT OUTER JOIN itemorganisationsources ios
ON ios.itemorganisationid = oi.id
LEFT OUTER JOIN bylines bl2
ON bl2.id = ios.bylineid
LEFT OUTER JOIN lookup_sourcetypes lst
ON lst.id = ios.sourcetypeid
WHERE p.id = #profileID
AND b.statusid IN ( 6, 7 )
AND bah.batchactionid = 6
AND i.statusid = 2
AND i.isrelevant = 1
when looking at the execution plan I can see an step which is costing 42%. Is there any way I could get this to a lower threshold or any way that I can improve the performance of the whole query.
Remove the profiles table as it is not needed and change the WHERE clause to
WHERE PR.profileid = #profileID
You have a left outer join on the batchactionhistory table but also have a condition in your WHERE clause which turns it back into an inner join. Change you code to this:
LEFT OUTER JOIN batchactionhistory bah
ON b.id = bah.batchid
AND bah.batchactionid = 6
You don't need the batches table as it is used to join other tables which could be joined directly and to show the id in you SELECT which is also available in other tables. Make the following changes:
i.batchidid AS BatchNo,
LEFT OUTER JOIN batchactionhistory bah
ON i.batchidid = bah.batchid
Are any of the fields that are used in joins or the WHERE clause from tables that contain large amounts of data but are not indexed. If so try adding an index on at time to the largest table.
Do you need every field in the result - if you could loose one or to you maybe could reduce the number of tables further.
First, if this is not a stored procedure, make it one. That's a lot of text for sql server to complile.
Next, my experience is that "worst practices" are occasionally a good idea. Specifically, I have been able to improve performance by splitting large queries into a couple or three small ones and assembling the results.
If this query is associated with a .net, coldfusion, java, etc application, you might be able to do the split/re-assemble in your application code. If not, a temporary table might come in handy.