Skip to content

Commit d79dcb4

Browse files
authored
cache getFinishedSync result to eliminate N+1 query pattern (#604)
* cache getFinishedSync result to eliminate N+1 query pattern * add tracing
1 parent 8ae8bd8 commit d79dcb4

File tree

3 files changed

+30
-10
lines changed

3 files changed

+30
-10
lines changed

pkg/dotc1z/c1file.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ type C1File struct {
4646
readOnly bool
4747
encoderConcurrency int
4848

49+
// Cached sync run for listConnectorObjects (avoids N+1 queries)
50+
cachedViewSyncRun *syncRun
51+
cachedViewSyncOnce sync.Once
52+
cachedViewSyncErr error
53+
4954
// Slow query tracking
5055
slowQueryLogTimes map[string]time.Time
5156
slowQueryLogTimesMu sync.Mutex

pkg/dotc1z/sql_helpers.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -194,20 +194,12 @@ func listConnectorObjects[T proto.Message](ctx context.Context, c *C1File, table
194194
case reqSyncID != "":
195195
q = q.Where(goqu.C("sync_id").Eq(reqSyncID))
196196
default:
197-
var latestSyncRun *syncRun
198-
var err error
199-
latestSyncRun, err = c.getFinishedSync(ctx, 0, connectorstore.SyncTypeFull)
197+
// Use cached sync run to avoid N+1 queries during pagination
198+
latestSyncRun, err := c.getCachedViewSyncRun(ctx)
200199
if err != nil {
201200
return nil, "", err
202201
}
203202

204-
if latestSyncRun == nil {
205-
latestSyncRun, err = c.getLatestUnfinishedSync(ctx, connectorstore.SyncTypeAny)
206-
if err != nil {
207-
return nil, "", err
208-
}
209-
}
210-
211203
if latestSyncRun != nil {
212204
q = q.Where(goqu.C("sync_id").Eq(latestSyncRun.ID))
213205
}

pkg/dotc1z/sync_runs.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,29 @@ type syncRun struct {
9595
ParentSyncID string
9696
}
9797

98+
// getCachedViewSyncRun returns the cached sync run for read operations.
99+
// This avoids N+1 queries when paginating through listConnectorObjects.
100+
// The result is computed once and cached for the lifetime of the C1File.
101+
func (c *C1File) getCachedViewSyncRun(ctx context.Context) (*syncRun, error) {
102+
ctx, span := tracer.Start(ctx, "C1File.getCachedViewSyncRun")
103+
defer span.End()
104+
105+
c.cachedViewSyncOnce.Do(func() {
106+
// First try to get a finished full sync
107+
c.cachedViewSyncRun, c.cachedViewSyncErr = c.getFinishedSync(ctx, 0, connectorstore.SyncTypeFull)
108+
if c.cachedViewSyncErr != nil {
109+
return
110+
}
111+
112+
// If no finished sync, try to get an unfinished one
113+
if c.cachedViewSyncRun == nil {
114+
c.cachedViewSyncRun, c.cachedViewSyncErr = c.getLatestUnfinishedSync(ctx, connectorstore.SyncTypeAny)
115+
}
116+
})
117+
118+
return c.cachedViewSyncRun, c.cachedViewSyncErr
119+
}
120+
98121
func (c *C1File) getLatestUnfinishedSync(ctx context.Context, syncType connectorstore.SyncType) (*syncRun, error) {
99122
ctx, span := tracer.Start(ctx, "C1File.getLatestUnfinishedSync")
100123
defer span.End()

0 commit comments

Comments
 (0)