Author |
Topic |
sdngr
Starting Member
5 Posts |
Posted - 2005-09-01 : 09:35:59
|
Greetings... I am currently building a report via stored procedures in Reporting Services. The report goes through a lot of records, and so is going to be a bit slow. Thus far, I have been able to reduce it from almost 10 mins to about 2.5 mins, which is pretty good. However, I would like to further reduce it, and was wondering if any of you might be able to shed light on areas to fine tune that could enable the report to run faster?Thanks... |
|
Kristen
Test
22859 Posts |
Posted - 2005-09-01 : 10:00:15
|
Hi sdngr, Welcome to SQL Team!You'll need to post the DDL for the tables, a few sample rows (e.g. as INSERT statements) and the source of your SProc.If you provide folk here with a script they can just run to create a test scenario they'll be very likely to play with it and make suggestions.Kristen |
 |
|
sdngr
Starting Member
5 Posts |
Posted - 2005-09-01 : 10:17:58
|
Oooo... that is going to be tricky.... there are quite a few tables involved, and their relationships are very tricky. The stored procedure itself is relatively big and complex as well.... I'll see what I can get... |
 |
|
sdngr
Starting Member
5 Posts |
Posted - 2005-09-01 : 10:31:55
|
OK.... here is the SProc source..._______________________________________________________________SET QUOTED_IDENTIFIER OFF GOSET ANSI_NULLS ON GOALTER PROCEDURE dbo.prc_rpt_exec_LienWaiver( @UserLogin as varchar(60) -- Uses IIS-supplied domain\username to determine data access priviledges., @OUnitCode_UserLogin as varchar(8), @GroupNo as varchar(10) = 'ALL' -- AuditGroup No, @UnitNo as varchar(10) = 'ALL' -- AuditUnitNo, @Supplier as varchar(20) = 'ALL' -- Address code, @CheckNo as varchar(10) = 'ALL' -- AuditUnitNo, @DateStart as varchar(10) = '1/1/1900')ASBEGIN SET @GroupNo = REPLICATE('0',8 - LEN(LTRIM(RTRIM(@GroupNo)))) + LTRIM(RTRIM(@GroupNo)) SET @UnitNo = REPLICATE('0',4 - LEN(LTRIM(RTRIM(@UnitNo)))) + LTRIM(RTRIM(@UnitNo)) DECLARE @TempLW TABLE ( LWID int IDENTITY(1,1) NOT NULL, [GroupNo] [varchar] (16) NULL , [UnitNo] [varchar] (8) NULL , [DocNumber] [varchar] (16) NULL , [IssueDate] [smalldatetime] NULL , [CheckAmount] [decimal] (17,2) NULL, [Supplier] [int] NULL , [OperUnit] [varchar] (10) NULL , [Project] [varchar] (16) NULL , [ProjectName] [varchar] (60) NULL , [Category] [varchar] (30) NULL , [CategoryDesc] [varchar] (60) NULL , [MajorCode] [varchar] (30) NULL , [MajorDesc] [varchar] (60) NULL , [Phase] [varchar] (10) NULL , [PONo] [varchar] (12) NULL , [POStatus] [varchar] (50) NOT NULL, [InvDate] [smalldatetime] NULL , [InvNo] [varchar] (30) NULL , [InvLine] [varchar] (8) NOT NULL, [Amount] [decimal](17, 2) NULL , [Adjustments] [decimal](17, 2) NULL , [NetAmount] [decimal](18, 2) NULL , [RefAlloc] [varchar] (68) NULL , [POID] [int] NULL , [POLineNo] [varchar] (8) NULL , [CraftCode] [varchar] (16) NULL , [Craft6] [varchar] (6) NULL , [Craft7] [varchar] (1) NULL , [PayCode] [varchar] (30) NULL ) INSERT @TempLW ( GroupNo , UnitNo , DocNumber , IssueDate , CheckAmount , Supplier , OperUnit , Project , ProjectName , Category , CategoryDesc , MajorCode , MajorDesc , Phase , PONo , POStatus , InvDate , InvNo , InvLine , Amount , Adjustments , NetAmount , RefAlloc , POID , POLineNo , CraftCode , Craft6 , Craft7 , PayCode ) ( SELECT TOP 100 PERCENT DocHist.GroupNo , DocHist.UnitNo , DocHist.DocNumber , DocHist.IssueDate , DocHist.Amount CheckAmount , DocHist.AID Supplier , LEFT(IRIS.dbo.SplitPart(APItem.RefAlloc,',',1),10) OperUnit , IRIS.dbo.SplitPart(APItem.RefAlloc,',',2) Project , P.Name ProjectName , RAJTM.Category , RAJTMS.Descr CategoryDesc , RAJTM.MajorCode , RAJTM.Descr MajorDesc , IRIS.dbo.SplitPart(APItem.RefAlloc,',',3) Phase , PUHeader.PONo , PUHeader.WFCode POStatus , APHeader.InvDate , APHeader.InvNo , APDetail.[LineNo] InvLine , - APDetail.Amount Amount , APDetail.DiscAmt Adjustments , - APDetail.Amount - APDetail.DiscAmt NetAmount , APItem.RefAlloc , PUHeader.POID , PUDetailI.[LineNo] POLineNo , (case when PUItem.CraftCode = '' then null else PUItem.CraftCode end) CraftCode , LEFT((case when PUItem.CraftCode = '' then null else PUItem.CraftCode end),6) Craft6 , SUBSTRING((case when PUItem.CraftCode = '' then null else PUItem.CraftCode end),7,1) Craft7 , (case when PUItem.PayCode = '' then null else PUItem.PayCode end) PayCode FROM (SELECT 1 Dummy) Dual INNER JOIN DataMartFL.dbo.AuditGroup AuditGroup ON (@GroupNo = '00000ALL' OR AuditGroup.GroupNo = @GroupNo) INNER JOIN DataMartFL.dbo.APDetail APDetail ON (APDetail.GroupNo = AuditGroup.GroupNo) AND (@UnitNo = '0ALL' OR APDetail.UnitNo = @UnitNo) INNER JOIN DataMartFL.dbo.DocHist DocHist ON (DocHist.GroupNo = APDetail.GroupNo) AND (DocHist.UnitNo = APDetail.UnitNo) AND DocHist.Good = 1 AND ((@CheckNo = 'All') OR (DocHist.DocNumber = @CheckNo)) AND ((DocHist.IssueDate = CONVERT(datetime,@DateStart)) OR (@GroupNo<>'ALL') OR (@CheckNo<>'ALL') ) INNER JOIN DataMartFL.dbo.APHeader APHeader ON APDetail.CompCode = APHeader.CompCode AND APDetail.Voucher = APHeader.Voucher AND APHeader.Invoice = 1 AND APHeader.AID = DocHist.AID INNER JOIN DataMartFL.dbo.APItem APItem ON APDetail.CompCode = APItem.CompCode AND APDetail.Voucher = APItem.Voucher AND APDetail.[LineNo] = APItem.[LineNo] AND ISNULL(APItem.POID,'') > '' LEFT OUTER JOIN DataMartFL.dbo.JobTypeMajor RAJTM ON LEFT(APItem.RefAlloc,1) = 'H' AND RAJTM.MajorCode= IRIS.dbo.SplitPart(APItem.RefAlloc,',',4) AND RAJTM.JobType = dbo.udf_JobType_ProjLot (IRIS.dbo.SplitPart(APItem.RefAlloc,',',2) , IRIS.dbo.SplitPart(APItem.RefAlloc,',',3) ) LEFT OUTER JOIN DataMartFL.dbo.JobTypeMajor RAJTMS ON LEFT(APItem.RefAlloc,1) = 'H' AND RAJTMS.MajorCode=RAJTM.Category AND RAJTMS.JobType = RAJTM.JobType INNER JOIN DataMartFL.dbo.PUHeader PUHeader ON APItem.POID = PUHeader.POID LEFT OUTER JOIN DataMartFL.dbo.Project P ON P.ProjCode = IRIS.dbo.SplitPart(APItem.RefAlloc,',',2)-- AND dbo.udf_OperUnitPermMatch (@OUnitCode_UserLogin,P.OUnitCode,1)=1 INNER JOIN DataMartFL..PUDetail PUDetailI ON PUDetailI.TransType = 'I' AND PUDetailI.POID = PUHeader.POID AND PUDetailI.APLineNo = APDetail.[LineNo] AND IRIS.dbo.SplitPart(PUDetailI.GUT,',',0) = APItem.GroupNo AND IRIS.dbo.SplitPart(PUDetailI.GUT,',',1) = APItem.UnitNo INNER JOIN DataMartFL..PUItem PUItem ON PUItem.POID = PUDetailI.POID AND PUItem.[LineNo] = PUDetailI.[LineNo] ) ORDER BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 SELECT TempLW.* , sub2.MaxCraft7 , sub2.MaxPayCode , CONVERT(bit, (case when len(TempLW.CraftCode)=6 and isnull(TempLW.PayCode,99999) >= isnull(sub2.MaxPayCode,0) then 1 else 0 end) + (case when len(TempLW.CraftCode)=7 and TempLW.Craft7 = sub2.MaxCraft7 then 1 else 0 end) + (case when isnull(TempLW.CraftCode,'') = '' and TempLW.POStatus = 'Closed' then 1 else 0 end) ) FinalABC , JPA.StreetNo + ' ' + JPA.Street LotStreetAddr , convert(varchar(60),(case when ProjLegal.LegalName>'' then ProjLegal.LegalName else 'CORP NAME NOT FOUND' end)) ProjCorp , convert(varchar(50),(case when ProjLegal.ProvName>'' then ProjLegal.ProvName else 'STATE NAME NOT FOUND' end)) ProjStateName , convert(varchar(5),(case when ProjLegal.ProvCode>'' then ProjLegal.ProvCode else 'STATE CODE NOT FOUND' end)) ProjStateCode , convert(varchar(30),(case when ProjLegal.County>'' then ProjLegal.County else 'COUNTY NAME NOT FOUND' end)) ProjCounty , convert(varchar(50),(case when ProjLegal.CityName>'' then ProjLegal.CityName else 'CITY NAME NOT FOUND' end)) ProjSiteCity , convert(varchar(60),P.Name) ProjName , convert(varchar(60),PA.Street) ProjStreet , PA.Suite ProjSuite , convert(varchar(50),PC.CityName) ProjCity , PC.Provcode ProjState , PA.Postal ProjPostal , PayeeAddr.Code PayeeCode , convert(varchar(40),PayeeAddr.Name) PayeeName , convert(varchar(60),PayeeAddr.Street) PayeeStreet , convert(varchar(20),PayeeAddr.Suite) PayeeSuite , convert(varchar(50),PayeeC.CityName) PayeeCity , PayeeC.ProvCode PayeeState , PayeeAddr.Postal PayeePostal FROM @TempLW TempLW LEFT OUTER JOIN DataMartFL..Project P ON P.ProjCode = TempLW.Project LEFT OUTER JOIN DataMartFL..Address PA ON P.Aid = PA.Aid LEFT OUTER JOIN DataMartFL..City PC ON PC.Citycode = PA.CityCode LEFT OUTER JOIN DataMartFL..JobPhaseAddr JPA ON JPA.ProjID = P.ProjID AND JPA.Phase = TempLW.Phase LEFT OUTER JOIN DataMartFL.dbo.Address PayeeAddr ON PayeeAddr.AID = TempLW.Supplier LEFT OUTER JOIN DataMartFL..City PayeeC ON PayeeC.Citycode = PayeeAddr.CityCode LEFT OUTER JOIN (-- ProjLegal SELECT Project.ProjCode , Project.Name , Address.Name LegalName , Province.Name ProvName , Province.ProvCode , dbo.SplitPart(Project.userdef,';',0) County , MAX(CityName) CityName FROM DataMartFL..Project Project LEFT OUTER JOIN DataMartFL..APCat APCat ON Project.CompCode = APCat.CompCode LEFT OUTER JOIN DataMartFL..Company C ON Project.CompCode = C.CompCode LEFT OUTER JOIN DataMartFL..BankAcct BankAcct ON substring(APCat.BankCode,1,charindex(',',APCat.BankCode+',')-1) = BankAcct.BankCode LEFT OUTER JOIN DataMartFL..Address Address ON BankAcct.CAID = Address.AID LEFT OUTER JOIN DataMartFL..JobPhaseAddr JobPhaseAddr ON JobPhaseAddr.ProjID = Project.ProjID LEFT OUTER JOIN DataMartFL..City City ON JobPhaseAddr.CityCode = City.CityCode LEFT OUTER JOIN DataMartFL..Province Province ON Province.ProvCode = City.ProvCode GROUP BY Project.ProjCode , Project.Name , Address.Name , Province.Name , Province.ProvCode , dbo.SplitPart(Project.userdef,';',0) ) ProjLegal ON ProjLegal.ProjCode = P.ProjCode LEFT OUTER JOIN ( -- sub2 SELECT TOP 100 PERCENT IRIS.dbo.SplitPart(OUnitProjectPhase,',',0) OperUnit , IRIS.dbo.SplitPart(OUnitProjectPhase,',',1) Project , IRIS.dbo.SplitPart(OUnitProjectPhase,',',2) Phase , Supplier , Craft6 , MaxCraft7 , MaxPayCode FROM ( SELECT IRIS.dbo.SplitPart(Alloc,',',1) + ',' + IRIS.dbo.SplitPart(Alloc,',',2) + ',' + IRIS.dbo.SplitPart(Alloc,',',3) OUnitProjectPhase , PUHeader.AID Supplier , LEFT(PUItem.CraftCode,6) Craft6 , MAX(substring(PUItem.CraftCode,7,1)) MaxCraft7 , MAX(PUItem.PayCode) MaxPayCode FROM (SELECT 1 Dummy) Dual INNER JOIN @TempLW TempLW ON TempLW.CraftCode > '' INNER JOIN DataMartFL..PUHeader PUHeader ON PUHeader.AID = TempLW.Supplier INNER JOIN DataMartFL..PUItem PUItem ON PUItem.POID = PUHeader.POID AND LEFT(PUItem.CraftCode,6) = TempLW.Craft6 AND TempLW.OperUnit = substring(PUItem.Alloc, 1+charindex(',',PUItem.Alloc), 1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc))-(1+charindex(',',PUItem.Alloc))-1) AND TempLW.Project = substring(PUItem.Alloc, 1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc)), 1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc))) -(1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc))) -1 ) AND TempLW.Phase = substring(PUItem.Alloc, 1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc))), 1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc)))) - (1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc,1+charindex(',',PUItem.Alloc)))) -1 ) GROUP BY IRIS.dbo.SplitPart(Alloc,',',1) + ',' + IRIS.dbo.SplitPart(Alloc,',',2) + ',' + IRIS.dbo.SplitPart(Alloc,',',3) , PUHeader.AID , LEFT(PUItem.CraftCode,6) ) sub1 ORDER BY OperUnit , Project , Phase , Supplier , Craft6 ) sub2 ON sub2.OperUnit = TempLW.OperUnit AND sub2.Project = TempLW.Project AND sub2.Phase = TempLW.Phase AND sub2.Supplier = TempLW.Supplier AND sub2.Craft6 = TempLW.Craft6 WHERE (0=0) AND ((@Supplier = 'ALL') OR (PayeeAddr.Code = @Supplier)) GROUP BY LWID , TempLW.GroupNo , TempLW.UnitNo , TempLW.DocNumber , TempLW.IssueDate , TempLW.CheckAmount , TempLW.Supplier , TempLW.OperUnit , TempLW.Project , TempLW.ProjectName , TempLW.Category , TempLW.CategoryDesc , TempLW.MajorDesc , TempLW.MajorCode , TempLW.MajorDesc , TempLW.Phase , TempLW.PONo , TempLW.POStatus , TempLW.InvDate , TempLW.InvNo , TempLW.InvLine , TempLW.Amount , TempLW.Adjustments , TempLW.NetAmount , TempLW.POID , TempLW.RefAlloc , TempLW.POLineNo , TempLW.CraftCode , TempLW.Craft6 , TempLW.Craft7 , TempLW.PayCode , sub2.Craft6 , sub2.MaxCraft7 , sub2.MaxPayCode , JPA.Street , JPA.StreetNo , ProjLegal.LegalName , ProjLegal.ProvName , ProjLegal.ProvCode , ProjLegal.County , ProjLegal.CityName , P.Name , PA.Street , PA.Suite , PC.CityName , PC.Provcode , PA.Postal , PayeeAddr.Code , PayeeAddr.Name , PayeeAddr.Street , PayeeAddr.Suite , PayeeC.CityName , PayeeC.ProvCode , PayeeAddr.Postal ENDGOSET QUOTED_IDENTIFIER OFF GOSET ANSI_NULLS ON GO__________________________________________________________________Like I said, pretty complex. Not sure if I will be able to get the DDL.... chances are probably not.... but if you or your folks can spot something here... that would be awesome...Thanks !!! |
 |
