A select query with join returns results in less than 1 sec(returns 1000 rows: 600 ms) but insert into temp table or physical table takes 15-16 seconds.
tested io performance : a select or insert into without any joins takes sub-second to write 1000 rows.
tried trace flag 1118
tried adding clustered index on the temp table and do insert into with tablock and maxdop hint.
None of these improved performance.
Thanks for all your comments. 6000 to 20000 rows that need to be inserted every 5 seconds from Kafka...
I get the data from kafka into sql server using table type variable
Pass it as a parameter to stored procedure
Load this data joining with other tables into a temporary table #table
I use the #table to merge the data into application table
Found a workaround that helps me achieve the target turnaround time but dont exactly know the reason for the behaviour. As I mentioned in the problem statement, the bottleneck was writing the resultset of the select statement that joins the table variable with various other tables to the temp table.
I put this into a stored prod and returned the execution of the stored proc to a temp table. Now the insert takes less than 1 sec
SELECT
i.Id AS IId,
df.Id AS dfid,
MAX(CASE
WHEN lp.Value IS NULL and f.pnp = 1 THEN 0
WHEN lp.Value = 0 and f.tzan = 1 and f.pnp = 0 THEN NULL
ELSE lp.Value
END) 'FV',
MAX(lp.TS),
MAX(lp.Eid),
MAX(0+lp.IsDelayedStream)
FROM
f1 f WITH (NOLOCK)
INNER JOIN ft1 ft WITH (NOLOCK) ON f.FeedTypeId = ft.Id
INNER JOIN FeedDataField fdf WITH (NOLOCK)
ON fdf.FeedId = f.Id
INNER JOIN df1 df WITH (NOLOCK)
ON fdf.dfId = df.Id
INNER JOIN ds1 ds WITH (NOLOCK)
ON df.dsid = ds.Id
INNER JOIN dp1 dp WITH (NOLOCK)
ON ds.dpId = dp.Id
INNER JOIN dc1 dc WITH (NOLOCK)
ON dc.dcId = ds.dcId
INNER JOIN i1 i WITH (NOLOCK)
ON f.iId = I.Id
INNER JOIN id1 id WITH (NOLOCK)
ON id.iId = i.Id
INNER JOIN IdentifierType it WITH (NOLOCK)
ON id.ItId = it.Id
INNER JOIN ivw_Tdf tdf WITH(NOEXPAND)
ON tdf.iId = i.Id
INNER JOIN z.dbo.[tlp] lp
ON lp.Ticker = id.Name AND lp.Field = df.SourceName AND
lp.Contributor = dc.Name AND lp.YellowKey = tdf.TextValue
WHERE
ft.Name in ('X', 'Y') AND f.SA = 1
AND dp.Name = 'B' AND (i.Inactive IS NULL OR i.Inactive = 0)
AND it.Name = 'T' AND id.ValidTo = #InfinityDate
AND tdf.SourceName = 'MSD'
AND tdf.ValidTo = #Infinity
GROUP BY i.Id, df.Id
OPTION(MAXDOP 4, OPTIMIZE FOR (#Infinity = '9999-12-31 23:59:59',
#InfinityDate = '9999-12-31))
Related
I have the below query with multiple joins.The last 3 joins are required to get the g.fin_id value. This works fine (see results) BUT because some records in the ACCUM_ISS_CHAR_HIST table have e.char9_nme values of NULL, it excludes the records in the results altogether. So it seems as when the e.char9_nme value has a record then it will produce a result, but as soon as it has a Null value then it is excluded. I would still like to see the records even though the g.fin_id for those will then be blank because they have a e.char9_nme value of Null. How can I change the query to accomplish this?
select
a.acct_id,
c.fld3_txt,
b.issue_loc1_cde,
b.instr_id,
a.fld1_nme,
b.issue_cls2_nme,
g.fin_id,
e.char9_nme
from position_dg as a
inner join
infoportal..issue_dg as b on b.INSTR_ID = a.INSTR_ID
inner join
InfoPortal..IVW_ACCT as c on a.acct_id = c.acct_id
inner join
InfoPortal..DW_AcctCharDG as d on a.acct_id = d.acctid
inner join
ACCUM_ISS_CHAR_HIST as e on a.instr_id = e.instr_id
inner join
MD_FINANCIAL_ENTITY as f on e.char9_nme = f.fin_enty_name
inner join md_FINANCIAL_ENTITY_ALTERNATE_IDENTIFIER as g on
f.fin_enty_id = g.fin_enty_id
and b.MAT_EXP_DTE > getdate()
and b.issue_cls1_nme = 'Derivatives'
and a.as_of_tms >= getdate()-1
and b.iss_typ in ('FFX','IRS','EQF')
and d.AcctChrSetId = 'DerivativeRpt'
and d.EndTms IS NULL
and a.acct_id = 'FOGEMBLCR'
and g.id_ctxt_typ = 'LEGAL_ENTITY_IDENTIFIER'
and e.as_of_dte = (
select MAX (as_of_dte)-1
from accum_iss_char_hist
)
I expect the results to show fin_id records for some ond blank fin_id records for some, but at the moment only the ones with a fin_id record is hown and the rest is excluded from the results.
You are looking for a left join.
Join all those tables (last 3 as you said) as left join. For better clarity I have moved conditions of every tables in their ON clause and for base table a made a where clause.
select
a.acct_id,
c.fld3_txt,
b.issue_loc1_cde,
b.instr_id,
a.fld1_nme,
b.issue_cls2_nme,
g.fin_id,
e.char9_nme
from position_dg as a
inner join
infoportal..issue_dg as b on b.INSTR_ID = a.INSTR_ID
and b.MAT_EXP_DTE > getdate()
and b.issue_cls1_nme = 'Derivatives'
and b.iss_typ in ('FFX','IRS','EQF')
inner join
InfoPortal..IVW_ACCT as c on a.acct_id = c.acct_id
inner join
InfoPortal..DW_AcctCharDG as d on a.acct_id = d.acctid
and d.AcctChrSetId = 'DerivativeRpt'
and d.EndTms IS NULL
left join
ACCUM_ISS_CHAR_HIST as e on a.instr_id = e.instr_id
and e.as_of_dte = (
select MAX (as_of_dte)-1
from accum_iss_char_hist
)
left join
MD_FINANCIAL_ENTITY as f on e.char9_nme = f.fin_enty_name
left join
md_FINANCIAL_ENTITY_ALTERNATE_IDENTIFIER as g on f.fin_enty_id = g.fin_enty_id
and g.id_ctxt_typ = 'LEGAL_ENTITY_IDENTIFIER'
Where a.as_of_tms >= getdate()-1
and a.acct_id = 'FOGEMBLCR'
What can be the reason for slow inserts into my SQL Server table compared to my local DB with 4GB of memory the script which is running less than 2 seconds while on my client's server with 1GB memory (attached image) it took 50 seconds.
Below is a sample query, records from my local and from my client's db are almost the same count.
IF OBJECT_ID('tempdb..#TempUnitServiceLogs') IS NOT NULL
drop table #TempUnitServiceLogs
Select
F.Unit_Id, MAX(F.UnitTransaction_Id) UnitTransaction_Id
into
#TempUnitServiceLogs
from
TempUnitServiceLogs F
group by F.Unit_Id
insert into TempUnitServiceLogs
Select
A.Unit_Id
,C.Brand_Name
,A.Unit_CompanyCode
,B.Project_Code
,A.Unit_Code
,A.Unit_Status
from Table1 A
inner join Table2 B on A.Project_Id = B.Project_Id
inner join Table3 C on B.Brand_Id = C.Brand_Id
left join #TempUnitServiceLogs D on A.Unit_Id = D.Unit_ID
left join Table4 ut on ut.Unit_Id = A.Unit_Id
left join Table5 pb on pb.ProspectiveBuyer_Id = ut.ProspectiveBuyer_Id
where 1=1
and d.UnitTransaction_Id IS NULL
and case when UnitTransaction_ModDate IS null
then convert(date,UnitTransaction_CrDate)
else convert(date,UnitTransaction_ModDate) end = CONVERT(date,GETDATE())
All the example used below is currently for only one Salesorganization and we may have more different salesOrganization number later in future.
I have 6 tables which has millions of records. This tables are populated by execution of SSIS package.
select count(*) from tmp_materials --11,02,032
select count(*) from tbl_VendorLogoData --20,41,501
select count(*) from TBL_Image_EDV --4,44,063
select count(*) from TBL_EXTPRODUCTATTRIBUTES_EDV -- 2,06,15,572
select count(*) from TBL_Accessories_EDV --10,11,568
select count(*) from TBL_SimilarSku --64,10,408
I have a stored procedure which is used to select distinct records from these tables
SELECT DISTINCT 'MD' AS [COMPANYCD]
, MAIN.MATERIAL AS [MATERIAL]
, ISNULL(UPPER(IMG.[lowprovider]),'') AS [LOW_IMAGE]
, ISNULL(UPPER(IMG.[midprovider]), '') AS [MID_IMAGE]
, ISNULL(UPPER(IMG.[highprovider]), '') AS [HIGH_IMAGE]
, ISNULL(UPPER(VS.isLogo),'') AS [VENDOR_LOGO]
, ISNULL(UPPER(DS.PROVIDER), '') AS [DATASHEET]
, ISNULL(ACC.AccessoryMaterial, '') AS [OPT_ACC]
, ISNULL(UPPER(ACC.Provider), '') AS [OPT_ACC_PROVIDER]
, ISNULL(SS.Similarsku, '') AS [SIMILAR_SKU]
, ISNULL(UPPER(SS.ProviderName), '') AS [SIMILAR_SKU_PROVIDER]
FROM tmp_materials MAIN WITH (NOLOCK)
LEFT OUTER JOIN TBL_Image_EDV IMG WITH (NOLOCK) ON MAIN.MATERIAL = IMG.MATERIAL AND MAIN.salesOrg = IMG.SalesOrganization
LEFT OUTER JOIN TBL_EXTPRODUCTATTRIBUTES_EDV DS WITH (NOLOCK) ON MAIN.MATERIAL = DS.SKUNBR AND MAIN.salesOrg = DS.SalesOrganization
LEFT OUTER JOIN TBL_Accessories_EDV ACC WITH (NOLOCK) ON MAIN.MATERIAL = ACC.ParentSKU AND MAIN.salesOrg = DS.SalesOrganization
LEFT OUTER JOIN TBL_SimilarSku SS WITH (NOLOCK) ON MAIN.MATERIAL = SS.ParentSKU AND MAIN.salesOrg = DS.SalesOrganization
LEFT OUTER JOIN tbl_VendorLogoData VS WITH (NOLOCK) ON MAIN.MATERIAL = VS.SKU AND MAIN.salesOrg = VS.Salesorganization
WHERE MAIN.salesOrg = #SALESORGANIZATION
AND (CASE WHEN IMG.MATERIAL IS NULL AND DS.SKUNBR IS NULL AND ACC.ParentSKU IS NULL AND SS.ParentSKU IS NULL AND VS.SKU IS NULL
THEN 0 ELSE 1 END) = 1
AND DS.Provider <> 'novalue'
AND SS.RecordIdentifier like '%##%'
AND ACC.RecordIdentifier like '%##%'
AND ACC.accessorySku LIKE '%##%'
The parameter for these procedure is #SALESORGANIZATION This is used to populate a report. I am running this for multiple salesorganization values. But for one of the salesorganization it is taking more than 5 hours to generate the data.
It seems i will need to write a loop, but finding it difficult to proceed with multiple joins any suggestions?
Please advice how can i optimize this query? Thanks for your assitance.
There you have an execution plan file SQL Execution Plan
Try to include more condition to improve performance.
In all the LEFT OUTER JOIN checks include your parameter directly and try to avoid JOINDE tables using there
e.g
LEFT OUTER JOIN TBL_Image_EDV IMG WITH (NOLOCK) ON
MAIN.MATERIAL = IMG.MATERIAL
AND MAIN.salesOrg = IMG.SalesOrganization
AND IMG.SalesOrganization=#SALESORGANIZATION
Add conditions in the WHERE
AND SS.RecordIdentifier like '%##%'
should be
(SS.id IS NOT NULL AND SS.RecordIdentifier like '%##%')
Thus you first cut the rows with no relation
UPDATE
One more idea
Try
INNER JOIN (select *
from TBL_Accessories_EDV
where RecordIdentifier like '%##%'
AND accessorySku LIKE '%##%') ACC WITH (NOLOCK)
ON MAIN.MATERIAL = ACC.ParentSKU AND MAIN.salesOrg = DS.SalesOrganization
Just to restrict amout of records you filter out later
Im having performance issues with this query. If I remove the status column it runs very fast but adding the subquery in the column section delays way too much the query 1.02 min. How can I modify this query so it runs fast getting the desired data.
The reason I put that subquery there its because I needed the status for the latest activity, some activities have null status so I have to ignore them.
Establishments: 6.5k rows -
EstablishmentActivities: 70k rows -
Status: 2 (Active, Inactive)
SELECT DISTINCT
est.id,
est.trackingNumber,
est.NAME AS 'establishment',
actTypes.NAME AS 'activity',
(
SELECT stat3.NAME
FROM SACPAN_EstablishmentActivities eact3
INNER JOIN SACPAN_ActivityTypes at3
ON eact3.activityType_FK = at3.code
INNER JOIN SACPAN_Status stat3
ON stat3.id = at3.status_FK
WHERE eact3.establishment_FK = est.id
AND eact3.rowCreatedDT = (
SELECT MAX(est4.rowCreatedDT)
FROM SACPAN_EstablishmentActivities est4
INNER JOIN SACPAN_ActivityTypes at4
ON est4.establishment_fk = est.id
AND est4.activityType_FK = at4.code
WHERE est4.establishment_fk = est.id
AND at4.status_FK IS NOT NULL
)
AND at3.status_FK IS NOT NULL
) AS 'status',
est.authorizationNumber,
reg.NAME AS 'region',
mun.NAME AS 'municipality',
ISNULL(usr.NAME, '') + ISNULL(+ ' ' + usr.lastName, '')
AS 'created',
ISNULL(usr2.NAME, '') + ISNULL(+ ' ' + usr2.lastName, '')
AS 'updated',
est.rowCreatedDT,
est.rowUpdatedDT,
CASE WHEN est.rowUpdatedDT >= est.rowCreatedDT
THEN est.rowUpdatedDT
ELSE est.rowCreatedDT
END AS 'LatestCreatedOrModified'
FROM SACPAN_Establishments est
INNER JOIN SACPAN_EstablishmentActivities eact
ON est.id = eact.establishment_FK
INNER JOIN SACPAN_ActivityTypes actTypes
ON eact.activityType_FK = actTypes.code
INNER JOIN SACPAN_Regions reg
ON est.region_FK = reg.code --
INNER JOIN SACPAN_Municipalities mun
ON est.municipality_FK = mun.code
INNER JOIN SACPAN_ContactEstablishments ce
ON ce.establishment_FK = est.id
INNER JOIN SACPAN_Contacts con
ON ce.contact_FK = con.id
--JOIN SACPAN_Status stat ON stat.id = actTypes.status_FK
INNER JOIN SACPAN_Users usr
ON usr.id = est.rowCreatedBy_FK
LEFT JOIN SACPAN_Users usr2
ON usr2.id = est.rowUpdatedBy_FK
WHERE (con.ssn = #ssn OR #ssn = '*')
AND eact.rowCreatedDT = (
SELECT MAX(eact2.rowCreatedDT)
FROM SACPAN_EstablishmentActivities eact2
WHERE eact2.establishment_FK = est.id
)
--AND est.id = 6266
ORDER BY 'LatestCreatedOrModified' DESC
Try moving that 'activiy' query to a Left Join and see if it speeds it up.
I solved the problem by creating a temporary table and creating an index to it, this removed the need of the slow subquery in the select statement. Then I join the temp table as I do with normal tables.
Thanks to all.
I have a hard time with query optimization, currently I'm very close to the point of database redesign. And the stackoverflow is my last hope. I don't think that just showing you the query is enough so I've linked not only database script but also attached database backup in case you don't want to generate the data by hand
Here you can find both the script and the backup
The problems start when you try to do the following...
exec LockBranches #count=64,#lockedBy='034C0396-5C34-4DDA-8AD5-7E43B373AE5A',#lockedOn='2011-07-01 01:29:43.863',#unlockOn='2011-07-01 01:32:43.863'
The main problems occur in this part:
UPDATE B
SET B.LockedBy = #lockedBy,
B.LockedOn = #lockedOn,
B.UnlockOn = #unlockOn,
B.Complete = 1
FROM
(
SELECT TOP (#count) B.LockedBy, B.LockedOn, B.UnlockOn, B.Complete
FROM Objectives AS O
INNER JOIN Generations AS G ON G.ObjectiveID = O.ID
INNER JOIN Branches AS B ON B.GenerationID = G.ID
INNER JOIN
(
SELECT SB.BranchID AS BranchID, SUM(X.SuitableProbes) AS SuitableProbes
FROM SpicieBranches AS SB
INNER JOIN Probes AS P ON P.SpicieID = SB.SpicieID
INNER JOIN
(
SELECT P.ID, 1 AS SuitableProbes
FROM Probes AS P
/* ----> */ INNER JOIN Results AS R ON P.ID = R.ProbeID /* SSMS Estimated execution plan says this operation is the roughest */
GROUP BY P.ID
HAVING COUNT(R.ID) > 0
) AS X ON P.ID = X.ID
GROUP BY SB.BranchID
) AS X ON X.BranchID = B.ID
WHERE
(O.Active = 1)
AND (B.Sealed = 0)
AND (B.GenerationNo < O.BranchGenerations)
AND (B.LockedBy IS NULL OR DATEDIFF(SECOND, B.UnlockOn, GETDATE()) > 0)
AND (B.Complete = 1 OR X.SuitableProbes = O.BranchSize * O.EstimateCount * O.ProbeCount)
) AS B
EDIT: Here are the amounts of rows in each table:
Spicies 71536
Results 10240
Probes 10240
SpicieBranches 4096
Branches 256
Estimates 5
Generations 1
Versions 1
Objectives 1
Somebody else might be able to explain better than I can why this is much quicker. Experience tells me when you have a bunch of queries that collectively run slow together but should be quick in their individual parts then its worth trying a temporary table.
This is much quicker
ALTER PROCEDURE LockBranches
-- Add the parameters for the stored procedure here
#count INT,
#lockedOn DATETIME,
#unlockOn DATETIME,
#lockedBy UNIQUEIDENTIFIER
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
--Create Temp Table
SELECT SpicieBranches.BranchID AS BranchID, SUM(X.SuitableProbes) AS SuitableProbes
INTO #BranchSuitableProbeCount
FROM SpicieBranches
INNER JOIN Probes AS P ON P.SpicieID = SpicieBranches.SpicieID
INNER JOIN
(
SELECT P.ID, 1 AS SuitableProbes
FROM Probes AS P
INNER JOIN Results AS R ON P.ID = R.ProbeID
GROUP BY P.ID
HAVING COUNT(R.ID) > 0
) AS X ON P.ID = X.ID
GROUP BY SpicieBranches.BranchID
UPDATE B SET
B.LockedBy = #lockedBy,
B.LockedOn = #lockedOn,
B.UnlockOn = #unlockOn,
B.Complete = 1
FROM
(
SELECT TOP (#count) Branches.LockedBy, Branches.LockedOn, Branches.UnlockOn, Branches.Complete
FROM Objectives
INNER JOIN Generations ON Generations.ObjectiveID = Objectives.ID
INNER JOIN Branches ON Branches.GenerationID = Generations.ID
INNER JOIN #BranchSuitableProbeCount ON Branches.ID = #BranchSuitableProbeCount.BranchID
WHERE
(Objectives.Active = 1)
AND (Branches.Sealed = 0)
AND (Branches.GenerationNo < Objectives.BranchGenerations)
AND (Branches.LockedBy IS NULL OR DATEDIFF(SECOND, Branches.UnlockOn, GETDATE()) > 0)
AND (Branches.Complete = 1 OR #BranchSuitableProbeCount.SuitableProbes = Objectives.BranchSize * Objectives.EstimateCount * Objectives.ProbeCount)
) AS B
END
This is much quicker with an average execution time of 54ms compared to 6 seconds with the original one.
EDIT
Had a look and combined my ideas with those from RBarryYoung's solution. If you use the following to create the temporary table
SELECT SB.BranchID AS BranchID, COUNT(*) AS SuitableProbes
INTO #BranchSuitableProbeCount
FROM SpicieBranches AS SB
INNER JOIN Probes AS P ON P.SpicieID = SB.SpicieID
WHERE EXISTS(SELECT * FROM Results AS R WHERE R.ProbeID = P.ID)
GROUP BY SB.BranchID
then you can get this down to 15ms which is 400x better than we started with. Looking at the execution plan shows that there is a table scan happening on the temp table. Normally you avoid table scans as best you can but for 128 rows (in this case) it is quicker than whatever it was doing before.
This is basically a complete guess here, but in times past I've found that joining onto the results of a sub-query can be horrifically slow. That is, the subquery was being evaluated way too many times when it really didn't need to.
The way around this was to move the subqueries into CTEs and to join onto those instead. Good luck!
It appears the join on the two uniqueidentifier columns are the source of the problem. One is a clustered index, the other non-clustered on the (FK table). Good that there are indexes on them. Unfortunately guids are notoriously poor performing when joining with large numbers of rows.
As troubleshooting steps:
what state are the indexes in? When was the last time the statistics were updated?
how performant is that subquery onto itself, when executed adhoc? i.e. when you run this statement by itself, how fast does the resultset return? acceptable?
after rebuilding the 2 indexes, and updating statistics, is there any measurable difference?
SELECT P.ID, 1 AS SuitableProbes FROM Probes AS P
INNER JOIN Results AS R ON P.ID = R.ProbeID
GROUP BY P.ID HAVING COUNT(R.ID) > 0
The following runs about 15x faster on my system:
UPDATE B
SET B.LockedBy = #lockedBy,
B.LockedOn = #lockedOn,
B.UnlockOn = #unlockOn,
B.Complete = 1
FROM
(
SELECT TOP (#count) B.LockedBy, B.LockedOn, B.UnlockOn, B.Complete
FROM Objectives AS O
INNER JOIN Generations AS G ON G.ObjectiveID = O.ID
INNER JOIN Branches AS B ON B.GenerationID = G.ID
INNER JOIN
(
SELECT SB.BranchID AS BranchID, COUNT(*) AS SuitableProbes
FROM SpicieBranches AS SB
INNER JOIN Probes AS P ON P.SpicieID = SB.SpicieID
WHERE EXISTS(SELECT * FROM Results AS R WHERE R.ProbeID = P.ID)
GROUP BY SB.BranchID
) AS X ON X.BranchID = B.ID
WHERE
(O.Active = 1)
AND (B.Sealed = 0)
AND (B.GenerationNo < O.BranchGenerations)
AND (B.LockedBy IS NULL OR DATEDIFF(SECOND, B.UnlockOn, GETDATE()) > 0)
AND (B.Complete = 1 OR X.SuitableProbes = O.BranchSize * O.EstimateCount * O.ProbeCount)
) AS B
Insertion of sub query into local temporary table
SELECT SB.BranchID AS BranchID, SUM(X.SuitableProbes) AS SuitableProbes
into #temp FROM SpicieBranches AS SB
INNER JOIN Probes AS P ON P.SpicieID = SB.SpicieID
INNER JOIN
(
SELECT P.ID, 1 AS SuitableProbes
FROM Probes AS P
/* ----> */ INNER JOIN Results AS R ON P.ID = R.ProbeID /* SSMS Estimated execution plan says this operation is the roughest */
GROUP BY P.ID
HAVING COUNT(R.ID) > 0
) AS X ON P.ID = X.ID
GROUP BY SB.BranchID
The below query shows the partial joins with the corresponding table instead of complete!!
UPDATE B
SET B.LockedBy = #lockedBy,
B.LockedOn = #lockedOn,
B.UnlockOn = #unlockOn,
B.Complete = 1
FROM
(
SELECT TOP (#count) B.LockedBy, B.LockedOn, B.UnlockOn, B.Complete
From
(
SELECT ID, BranchGenerations, (BranchSize * EstimateCount * ProbeCount) as MultipliedFactor
FROM Objectives AS O WHERE (O.Active = 1)
)O
INNER JOIN Generations AS G ON G.ObjectiveID = O.ID
Inner Join
(
Select Sealed, GenerationNo, LockedBy, UnlockOn, ID, Complete
From Branches
Where B.Sealed = 0 AND (B.LockedBy IS NULL OR DATEDIFF(SECOND, B.UnlockOn, GETDATE()) > 0)
)B ON B.GenerationID = G.ID
INNER JOIN
(
Select * from #temp
) AS X ON X.BranchID = B.ID
WHERE
AND (B.GenerationNo < O.BranchGenerations)
AND (B.Complete = 1 OR X.SuitableProbes = O.MultipliedFactor)
) AS B