@@ -206,59 +206,51 @@ export const buildQuery = ({
206206 log . info ( `useActivityCountOptimized=${ useActivityCountOptimized } ` )
207207 if ( useActivityCountOptimized ) {
208208 const ctes : string [ ] = [ ]
209-
210- // Include member_orgs CTE only for the OUTER query (never filter inside the CTE)
211209 if ( needsMemberOrgs ) ctes . push ( buildMemberOrgsCTE ( true ) . trim ( ) )
212-
213- // Include search CTE if present, but join it to msa inside top_members via memberId
214210 if ( searchConfig . cte ) ctes . push ( searchConfig . cte . trim ( ) )
215211
216212 const searchJoinForTopMembers = searchConfig . cte
217213 ? `\n INNER JOIN member_search ms ON ms."memberId" = msa."memberId"`
218214 : ''
219215
220- // Fix pagination: fetch enough rows to handle the requested page correctly
221- const totalNeeded = limit + offset
216+ const oversampleMultiplier = 5
217+ const prefetch = Math . max ( offset + limit * oversampleMultiplier , offset + limit )
222218
223219 ctes . push (
224220 `
225- top_members AS (
226- SELECT
227- msa."memberId",
228- msa."activityCount"
229- FROM "memberSegmentsAgg" msa
230- ${ searchJoinForTopMembers }
231- WHERE
232- msa."segmentId" = $(segmentId)
233- ORDER BY
234- msa."activityCount" ${ direction } NULLS LAST
235- LIMIT ${ totalNeeded }
236- )
237- ` . trim ( ) ,
221+ top_members AS (
222+ SELECT
223+ msa."memberId",
224+ msa."activityCount",
225+ ROW_NUMBER() OVER (
226+ ORDER BY msa."activityCount" ${ direction } NULLS LAST, msa."memberId" ASC
227+ ) AS rn
228+ FROM "memberSegmentsAgg" msa
229+ ${ searchJoinForTopMembers }
230+ WHERE msa."segmentId" = $(segmentId)
231+ ORDER BY msa."activityCount" ${ direction } NULLS LAST
232+ LIMIT ${ prefetch }
233+ )
234+ ` . trim ( ) ,
238235 )
239236
240237 const withClause = `WITH ${ ctes . join ( ',\n' ) } `
241238 const memberOrgsJoin = needsMemberOrgs ? `LEFT JOIN member_orgs mo ON mo."memberId" = m.id` : ''
242239
243- // Outer filters (including mo./me.) applied here; remove OFFSET/LIMIT since top_members already handles it
244240 return `
245- ${ withClause }
246- SELECT ${ fields }
247- FROM top_members tm
248- JOIN members m
249- ON m.id = tm."memberId"
250- INNER JOIN "memberSegmentsAgg" msa
251- ON msa."memberId" = m.id
252- AND msa."segmentId" = $(segmentId)
253- ${ memberOrgsJoin }
254- LEFT JOIN "memberEnrichments" me
255- ON me."memberId" = m.id
256- WHERE (${ filterString } )
257- ORDER BY
258- msa."activityCount" ${ direction } NULLS LAST
259- LIMIT ${ limit }
260- OFFSET ${ offset }
261- ` . trim ( )
241+ ${ withClause }
242+ SELECT ${ fields }
243+ FROM top_members tm
244+ JOIN members m ON m.id = tm."memberId"
245+ INNER JOIN "memberSegmentsAgg" msa
246+ ON msa."memberId" = m.id AND msa."segmentId" = $(segmentId)
247+ ${ memberOrgsJoin }
248+ LEFT JOIN "memberEnrichments" me ON me."memberId" = m.id
249+ WHERE (${ filterString } )
250+ AND tm.rn > ${ offset }
251+ ORDER BY tm.rn ASC
252+ LIMIT ${ limit }
253+ ` . trim ( )
262254 }
263255
264256 // Fallback path (other sorts / non-aggregate)
0 commit comments