|
Kristen
Test
22859 Posts |
Posted - 2005-09-01 : 11:02:29
|
This doesn't bode well at a glance IMHO!!LEFT OUTER JOIN( SELECT TOP 100 PERCENT ... FROM ( SELECT ... FROM ( SELECT 1 Dummy ) Dual I'll take a look a bit later onKristen |
 |
|
sdngr
Starting Member
5 Posts |
Posted - 2005-09-01 : 11:08:39
|
Yeh... no kidding.... this was written by a co-worker who likes to use loads of joins.... supposedly increases the performances versus individual selects. I have been assigned to look into decreasing the response time.In any case, I do appreciate your help. |
 |
|
Kristen
Test
22859 Posts |
Posted - 2005-09-01 : 13:33:15
|
I hope I'm wrong with 99% of my comments - this code looks dire to me - good job no-one here wrote it, or we'd be having a public execution! There are some serious normalisation issues on the source data, which is resulting in frantic splitting of single-columns into multiple-columns. Fix that in the underlying data and I reckon that will make a dramatic improvement.I formatted the source so I could see what was going on - hopefully it will help smarter-minds-than-mine to spot some other improvementsI presume that all columns used in the JOINS are Indexed?KristenALTER PROCEDURE dbo.prc_rpt_exec_LienWaiver( -- Uses IIS-supplied domain\username to determine data access priviledges. @UserLogin as varchar(60) , @OUnitCode_UserLogin as varchar(8) , @GroupNo as varchar(10) = 'ALL' -- AuditGroup No , @UnitNo as varchar(10) = 'ALL' -- AuditUnitNo , @Supplier as varchar(20) = 'ALL' -- Address code , @CheckNo as varchar(10) = 'ALL' -- AuditUnitNo , @DateStart as varchar(10) = '1/1/1900')ASBEGINSET @GroupNo = REPLICATE('0', 8 - LEN(LTRIM(RTRIM(@GroupNo)))) + LTRIM(RTRIM(@GroupNo))SET @UnitNo = REPLICATE('0', 4 - LEN(LTRIM(RTRIM(@UnitNo)))) + LTRIM(RTRIM(@UnitNo)) DECLARE @TempLW TABLE( LWID int IDENTITY(1,1) NOT NULL, [GroupNo] [varchar] (16) NULL , [UnitNo] [varchar] (8) NULL , [DocNumber] [varchar] (16) NULL , [IssueDate] [smalldatetime] NULL , [CheckAmount] [decimal] (17,2) NULL, [Supplier] [int] NULL , [OperUnit] [varchar] (10) NULL , [Project] [varchar] (16) NULL , [ProjectName] [varchar] (60) NULL , [Category] [varchar] (30) NULL , [CategoryDesc] [varchar] (60) NULL , [MajorCode] [varchar] (30) NULL , [MajorDesc] [varchar] (60) NULL , [Phase] [varchar] (10) NULL , [PONo] [varchar] (12) NULL , [POStatus] [varchar] (50) NOT NULL, [InvDate] [smalldatetime] NULL , [InvNo] [varchar] (30) NULL , [InvLine] [varchar] (8) NOT NULL, [Amount] [decimal](17, 2) NULL , [Adjustments] [decimal](17, 2) NULL , [NetAmount] [decimal](18, 2) NULL , [RefAlloc] [varchar] (68) NULL , [POID] [int] NULL , [POLineNo] [varchar] (8) NULL , [CraftCode] [varchar] (16) NULL , [Craft6] [varchar] (6) NULL , [Craft7] [varchar] (1) NULL , [PayCode] [varchar] (30) NULL )Primary Key definition essentialINSERT @TempLW( GroupNo , UnitNo , DocNumber , IssueDate , CheckAmount , Supplier , OperUnit , Project , ProjectName , Category , CategoryDesc , MajorCode , MajorDesc , Phase , PONo , POStatus , InvDate , InvNo , InvLine , Amount , Adjustments , NetAmount , RefAlloc , POID , POLineNo , CraftCode , Craft6 , Craft7 , PayCode)( I cannot see that this TOP 100 PERCENT is doing anything. The bracket is superfluous too SELECT TOP 100 PERCENT DocHist.GroupNo , DocHist.UnitNo , DocHist.DocNumber , DocHist.IssueDate , DocHist.Amount CheckAmount , DocHist.AID SupplierTry to replace all these SplitPart functions with some better quality "normalised" data , LEFT(IRIS.dbo.SplitPart(APItem.RefAlloc,',',1),10) OperUnit , IRIS.dbo.SplitPart(APItem.RefAlloc,',',2) Project , P.Name ProjectName , RAJTM.Category , RAJTMS.Descr CategoryDesc , RAJTM.MajorCode , RAJTM.Descr MajorDesc , IRIS.dbo.SplitPart(APItem.RefAlloc,',',3) Phase , PUHeader.PONo , PUHeader.WFCode POStatus , APHeader.InvDate , APHeader.InvNo , APDetail.[LineNo] InvLine , - APDetail.Amount Amount , APDetail.DiscAmt Adjustments , - APDetail.Amount - APDetail.DiscAmt NetAmount , APItem.RefAlloc , PUHeader.POID , PUDetailI.[LineNo] POLineNoThere are several occurences of things that convert blanks to nullReplace them all with NullIf{PUItem.CraftCode, '') , (case when PUItem.CraftCode = '' then null else PUItem.CraftCode end) CraftCode , LEFT((case when PUItem.CraftCode = '' then null else PUItem.CraftCode end) ,6) Craft6 , SUBSTRING((case when PUItem.CraftCode = '' then null else PUItem.CraftCode end), 7, 1) Craft7 , (case when PUItem.PayCode = '' then null else PUItem.PayCode end) PayCode FROM I cannot for the life of me figure out what the point of this dummy table is ( SELECT 1 Dummy ) DualThese cartesian joins, if the parmeter is "ALL", will potentially result in some big resultsets INNER JOIN DataMartFL.dbo.AuditGroup AuditGroup ON @GroupNo = '00000ALL' OR AuditGroup.GroupNo = @GroupNo INNER JOIN DataMartFL.dbo.APDetail APDetail ON APDetail.GroupNo = AuditGroup.GroupNo AND (@UnitNo = '0ALL' OR APDetail.UnitNo = @UnitNo) INNER JOIN DataMartFL.dbo.DocHist DocHist ON DocHist.GroupNo = APDetail.GroupNo AND DocHist.UnitNo = APDetail.UnitNo AND DocHist.Good = 1 AND (@CheckNo = 'All' OR DocHist.DocNumber = @CheckNo) AND (The @DateStart should be coverted [at the top of this SProc] to a separate @Variable which has a datetime datatype DocHist.IssueDate = CONVERT(datetime, @DateStart)I would put good money on these two ORs defeating the optimiser, if either of these ALL tests are true I would do something with @DateStart parameter [at top of SProc] to satify this clause OR @GroupNo<>'ALL' OR @CheckNo<>'ALL' ) INNER JOIN DataMartFL.dbo.APHeader APHeader ON APDetail.CompCode = APHeader.CompCode AND APDetail.Voucher = APHeader.Voucher AND APHeader.Invoice = 1 AND APHeader.AID = DocHist.AID INNER JOIN DataMartFL.dbo.APItem APItem ON APDetail.CompCode = APItem.CompCode AND APDetail.Voucher = APItem.Voucher AND APDetail.[LineNo] = APItem.[LineNo] Need to avoid manipulation of joined table columns as it will prevent index selectionAPItem.POID = NULL is going to fail this test anyway, isn't it? if so just useAND APItem.POID > '' AND ISNULL(APItem.POID, '') > '' LEFT OUTER JOIN DataMartFL.dbo.JobTypeMajor RAJTM This will defeat the optimisers index selection too I expectAPItem.RefAlloc LIKE 'H%'may be better ON LEFT(APItem.RefAlloc, 1) = 'H' AND RAJTM.MajorCode= IRIS.dbo.SplitPart(APItem.RefAlloc,',',4) AND RAJTM.JobType = dbo.udf_JobType_ProjLotThese are scary beyond belief! Create a data source that can provide the componenets of APItem.RefAlloc without run-time splitting ( IRIS.dbo.SplitPart(APItem.RefAlloc,',',2) , IRIS.dbo.SplitPart(APItem.RefAlloc,',',3) ) LEFT OUTER JOIN DataMartFL.dbo.JobTypeMajor RAJTMS Ditto ON LEFT(APItem.RefAlloc,1) = 'H' AND RAJTMS.MajorCode=RAJTM.Category AND RAJTMS.JobType = RAJTM.JobType INNER JOIN DataMartFL.dbo.PUHeader PUHeader ON APItem.POID = PUHeader.POID LEFT OUTER JOIN DataMartFL.dbo.Project PDitto ON P.ProjCode = IRIS.dbo.SplitPart(APItem.RefAlloc,',',2)-- AND dbo.udf_OperUnitPermMatch (@OUnitCode_UserLogin,P.OUnitCode,1)=1 INNER JOIN DataMartFL..PUDetail PUDetailI ON PUDetailI.TransType = 'I' AND PUDetailI.POID = PUHeader.POID AND PUDetailI.APLineNo = APDetail.[LineNo] Ditto AND IRIS.dbo.SplitPart(PUDetailI.GUT,',',0) = APItem.GroupNo AND IRIS.dbo.SplitPart(PUDetailI.GUT,',',1) = APItem.UnitNo INNER JOIN DataMartFL..PUItem PUItem ON PUItem.POID = PUDetailI.POID AND PUItem.[LineNo] = PUDetailI.[LineNo])Really bad idea to use column numbers. Are they ALL needed for a unique sort order?This is just inserted in a temporary table, is the order being relied on? (Another bad idea!)ORDER BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18I would put a SELECT COUNT(*) FROM @TempLW here to see how many rows are in thetemp table, compared to the number of results rows you get.SELECT Name all the columns, otherwise the query plan is unlikely to be cached TempLW.* , sub2.MaxCraft7 , sub2.MaxPayCode , CONVERT(bit,This BIT conversion is potentially going to add up three 1s - what is that supposed to convert to? ( case when len(TempLW.CraftCode)=6 I do not like the Coalesce to 9999 and 0 as a mean of "not matching" - is that going to work safely with real values of these two columns and isnull(TempLW.PayCode,99999) >= isnull(sub2.MaxPayCode,0) then 1 else 0 end ) + ( case when len(TempLW.CraftCode)=7 and TempLW.Craft7 = sub2.MaxCraft7 then 1 else 0 end ) + ( case when isnull(TempLW.CraftCode,'') = '' and TempLW.POStatus = 'Closed' then 1 else 0 end ) ) FinalABC , JPA.StreetNo + ' ' + JPA.Street LotStreetAddrWhat are these text strings "converted" to varchar?? , convert(varchar(60), (I would replace these with IsNull(NullIf(ProjLegal.LegalName, ''), 'CORP NAME NOT FOUND')Is it really possible for the column to contain EITHER an empty string OR a NULL? I would clean up the data so its one or the other case when ProjLegal.LegalName>'' then ProjLegal.LegalName else 'CORP NAME NOT FOUND' end) ) ProjCorpDitto , convert(varchar(50), (case when ProjLegal.ProvName>'' then ProjLegal.ProvName else 'STATE NAME NOT FOUND' end) ) ProjStateNameDitto , convert(varchar(5), (case when ProjLegal.ProvCode>'' then ProjLegal.ProvCode else 'STATE CODE NOT FOUND' end) ) ProjStateCodeDitto , convert(varchar(30), (case when ProjLegal.County>'' then ProjLegal.County else 'COUNTY NAME NOT FOUND' end) ) ProjCountyDitto , convert(varchar(50), (case when ProjLegal.CityName>'' then ProjLegal.CityName else 'CITY NAME NOT FOUND' end) ) ProjSiteCityCONVERT seems pointless - use LEFT() if you need to constrain length , convert(varchar(60), P.Name) ProjName , convert(varchar(60), PA.Street) ProjStreet , PA.Suite ProjSuite , convert(varchar(50), PC.CityName) ProjCity , PC.Provcode ProjState , PA.Postal ProjPostal , PayeeAddr.Code PayeeCode , convert(varchar(40), PayeeAddr.Name) PayeeName , convert(varchar(60), PayeeAddr.Street) PayeeStreet , convert(varchar(20), PayeeAddr.Suite) PayeeSuite , convert(varchar(50), PayeeC.CityName) PayeeCity , PayeeC.ProvCode PayeeState , PayeeAddr.Postal PayeePostalFROM @TempLW TempLWPersonally I would replace the ".." with ".dbo." LEFT OUTER JOIN DataMartFL..Project P ON P.ProjCode = TempLW.Project LEFT OUTER JOIN DataMartFL..Address PA ON P.Aid = PA.Aid LEFT OUTER JOIN DataMartFL..City PC ON PC.Citycode = PA.CityCode LEFT OUTER JOIN DataMartFL..JobPhaseAddr JPA ON JPA.ProjID = P.ProjID AND JPA.Phase = TempLW.Phase LEFT OUTER JOIN DataMartFL.dbo.Address PayeeAddr ON PayeeAddr.AID = TempLW.Supplier LEFT OUTER JOIN DataMartFL..City PayeeC ON PayeeC.Citycode = PayeeAddr.CityCode LEFT OUTER JOIN ( -- ProjLegal SELECT Project.ProjCode , Project.Name , Address.Name LegalName , Province.Name ProvName , Province.ProvCode , dbo.SplitPart(Project.userdef,';',0) CountySo, we are doing all this SUB SELECT work just to get the MAX CityName?What real world use is the MAX(CityName)? Sounds utterly confusing to me , MAX(CityName) CityName FROM DataMartFL..Project ProjectAll this complex JOINery is repeated here just to get a lookup list. I expect it would be much better to pre-prepare this and JOIN it direct LEFT OUTER JOIN DataMartFL..APCat APCat ON Project.CompCode = APCat.CompCode LEFT OUTER JOIN DataMartFL..Company C ON Project.CompCode = C.CompCode LEFT OUTER JOIN DataMartFL..BankAcct BankAcct LEFT may be faster here. More scary delimited data ON substring(APCat.BankCode,1, charindex(',',APCat.BankCode+',')-1) = BankAcct.BankCode LEFT OUTER JOIN DataMartFL..Address Address ON BankAcct.CAID = Address.AID LEFT OUTER JOIN DataMartFL..JobPhaseAddr JobPhaseAddr ON JobPhaseAddr.ProjID = Project.ProjID LEFT OUTER JOIN DataMartFL..City City ON JobPhaseAddr.CityCode = City.CityCode LEFT OUTER JOIN DataMartFL..Province Province ON Province.ProvCode = City.ProvCode GROUP BY Project.ProjCode , Project.Name , Address.Name , Province.Name , Province.ProvCode , dbo.SplitPart(Project.userdef,';',0) ) ProjLegal ON ProjLegal.ProjCode = P.ProjCode LEFT OUTER JOIN ( -- sub2Is there some reason for this TOP 100 PERCENT? It must be in order to ORDER this SUB SELECT, but I can not see what that achieves SELECT TOP 100 PERCENTMore scary splitting IRIS.dbo.SplitPart(OUnitProjectPhase,',',0) OperUnit , IRIS.dbo.SplitPart(OUnitProjectPhase,',',1) Project , IRIS.dbo.SplitPart(OUnitProjectPhase,',',2) Phase , Supplier , Craft6 , MaxCraft7 , MaxPayCode FROM ( SELECT The three parts of Alloc are split here, and then re-combined, to then be re-split in the outer SELECT; Why? IRIS.dbo.SplitPart(Alloc,',',1) + ',' + IRIS.dbo.SplitPart(Alloc,',',2) + ',' + IRIS.dbo.SplitPart(Alloc,',',3) OUnitProjectPhase , PUHeader.AID SupplierThis LEFT/SUBSTRING stuff is a bit scary too - does PUItem.CraftCode holds data for two separate things? , LEFT(PUItem.CraftCode,6) Craft6 , MAX(substring(PUItem.CraftCode,7,1)) MaxCraft7 , MAX(PUItem.PayCode) MaxPayCode FROM (Pointless? SELECT 1 Dummy ) Dual INNER JOIN @TempLW TempLW ON TempLW.CraftCode > '' INNER JOIN DataMartFL..PUHeader PUHeader ON PUHeader.AID = TempLW.Supplier INNER JOIN DataMartFL..PUItem PUItem ON PUItem.POID = PUHeader.POID AND LEFT(PUItem.CraftCode,6) = TempLW.Craft6Now this splitting is REALLY scary - unless the Optimiser is able to spot that the sameeffort is happening gazzilions of times, which I doubtClearly PUItem.Alloc should be held in a number fo actual columns, but failing that it shouldbe split in a SUB SELECT AND TempLW.OperUnit = substring(PUItem.Alloc, 1+charindex(',',PUItem.Alloc), 1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc) )-(1+charindex(',',PUItem.Alloc))-1 ) AND TempLW.Project = substring(PUItem.Alloc, 1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc) ), 1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc) ) ) - (1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc) ) ) -1 ) AND TempLW.Phase = substring(PUItem.Alloc, 1+charindex(',', PUItem.Alloc, 1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc) ) ), 1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc) ) ) ) - (1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc, 1+charindex(',',PUItem.Alloc) ) ) ) -1 ) GROUP BY IRIS.dbo.SplitPart(Alloc,',',1) + ',' + IRIS.dbo.SplitPart(Alloc,',',2) + ',' + IRIS.dbo.SplitPart(Alloc,',',3) , PUHeader.AID , LEFT(PUItem.CraftCode,6) ) sub1 ORDER BY OperUnit , Project , Phase , Supplier , Craft6 ) sub2 ON sub2.OperUnit = TempLW.OperUnit AND sub2.Project = TempLW.Project AND sub2.Phase = TempLW.Phase AND sub2.Supplier = TempLW.Supplier AND sub2.Craft6 = TempLW.Craft6I can't see the optimiser having trouble with "0=0", but I would n't chance it! WHERE (0=0) AND ( @Supplier = 'ALL' OR PayeeAddr.Code = @Supplier )Why the GROUP BY? I did not see any aggregate functions in the SELECT.So is this just a DISTINCT?Is so I would be VERY scared that this is just to get rid of all the cartesian JOINs.Try running with a COUNT(*) instead of the select and see how many rows were aggregatedIf its gazzilions then thats probably the primary source of the performance issues - erroneously JOINing data multiple times.GROUP BY LWID , TempLW.GroupNo , TempLW.UnitNo , TempLW.DocNumber , TempLW.IssueDate , TempLW.CheckAmount , TempLW.Supplier , TempLW.OperUnit , TempLW.Project , TempLW.ProjectName , TempLW.Category , TempLW.CategoryDesc , TempLW.MajorDesc , TempLW.MajorCode , TempLW.MajorDesc , TempLW.Phase , TempLW.PONo , TempLW.POStatus , TempLW.InvDate , TempLW.InvNo , TempLW.InvLine , TempLW.Amount , TempLW.Adjustments , TempLW.NetAmount , TempLW.POID , TempLW.RefAlloc , TempLW.POLineNo , TempLW.CraftCode , TempLW.Craft6 , TempLW.Craft7 , TempLW.PayCode , sub2.Craft6 , sub2.MaxCraft7 , sub2.MaxPayCode , JPA.Street , JPA.StreetNo , ProjLegal.LegalName , ProjLegal.ProvName , ProjLegal.ProvCode , ProjLegal.County , ProjLegal.CityName , P.Name , PA.Street , PA.Suite , PC.CityName , PC.Provcode , PA.Postal , PayeeAddr.Code , PayeeAddr.Name , PayeeAddr.Street , PayeeAddr.Suite , PayeeC.CityName , PayeeC.ProvCode , PayeeAddr.Postal END |
 |
|
sdngr
Starting Member
5 Posts |
Posted - 2005-09-01 : 15:02:08
|
Kristen,Thanks soooo much for the feedback and the time spent. You bring up a lot of good points.... I don't know most of the answers to the questions you asked as I did not write the SProc, but I can certainly see where you are headed. Gives me something to work on.Again... muchos gracias.Rene |
 |
|
|
|
|