BAQ Works in Designer - Not in Dashboard

Good morning,
I have a really ugly BAQ that pulls data from the Resource Time Used table, rolls it up by resource group, job, assembly, and operation, then spits out the total load, and earned hours by resource group. The BAQ works well, a bit slow but it seems to have mostly the correct data. It only takes 400-600ms to run in BAQ designer and it returns about 500 rows. When I run the same BAQ in my dashboard (not customized), epicor freezes up for 30 seconds or so, then returns “Ready” with 0 results. There are no filters at the dashboard level, everything is done in the BAQ.

This was workign in the dashboard until I did two things. First, I filtered the top level query to show TotalLoad > 0. Next, I added the EH per Load calculation that literally just divides the two.

In the BAQ this is still working perfectly, but now the dashboard just returns 0 after a bit of freezing.

I cleared client cache - no change.
I restarted epicor - no change.
I rearranged the criteria in the BAQ a few different ways and always just made it worse.

Here is the BAQ, you may have to alter the resource group filter on one of the subqueries to match your resource groups.
RTU_LoadTotalsWithEstEH1.baq (95.1 KB)

There is nothing special about the dashboard. When I add the query to it, I add group by and summary. I group by ResourceGrpID, then WhatIf. This shows me a difference of load between regular and what-if schedules by resource group. In the dashboard, I also apply a sum to Earned Hours, TotalLoad, and EHPerLoad.

If you’re willing to take a look at the BAQ, please let me know if you see anything that might cause this kind of issue. If you can’t load the BAQ, here is the SQL:

/*
 * Disclaimer!!!
 * This is not a real query being executed, but a simplified version for general vision.
 * Executing it with any other tool may produce a different result.
 */
 
select 
	[SubQuery4].[ResourceTimeUsed_WhatIf] as [ResourceTimeUsed_WhatIf],
	[SubQuery4].[Resource_ResourceGrpID] as [Resource_ResourceGrpID],
	[SubQuery4].[Calculated_LoadMonth] as [Calculated_LoadMonth],
	[SubQuery4].[JobHead_JobNum] as [JobHead_JobNum],
	[SubQuery4].[JobHead_PartNum] as [JobHead_PartNum],
	[SubQuery4].[JobHead_ProdQty] as [JobHead_ProdQty],
	[SubQuery4].[JobAsmbl_PartNum] as [JobAsmbl_PartNum],
	[SubQuery4].[JobOper_OprSeq] as [JobOper_OprSeq],
	[SubQuery4].[JobOper_RunQty] as [JobOper_RunQty],
	[SubQuery4].[JobOper_ProdStandard] as [JobOper_ProdStandard],
	[SubQuery4].[Calculated_EarnedHours] as [Calculated_EarnedHours],
	(sum(cast(SubQuery4.Calculated_LoadHours as decimal (5,2)))) as [Calculated_TotalLoad],
	(SubQuery4.Calculated_EarnedHours/ TotalLoad) as [Calculated_EHPerLoad]
