I have this SP with more than 10tables involved. In the underlined lines, there is a table AllData which is being joined 3times because of the fieldname in the where clause.
Any suggestions on how to handle this complex query better will be greatly appreciated. Mostly, to avoid the multiple times I am joining AllData(with alias names ad1, adl2, adl3). This could affect the performance.
Here is the sp
ALTER PROCEDURE [dbo].[StoredProc1]
AS
select case when pd.Show_Photo = '1,1,1'
then i.id
else null
end as thumbimage,
t1.FPId,
'WebProfile' as profiletype,
mmbp.Name as Name,
t1.Age,
t1.Height,
adl.ListValue as AlldataValue1,
adl2.ListValue as AlldataValue2,
adl3.ListValue as AlldataValue3,
c.CName,
ed.ELevel,
ed.EDeg,
NEWID()
from Table2 mmbp, Table3 u
join Table1 t1 on t1.Pid = u.Pid
left join Table4 mmb on t1.Pid= mmb.Pid
join table5 i on t1.Pid = i.Pid
join table6 pd on t1.Pid = pd.Pid
join table7 ed on t1.Pid = ed.Pid
join table8 c on t1.xxx= c.xxx
join AllData adl on t1.xxx = adl.ListKey
join AllData adl2 on b.ms = adl2.ListKey
join AllData adl3 on b.Diet = adl3.ListKey
where adl.FieldName=xxx and
adl2.FieldName='ms' and
adl3.FieldName='Diet' and
------
I note that you appear to have a cartesian join between Table2 and Table3 - unless one of these tables is very small, this is likely to drastically affect performance. I suggest explicitly joining Table2 to one of the other tables in the query, to improve performance.
One thing you could try is moving the where conditions into the joins
join AllData ad1 on t1.xxx = ad1.ListKey AND ad1.FieldName = xxx
join AllData ad2 on b.ms = adl2.ListKey AND ad2.FieldName = 'ms'
join AllData ad3 on b.Diet = adl3.ListKey AND ad3.FieldName = 'Diet'
This would give better performance as the join size would be limited to only the records you want. To do this all in one join you could join AllData ad on (t1.xxx = ad.ListKey AND ad.FieldName = xxx) OR (b.ms = ad.ListKey AND ad.FieldName = 'ms').... The issue with this option is you no longer have distinct columns for ad1, ad2, etc.
Related
I have the following issue:
I have several tables in my Database, in order to check for a specific criteria I have to join several tables, where I use the following statement:
SELECT *
FROM (SELECT * FROM (((((((((SELECT * FROM table1 WHERE tab1_id = 1) AS A
INNER JOIN (SELECT * FROM table2 WHERE tab2_variable IS NOT NULL) AS B
ON A.variable = B.variable)
INNER JOIN (SELECT table3.*, IIF(year='XXXX', 0, 1) AS flag FROM table3) AS C
ON A.h_name = C.h_name)
INNER JOIN (SELECT * FROM table4 WHERE s_flag = 0) AS D
ON C.v_type = D.v_type)
INNER JOIN table5
ON C.ng_type = table5.ng_type)
INNER JOIN table6
ON C.part = table6.part)
INNER JOIN table7
ON C.ifg = table7.ifg)
INNER JOIN table8
ON C.v_type = table8.v_type AND C.ng_typ = table8.ng_typ AND C.ntr_flag = table8.ntr_flag)
INNER JOIN table9
ON table8.ifg_sii_id = table9.ifg_sii_id)) AS F
LEFT JOIN table10
ON F.risk = table10.risk AND C.v_type = table10.v_type
AND F.series = table10.series
This statement fails. But when I remove one the following two join-conditions in the last Left JOIN, it works as intended:
F.risk = table10.risk and/or C.v_type = table10.v_type
They are both of type CHAR, whereas series is type TINYINT, I guess it has something to do with joining on multiple conditions with strings, but I'm not able to find a workaround, any ideas?
according to your current SQL, Table C is not visible as it's a sub query within F. instead of C.v_type you need to use F.c_v_type and the c_v_type field must come from C table like. select v_type as c_v_type from table3... as C
In the last part of your Query You could try to actually select the table and include the Where Clause Like so:
LEFT JOIN (Select * from table10 Where C.v_type = v_type AND F.series = series) as xx
ON F.risk = xx.risk
Hope this helps
I'm having a performance problem with a SQL query that is generated by a .NET application.
Basically what the query is doing is:
(query1) left join (query2) right join (queries3 to 30) WHERE (query1.ID IS NULL) OR (query3.ID IS NULL AND query4.ID IS NULL AND… queryN.ID IS NULL)
When the query only does WHERE A (query1.ID) the query is fast.
When the query only does WHERE B (query3 to 30) the query is fast
When A and B are a combined WHERE clause with an OR, the query is
very slow.
I'm looking for a way to optimize this query without variables or stored procedures.
The query:
SELECT DISTINCT [Table0].[FIELD]
FROM /*8*/ ([Table0] AS [Table0]
INNER JOIN
[XTABLE] AS [XTABLE0]
ON [Table0].ID = [XTABLE0].ID1
AND [XTABLE0].ID3 = 52)
RIGHT OUTER /*10*/ JOIN
[Table1] AS [Table1]
/*21*/ /*11*/ ON [XTABLE0].ID2 = [Table1].ID
AND [XTABLE0].ID3 = 52
LEFT OUTER JOIN
([XTABLE] AS [XTABLE1]
INNER JOIN
[Table2] AS [Table2]
ON [XTABLE1].ID1 = [Table2].ID
AND [XTABLE1].ID3 = 19
/*20a*/ INNER JOIN
[XTABLE] AS [XTABLE2]
ON [Table2].ID = [XTABLE2].ID1
AND [XTABLE2].ID3 = 8
INNER JOIN
[Table3] AS [Table3]
ON [XTABLE2].ID2 = [Table3].ID
AND [XTABLE2].ID3 = 8/*22*/ )
ON [Table1].ID = [XTABLE1].ID2
AND [XTABLE1].ID3 = 19
/*26 */ LEFT OUTER JOIN
([XTABLE] AS [XTABLE3]
... and tens of similar INNER JOIN blocks
WHERE (/*13*/ [XTABLE0].ID IS NULL)
OR (/*25*/ [XTABLE1].ID IS NULL
AND /*27b*/ [XTABLE3].ID IS NULL
AND /*27b*/ [XTABLE5].ID IS NULL
... and tens of similar lines
AND /*27b*/ [XTABLE131].ID IS NULL);
You are OUTER JOIN'ing the queries, so, when you start putting stuff in the WHERE clause from the result of the OUTER JOIN table expressions (derived table in this case) then it will more than likely be treat as an INNER JOIN - you can see that by checking the query plan.
I have problem with LEFT JOIN query which is working in SQL, but when I try to query MDB database it doesn´t work.
Here it is:
Select PH.[ID], PH.[SText], PH.[Datum] ,PHpol.[SText], PHpol.[Mnozstvi], PHpol.[kcJedn], PHpol.[RelSzDPH], PHpol.[SDph], skst.[ID]
from PH LEFT JOIN PHpol ON PH.[ID] = PHpol.[RefAg]
LEFT JOIN Skz ON PHpol.[RefSKz] = Skz.[ID]
LEFT JOIN Skst ON Skz.[RefStruct] = Skst.[ID]
WHERE RelforUh = 2
AND RelCr=43
AND Datum BETWEEN #2015-01-01# AND #2015-09-01#
In MS Access, you need parentheses for multiple joins:
Select PH.[ID], PH.[SText], PH.[Datum] ,PHpol.[SText], PHpol.[Mnozstvi], PHpol.[kcJedn], PHpol.[RelSzDPH], PHpol.[SDph], skst.[ID]
from ((PH LEFT JOIN
PHpol
ON PH.[ID] = PHpol.[RefAg]
) LEFT JOIN
Skz
ON PHpol.[RefSKz] = Skz.[ID]
) LEFT JOIN
Skst
ON Skz.[RefStruct] = Skst.[ID]
WHERE RelforUh = 2 AND RelCr=43 AND
Datum BETWEEN #2015-01-01# AND #2015-09-01#
In MS-Access you need to add parentheses if you have to query on more than two tables. Structure goes like this..
Syntax for when you have two tables
Select <column list>
From Table1 Join Table2
on Table1.Col = Table2.col
where <your conditions>
Syntax for more than two tables.
Select <column list>
From (Table1 Join Table2
on Table1.Col = Table2.col)
Join Table3 on Table2.col = Table3.col
where <your conditions>
() make sure that whatever is written inside it, act as a table. If you have more tables then you can join them in the same fashion. You can read more about joining multiple tables in MS-Access here.
Well you can re-write your query as follows.
Select PH.[ID], PH.[SText], PH.[Datum] ,PHpol.[SText], PHpol.[Mnozstvi], PHpol.[kcJedn], PHpol.[RelSzDPH], PHpol.[SDph], skst.[ID]
from ((PH LEFT JOIN PHpol ON PH.[ID] = PHpol.[RefAg])
LEFT JOIN Skz ON PHpol.[RefSKz] = Skz.[ID])
LEFT JOIN Skst ON Skz.[RefStruct] = Skst.[ID]
WHERE RelforUh = 2
AND RelCr=43
AND Datum BETWEEN #2015-01-01# AND #2015-09-01#
I keep receiving a syntax error on this particular statement.
SELECT tbl1.ProjectID, tbl1.EntryDate AS StartDate, tbl2.EntryDate AS EndDate,
(tbl3.ChecklistDayMax - tbl3.ChecklistDayMin + 1) AS DaysAllotted,
(SELECT ProjectPriority FROM project_master WHERE ProjectID = tbl1.ProjectID) AS Priority,
tbl3.MilestoneName,
IIF(Priority = 1, tbl3.BonusDaysFH,
IIF(Priority = 2, tbl3.BonusDaysFM,
IIF(Priority = 3, tbl3.BonusDaysFL))) AS BonusDaysAllotted
FROM (((checklist_entries AS tbl1
INNER JOIN checklist_entries AS tbl2 ON tbl1.ProjectID = tbl2.ProjectID)
INNER JOIN milestone_def AS tbl3 ON [#milestoneID] = milestone_def.MilestoneDefID)
INNER JOIN project_active_status AS tbl4 ON tbl1.ProjectID = project_active_status.ProjectID)
WHERE tbl1.ChecklistDay = tbl3.ChecklistDayMin
AND tbl2.ChecklistDay = tbl3.ChecklistDayMax
AND tbl4.ProjectIsOpen = FALSE;
The error says Syntax Error In Join Operation and then it highlights milestone_def right after the 2nd INNER JOIN. Funny thing is, if I switch this line...
INNER JOIN milestone_def AS tbl3 ON [#milestoneID] = milestone_def.MilestoneDefID)
with this line...
INNER JOIN milestone_def AS tbl3 ON [#milestoneID] = tbl3.MilestoneDefID)
I get the error Join Expression Not Supported and then it highlights...
[#milestoneID] = tbl3.MilestoneDefID)
But as you can see, in the first join...
INNER JOIN checklist_entries AS tbl2 ON tbl1.ProjectID = tbl2.ProjectID
I name it tbl2 and then use tbl2.ProjectID and the expression works just fine. Ultimately, I need to get this to work, regardless how how I name these things.
[#milestoneID] is a parameter passed into the query to match milestone_def.MilestoneDefID
[Expanded from comments.] This is just a hunch, as I don't have access to Access (ha ha), but your query currently specifies an INNER JOIN that doesn't actually relate the table to the rest of the query:
...
INNER JOIN milestone_def AS tbl3
ON [#milestoneID] = milestone_def.MilestoneDefID
...
The ON clause references only an external variable, so isn't relevant to the JOIN operation, making this effectively a CROSS JOIN with a separate WHERE condition:
...
CROSS JOIN milestone_def AS tbl3
...
WHERE [#milestoneID] = milestone_def.MilestoneDefID
...
Looking at the bottom of your query, you have the actual join conditions for this table in the WHERE clause; these should be swapped into the ON clause, so that it actually specifies the INNER JOIN condition:
...
INNER JOIN milestone_def AS tbl3
ON tbl1.ChecklistDay = tbl3.ChecklistDayMin
AND tbl2.ChecklistDay = tbl3.ChecklistDayMax
...
WHERE [#milestoneID] = milestone_def.MilestoneDefID
...
It's certainly more logical that way, and it will possibly solve the problem Access's parser is having understanding your query.
Since the problem is with the joins, you would be wise to investigate the issue with a simpler query.
SELECT *
FROM
((checklist_entries AS tbl1
INNER JOIN checklist_entries AS tbl2
ON tbl1.ProjectID = tbl2.ProjectID)
INNER JOIN milestone_def AS tbl3
ON [#milestoneID] = milestone_def.MilestoneDefID)
INNER JOIN project_active_status AS tbl4
ON tbl1.ProjectID = project_active_status.ProjectID
Notice you have aliased the table names. Therefore you must use those aliases instead of the table names in the ON clauses.
SELECT *
FROM
((checklist_entries AS tbl1
INNER JOIN checklist_entries AS tbl2
ON tbl1.ProjectID = tbl2.ProjectID)
INNER JOIN milestone_def AS tbl3
ON tbl1.[#milestoneID] = tbl3.MilestoneDefID)
INNER JOIN project_active_status AS tbl4
ON tbl1.ProjectID = tbl4.ProjectID
I don't know what [#milestoneID] is or where it comes from. My best guess is it's a field in checklist_entries, so I qualified it with the tbl1 alias.
I think HansUp's answer is pointing you in the right direction. One other thing that I noticed is that you have a series of three nested IIFs and the final one only has a test and a true but is missing the false parameter. I thought that all three were compulsory.
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.