-
Notifications
You must be signed in to change notification settings - Fork 0
Database Performance Optimizations #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: db-cleanup-baseline
Are you sure you want to change the base?
Conversation
… deadlocks on MySQL (#80329) * Split subquery when cleaning annotations * update comment * Raise batch size, now that we pay attention to it * Iterate in batches * Separate cancellable batch implementation to allow for multi-statement callbacks, add overload for single-statement use * Use split-out utility in outer batching loop so it respects context cancellation * guard against empty queries * Use SQL parameters * Use same approach for tags * drop unused function * Work around parameter limit on sqlite for large batches * Bulk insert test data in DB * Refactor test to customise test data creation * Add test for catching SQLITE_MAX_VARIABLE_NUMBER limit * Turn annotation cleanup test to integration tests * lint --------- Co-authored-by: Sofia Papagiannaki <[email protected]>
|
@claude review this PR |
1 similar comment
|
@claude review this PR |
|
Claude finished @akshayutture-augment's task —— View job Code Review Complete ✅SummaryThis PR addresses database deadlock issues on MySQL by refactoring annotation cleanup logic. The changes split the cleanup process into separate query and delete operations to prevent deadlocks caused by concurrent inserts during cleanup. Overall, the implementation is solid with good test coverage and proper handling of database-specific limitations. 🎯 Key Changes
✅ Strengths1. Smart Deadlock AvoidanceThe core problem is well-addressed. Moving from a single DELETE-with-subquery to separate SELECT+DELETE operations prevents lock escalation on MySQL. Before (deadlock-prone): DELETE FROM annotation WHERE id IN (SELECT id FROM (...) a)After (deadlock-resistant): ids := fetchIDs(...) // Releases locks quickly
deleteByIDs(...) // Separate transaction2. Robust SQLite HandlingThe workaround for SQLite's 999-parameter limit is clever: if r.db.GetDBType() == migrator.SQLite && r.cfg.AnnotationCleanupJobBatchSize > sqliteParameterLimit {
values := fmt.Sprint(ids[0])
for _, v := range ids[1:] {
values = fmt.Sprintf("%s, %d", values, v)
}
sql = fmt.Sprintf(`DELETE FROM %s WHERE id IN (%s)`, table, values)3. Excellent Test CoverageThe test improvements are significant:
🔴 Critical Issues1. Error-Level Logging for Normal Operations (pkg/services/annotations/annotationsimpl/xorm_store.go)Lines 534, 537, 554, 557, 576, 579 use r.log.Error("Annotations to clean by time", "count", len(ids), "ids", ids, "cond", cond, "err", err)
r.log.Error("cleaned annotations by time", "count", len(ids), "affected", x, "err", y)Problem: This will flood error logs with routine cleanup operations, making it hard to spot actual errors. Fix: Change to r.log.Debug("Cleaning annotations by time", "count", len(ids))
r.log.Debug("Cleaned annotations by time", "affected", x)Locations:
2. SQL Injection Risk with String Concatenation (xorm_store.go:609-613)values := fmt.Sprint(ids[0])
for _, v := range ids[1:] {
values = fmt.Sprintf("%s, %d", values, v)
}
sql = fmt.Sprintf(`DELETE FROM %s WHERE id IN (%s)`, table, values)Problem: While Analysis:
Recommendation: Consider using a string builder and add validation: if len(ids) == 0 {
return 0, nil
}
// Validate table name
if table != "annotation" && table != "annotation_tag" {
return 0, fmt.Errorf("invalid table name: %s", table)
}
var sb strings.Builder
sb.WriteString("DELETE FROM ")
sb.WriteString(table)
sb.WriteString(" WHERE id IN (")
sb.WriteString(strconv.FormatInt(ids[0], 10))
for _, v := range ids[1:] {
sb.WriteString(",")
sb.WriteString(strconv.FormatInt(v, 10))
}
sb.WriteString(")")
sql = sb.String()
|
Test 7
Replicated from ai-code-review-evaluation/grafana-greptile#7