from  (select 
	[SubQuery1].[ResourceTimeUsed_WhatIf] as [ResourceTimeUsed_WhatIf],
	[SubQuery1].[Resource_ResourceGrpID] as [Resource_ResourceGrpID],
	(datepart(month, SubQuery1.ResourceTimeUsed_LoadDate)) as [Calculated_LoadMonth],
	[SubQuery1].[JobHead_JobNum] as [JobHead_JobNum],
	[SubQuery1].[JobHead_PartNum] as [JobHead_PartNum],
	[SubQuery1].[JobHead_ProdQty] as [JobHead_ProdQty],
	[SubQuery1].[JobAsmbl_PartNum] as [JobAsmbl_PartNum],
	[SubQuery1].[JobOper_OprSeq] as [JobOper_OprSeq],
	[SubQuery1].[JobOper_RunQty] as [JobOper_RunQty],
	[SubQuery1].[JobOper_ProdStandard] as [JobOper_ProdStandard],
	((SubQuery1.JobOper_RunQty * SubQuery1.JobOper_ProdStandard)/60) as [Calculated_EarnedHours],
	(SubQuery1.Calculated_DayLoadHours) as [Calculated_LoadHours]
from  (select distinct
	[Resource].[ResourceGrpID] as [Resource_ResourceGrpID],
	[ResourceGroup].[Description] as [ResourceGroup_Description],
	[JobHead].[PartNum] as [JobHead_PartNum],
	[JobAsmbl].[PartNum] as [JobAsmbl_PartNum],
	([Ice].entry(RowCount.Calculated_RowNum, RTU.ResourceTimeUsed_LoadHours,'~')) as [Calculated_DayLoadHours],
	[RowCount].[Calculated_RowNum] as [Calculated_RowNum],
	[JobHead].[JobNum] as [JobHead_JobNum],
	[RTU].[ResourceTimeUsed_LoadDate] as [ResourceTimeUsed_LoadDate],
	[RTU].[ResourceTimeUsed_WhatIf] as [ResourceTimeUsed_WhatIf],
	[JobOper].[RunQty] as [JobOper_RunQty],
	[JobOper].[ProdStandard] as [JobOper_ProdStandard],
	[JobHead].[ProdQty] as [JobHead_ProdQty],
	[JobOper].[OprSeq] as [JobOper_OprSeq]
from  (select 
	[ResourceTimeUsed].[Company] as [ResourceTimeUsed_Company],
	[ResourceTimeUsed].[JobNum] as [ResourceTimeUsed_JobNum],
	[ResourceTimeUsed].[AssemblySeq] as [ResourceTimeUsed_AssemblySeq],
	[ResourceTimeUsed].[OprSeq] as [ResourceTimeUsed_OprSeq],
	[ResourceTimeUsed].[OpDtlSeq] as [ResourceTimeUsed_OpDtlSeq],
	[ResourceTimeUsed].[WhatIf] as [ResourceTimeUsed_WhatIf],
	[ResourceTimeUsed].[AllocNum] as [ResourceTimeUsed_AllocNum],
	[ResourceTimeUsed].[ResourceGrpID] as [ResourceTimeUsed_ResourceGrpID],
	[ResourceTimeUsed].[ResourceID] as [ResourceTimeUsed_ResourceID],
	[ResourceTimeUsed].[StartDate] as [ResourceTimeUsed_StartDate],
	[ResourceTimeUsed].[StartTime] as [ResourceTimeUsed_StartTime],
	[ResourceTimeUsed].[EndDate] as [ResourceTimeUsed_EndDate],
	[ResourceTimeUsed].[EndTime] as [ResourceTimeUsed_EndTime],
	[ResourceTimeUsed].[Lock] as [ResourceTimeUsed_Lock],
	[ResourceTimeUsed].[LoadDate] as [ResourceTimeUsed_LoadDate],
	[ResourceTimeUsed].[LoadHour] as [ResourceTimeUsed_LoadHour],
	[ResourceTimeUsed].[EstHours] as [ResourceTimeUsed_EstHours],
	[ResourceTimeUsed].[ActualHours] as [ResourceTimeUsed_ActualHours],
	[ResourceTimeUsed].[LoadDays] as [ResourceTimeUsed_LoadDays],
	[ResourceTimeUsed].[LoadHours] as [ResourceTimeUsed_LoadHours],
	[ResourceTimeUsed].[RestoreFlag] as [ResourceTimeUsed_RestoreFlag],
	[ResourceTimeUsed].[SysDate] as [ResourceTimeUsed_SysDate],
	[ResourceTimeUsed].[SysTime] as [ResourceTimeUsed_SysTime],
	[ResourceTimeUsed].[JobEngineered] as [ResourceTimeUsed_JobEngineered],
	[ResourceTimeUsed].[DailyProdQty] as [ResourceTimeUsed_DailyProdQty],
	[ResourceTimeUsed].[SysUser] as [ResourceTimeUsed_SysUser],
	[ResourceTimeUsed].[SysRowID] as [ResourceTimeUsed_SysRowID]
from Erp.ResourceTimeUsed as ResourceTimeUsed
where (ResourceTimeUsed.LoadDate >= @StartDate  and ResourceTimeUsed.LoadDate <= @EndDate))  as RTU
inner join Erp.Resource as Resource on 
	Resource.Company = RTU.ResourceTimeUsed_Company
	and Resource.ResourceID = RTU.ResourceTimeUsed_ResourceID
inner join Erp.ResourceGroup as ResourceGroup on 
	Resource.Company = ResourceGroup.Company
	and Resource.ResourceGrpID = ResourceGroup.ResourceGrpID
inner join  (select 
	(ROW_NUMBER() OVER(ORDER BY ZDataField.SysRevID ASC)) as [Calculated_RowNum]
from Ice.ZDataField as ZDataField)  as RowCount on 
	RowCount.Calculated_RowNum <= [Ice].num_entries(RTU.ResourceTimeUsed_LoadDays,'~')
inner join Erp.JobOper as JobOper on 
	JobOper.Company = RTU.ResourceTimeUsed_Company
	and JobOper.JobNum = RTU.ResourceTimeUsed_JobNum
	and JobOper.AssemblySeq = RTU.ResourceTimeUsed_AssemblySeq
	and JobOper.OprSeq = RTU.ResourceTimeUsed_OprSeq
inner join Erp.JobAsmbl as JobAsmbl on 
	JobAsmbl.Company = JobOper.Company
	and JobAsmbl.JobNum = JobOper.JobNum
	and JobAsmbl.AssemblySeq = JobOper.AssemblySeq
inner join Erp.JobProd as JobProd on 
	JobProd.Company = JobAsmbl.Company
	and JobProd.JobNum = JobAsmbl.JobNum
inner join Erp.JobHead as JobHead on 
	JobHead.Company = JobProd.Company
	and JobHead.JobNum = JobProd.JobNum
	and ( JobHead.JobClosed = false  ))  as SubQuery1
where (SubQuery1.Resource_ResourceGrpID in ('2B', '4A', 'MCU')))  as SubQuery4
group by [SubQuery4].[ResourceTimeUsed_WhatIf],
	[SubQuery4].[Resource_ResourceGrpID],
	[SubQuery4].[Calculated_LoadMonth],
	[SubQuery4].[JobHead_JobNum],
	[SubQuery4].[JobHead_PartNum],
	[SubQuery4].[JobHead_ProdQty],
	[SubQuery4].[JobAsmbl_PartNum],
	[SubQuery4].[JobOper_OprSeq],
	[SubQuery4].[JobOper_RunQty],
	[SubQuery4].[JobOper_ProdStandard],
	[SubQuery4].[Calculated_EarnedHours]
having (sum(cast(SubQuery4.Calculated_LoadHours as decimal (5,2)))) > 0
order by SubQuery4.ResourceTimeUsed_WhatIf, SubQuery4.JobHead_PartNum, SubQuery4.JobAsmbl_PartNum, SubQuery4.JobOper_OprSeq

Thank you for your time!
Nate

Have you tried setting your company code on one of your tables. It is probally timing out.

1 Like

All of the queries include company as the first join. Is that what you mean? I also tried increasing the timeout to 60 seconds, but the dash continues to return 0 records, while the BAQ returns about 500 in only a few hundred milliseconds.

Add it in on one of you table criteria
.

1 Like

Added criteria Company = BAQ CurrentCompany constant to the JobHead table. This seems to have fixed it! I never would have thought to do that since we only have one company. Thanks! @Devin.Draeger

Yeah i had to do that on one of our BAQ doing the same thing

1 Like

2 Likes

@Mark_Wonsil huh? I feel like you’re trying to communicate something important in a witty way, and I don’t get it. :grimacing:

Almost all indexes in the database start with the field Company. Part for example has the primary index Company and PartNum. So if you do a BAQ with a condition on the PartNum only, it won’t use the index. But if you use Company and PartNum, it will and it will be faster.

Wouldn’t it be great if BAQ designer could suggest links for indexed fields? Otherwise, you have to either know the indexed fields already, or look them up. It looks like I discovered this company thing in the past. I see it included on some older BAQs that have a lot going on. I guess I just got lazy and stopped including company because it isn’t required.

When the links automagically appear when dragging tables on the screen, that’s Epicor suggesting indexed fields. It just can’t do it for subqueries… not easily anyway

Should company be referenced in every table and subquery in the table criteria?

i don’t think it needs to be put on for all table queries, but it should be in your table joins as that is a primary index on those tables.

Almost always. If you go to the Data Dictionary Viewer, you can scroll down the indexes on a table.

Index Name	Fields	
IX_JobHead	Company,JobNum
PK_JobHead	SysRowID
IX_JobHead_CallNum	Company,CallNum,CallLine
IX_JobHead_Candidates	Company,JobClosed,JobComplete,Candidate,JobNum
IX_JobHead_ClsdCmpStart	Company,JobClosed,JobComplete,WIStartDate,WIStartHour,JobNum
IX_JobHead_CmplJobNum	Company,JobClosed,JobComplete,JobNum
IX_JobHead_CmpPart	Company,JobComplete,PartNum,JobCompletionDate
IX_JobHead_CmpProdYld	Company,JobClosed,JobComplete,JobEngineered,JobReleased,ProductionYield
IX_JobHead_EngJobNum	Company,JobEngineered
IX_JobHead_EquipClsDt	Company,EquipID,ClosedDate
IX_JobHead_HDCaseNum	Company,HDCaseNum,JobNum
IX_JobHead_JobClosed	Company,JobClosed,ReqDueDate
IX_JobHead_JobDue	Company,JobClosed,DueDate,JobNum
IX_JobHead_JobProdYld	Company,JobNum,JobClosed,JobComplete,JobEngineered,JobReleased,ProductionYield
IX_JobHead_JobStart	Company,JobClosed,StartDate,JobNum
IX_JobHead_OpenJob	Company,JobClosed,JobNum
IX_JobHead_PartNum	Company,JobClosed,PartNum,JobNum
IX_JobHead_PlantCallNum	Company,Plant,CallNum,CallLine
IX_JobHead_PlantCandidates	Company,Plant,JobClosed,JobComplete,Candidate,JobNum
IX_JobHead_PlantJobClosed	Company,Plant,JobClosed,ReqDueDate,JobNum
IX_JobHead_PlantJobDue	Company,Plant,JobClosed,DueDate,JobNum
IX_JobHead_PlantJobNum	Company,Plant,JobNum
IX_JobHead_PlantJobStart	Company,Plant,JobClosed,StartDate,JobNum
IX_JobHead_PlantOpenJob	Company,Plant,JobClosed,JobNum
IX_JobHead_PlantPartNum	Company,Plant,JobClosed,PartNum,JobNum
IX_JobHead_PlantProject	Company,Plant,ProjectID,JobNum
IX_JobHead_PlantTypeTemplate	Company,Plant,JobType,InCopyList,JobNum
IX_JobHead_Project	Company,ProjectID,JobNum
IX_JobHead_ProjPhase	Company,ProjectID,PhaseID,JobNum
IX_JobHead_RCutScheduled	Company,RoughCutScheduled
IX_JobHead_RelJobNum	Company,JobReleased
IX_JobHead_StatusReadyToPrint	Company,Plant,StatusReadyToPrint,JobNum
IX_JobHead_TravelerReadyToPrint	Company,Plant,TravelerReadyToPrint,JobNum
IX_JobHead_WhatIf	Company,WIName
IX_JobHead_WIPCleared	Company,WIPCleared,JobNum
IX_JobHead_WordIssueTopics	IssueTopics
IX_JobHead_WordResTopics	ResTopics
IX_JobHead_SchedPriority	Company,SchedPriority,ReqDueDate,JobNum
IX_JobHead_SchedSeq	Company,SchedSeq
IX_JobHead_ContractID	Company,ContractID
1 Like

This is neat. I have looked at the DDV before but didn’t really get it. Can you help me understand what I am seeing here? Are there different indexes based on which field you are pulling from the table? Like this line:

IX_JobHead_PartNum	Company,JobClosed,PartNum,JobNum

Does this mean if I want to pull in the part number from job head, that I need to include each of those fields?

I include as many as I can from left to right, depending how I’m linking. If I’m looking for all parts for a job, then yes.

1 Like

I just want to make sure I get this right. For example, I am joining JobHead and JobProd. I link them on Company, PartNum, and JobNum. Do I also need to somehow link them on JobClosed?

So, it depends. Are you just looking at only open jobs in your query? If so, then yes. If you want all jobs regardless of the JobClose field, then no.

And you don’t have to link to another table. You can provide a constant like above - BAQ Company for example like @Devin.Draeger suggested.

In the end, you should really just try it out and see what gives you the best performance. Use the indexes to your advantage whenever possible. SQL Server is smart and does well but play around until you find acceptable performance.

1 Like

Hey @NateS , if you really want to get a handle on what indexes are, and how they work, I encourage you to spend some time and watch this video series. It gives a good intro to how indexes work and what they are.

1 Like

If I link up a UD table, and I only have values in Key1, do I need to link all 5 keys and set the criteria to Key2 = ‘’ ?
In my example I am linking UD07 with a subquery that contains a job number. Key1 has that job number.