镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Optimized GetHostScriptExecutionResults MySQL query for for large numbers of script results. - #32595

Merged
getvictor merged 5 commits into
mainfrom
victor/32295-optimize-list-script-results
Sep 4, 2025
Merged

getvictor merged 5 commits into
mainfrom
victor/32295-optimize-list-script-results

Conversation

@getvictor

@getvictor getvictor commented Sep 4, 2025 •

Copy link
Copy Markdown
Member

Fixes #32295

The issue was identified/fixed using this performance test: https://github.com/proxy/gist.github.com/getvictor/b289b7b14981fb7bf77e57c80af117d1

With the fix:

  • 100 records: 2.6ms (similar)
  • 1,000 records: ~7ms (32x faster)
  • 5,000 records: ~10ms (530x faster)
  • 10,000 records: 13ms (1,430x faster)
  • 20,000 records: ~25ms (2,960x faster)
  • 40,000 records: 50ms (6,000x faster)

Checklist for submitter

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.
    See Changes files for more information.

Testing

  • QA'd all new/changed functionality manually

Summary by CodeRabbit

  • New Features
    • Script details now surface the most relevant “latest” status per script, prioritizing upcoming executions when present.
  • Performance Improvements
    • Significantly faster loading of host script results and script details, especially at large scale.
    • Improved responsiveness when filtering/sorting script results.
  • Documentation
    • Added changelog entry describing the optimization to script results handling.

@codecov

codecov Bot commented Sep 4, 2025 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.81633% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.01%. Comparing base (d7fa824) to head (be08cf8).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
...s/20250904115553_OptimizeHostScriptResultsIndex.go 67.85% 7 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #32595      +/-   ##
==========================================
- Coverage   64.01%   64.01%   -0.01%     
==========================================
  Files        2000     2001       +1     
  Lines      198159   198188      +29     
  Branches     6462     6462              
==========================================
+ Hits       126859   126877      +18     
- Misses      61310    61320      +10     
- Partials     9990     9991       +1     
Flag Coverage Δ
backend 65.21% <90.81%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…readability and efficiency by using window functions and simplifying logic.
@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Sep 4, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai

coderabbitai Bot commented Sep 4, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a migration and schema changes to replace an index on host_script_results and updates the SQL in GetHostScriptDetails to compute the latest per-script activity using CTEs and window functions. A changelog entry documents the optimization.

Changes

Cohort / File(s) Summary
Changelog
changes/32296-optimize-list-script-results
Adds changelog entry noting optimization of GetHostScriptExecutionResults for large volumes.
Migration: Optimize index
server/datastore/mysql/migrations/tables/20250904115553_OptimizeHostScriptResultsIndex.go
New migration: Up creates composite index (host_id, script_id, canceled, created_at DESC) and drops old idx_host_script_created_at; Down is no-op; registers migration.
Schema updates
server/datastore/mysql/schema.sql
Replaces index on host_script_results with idx_host_script_canceled_created_at; updates migration_status_tables AUTO_INCREMENT and inserts new migration record.
Datastore query changes
server/datastore/mysql/scripts.go
Rewrites GetHostScriptDetails SQL: uses CTEs and ROW_NUMBER to unify latest completed and upcoming activities; selects a single latest per script; updates parameter bindings and joins.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as Client/UI
  participant API as Server API
  participant DS as Datastore (scripts.go)
  participant DB as MySQL

  UI->>API: GET /hosts/{id}/scripts
  API->>DS: GetHostScriptDetails(hostID, team/global scope)
  DS->>DB: SQL with CTEs + window functions<br/>uses idx_host_script_canceled_created_at
  DB-->>DS: Latest per-script rows (upcoming or completed)
  DS-->>API: Script list with latest activity fields
  API-->>UI: 200 OK response
  note over DB,DS: New composite index (host_id, script_id, canceled, created_at DESC)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Assessment against linked issues

Objective Addressed Explanation
Optimize database indexing to improve queries on hosts with many host_script_results (#32295) ✅
Refactor list scripts query to avoid timeouts on high-volume hosts (#32295) ✅
Ensure list scripts endpoint no longer times out for affected hosts (#32295) ❓ Requires runtime validation/perf testing; not verifiable from code alone.

Suggested reviewers

  • lucasmrod
  • dantecatalfamo
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch victor/32295-optimize-list-script-results

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
server/datastore/mysql/migrations/tables/20250904115553_OptimizeHostScriptResultsIndex.go (1)

30-35: Create-before-drop is the right order; consider large-table lock impact (optional).

If you expect very large host_script_results tables, using ALTER TABLE ... ADD INDEX with ALGORITHM/LOCK options can further reduce lock time in some MySQL setups. Not blocking.

server/datastore/mysql/scripts.go (4)

973-1022: CTE/window approach is sound; consider naming columns explicitly.

SELECT * in both ranked subqueries can increase materialization work. Listing explicit columns keeps the shape tight and resilient to future additions. Optional.

Apply this diff skeleton (adjust types as needed):

-    SELECT
-        id,
-        host_id,
-        script_id,
-        execution_id,
-        created_at,
-        exit_code,
-        'completed' as source,
+    SELECT
+        id,
+        host_id,
+        script_id,
+        execution_id,
+        created_at,
+        exit_code,
+        'completed' AS source,
...
-    SELECT
-        NULL as id,
-        ua.host_id,
-        sua.script_id,
-        ua.execution_id,
-        ua.created_at,
-        NULL as exit_code,
-        'upcoming' as source,
+    SELECT
+        NULL AS id,
+        ua.host_id,
+        sua.script_id,
+        ua.execution_id,
+        ua.created_at,
+        NULL AS exit_code,
+        'upcoming' AS source,

1033-1047: Semantics: “prefer upcoming over completed” even if older — confirm intent.

The CASE puts upcoming ahead of completed regardless of timestamps. If the goal is “show the most recent activity overall,” consider preferring upcoming only when it’s newer.

Alternative ORDER if you want “newest overall, but upcoming wins only on tie”:

-ORDER BY 
-  CASE WHEN source = 'upcoming' THEN 1 ELSE 2 END,
-  created_at DESC,
-  id DESC
+ORDER BY 
+  created_at DESC,
+  id DESC,
+  CASE WHEN source = 'upcoming' THEN 1 ELSE 2 END

1048-1052: Redundant host filter; simplify (optional).

latest already contains rows filtered by host_id in the CTE. The WHERE (latest.host_id IS NULL OR latest.host_id = ?) is unnecessary and can be dropped to simplify args.

Apply this diff:

-WHERE
-  (latest.host_id IS NULL OR latest.host_id = ?)
-  AND s.global_or_team_id = ?
+WHERE
+  s.global_or_team_id = ?

And update args accordingly (see next comment).


---

`1054-1060`: **Adjust args if previous simplification is applied.**

If you drop the extra host filter, remove one hostID from args.

Apply this diff:

```diff
-args := []any{hostID, hostID, hostID, globalOrTeamID}
+args := []any{hostID, hostID, globalOrTeamID}
 ...
-if len(extension) > 0 {
-  args = append(args, extension)
+if len(extension) > 0 {
+  args = append(args, extension)

(No functional change apart from arg count.)


</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used**: Path: .coderabbit.yaml

**Review profile**: CHILL

**Plan**: Pro

**💡 Knowledge Base configuration:**

- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between d7fa824e97f377abaae0d1f21bd9a0af847bf31b and 471b0fdfbc874e067867df4b74b49d5c68074133.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `changes/32296-optimize-list-script-results` (1 hunks)
* `server/datastore/mysql/migrations/tables/20250904115553_OptimizeHostScriptResultsIndex.go` (1 hunks)
* `server/datastore/mysql/schema.sql` (2 hunks)
* `server/datastore/mysql/scripts.go` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (1)</summary>

<details>
<summary>**/*.go</summary>


**⚙️ CodeRabbit configuration file**

> When reviewing SQL queries that are added or modified, ensure that appropriate filtering criteria are applied—especially when a query is intended to return data for a specific entity (e.g., a single host). Check for missing WHERE clauses or incorrect filtering that could lead to incorrect or non-deterministic results (e.g., returning the first row instead of the correct one). Flag any queries that may return unintended results due to lack of precise scoping.

Files:
- `server/datastore/mysql/migrations/tables/20250904115553_OptimizeHostScriptResultsIndex.go`
- `server/datastore/mysql/scripts.go`

</details>

</details><details>
<summary>🧠 Learnings (2)</summary>

<details>
<summary>📚 Learning: 2025-07-08T16:13:39.114Z</summary>

Learnt from: getvictor
PR: #30589
File: server/datastore/mysql/migrations/tables/20250707095725_HostIdentitySCEPCertificates.go:53-55
Timestamp: 2025-07-08T16:13:39.114Z
Learning: In the Fleet codebase, Down migration functions are intentionally left empty/no-op. The team does not implement rollback functionality for database migrations, so empty Down_* functions in migration files are correct and should not be flagged as issues.


**Applied to files:**
- `server/datastore/mysql/migrations/tables/20250904115553_OptimizeHostScriptResultsIndex.go`

</details>
<details>
<summary>📚 Learning: 2025-08-01T15:08:16.858Z</summary>

Learnt from: sgress454
PR: #31508
File: server/datastore/mysql/schema.sql:102-116
Timestamp: 2025-08-01T15:08:16.858Z
Learning: The schema.sql file in server/datastore/mysql/ is auto-generated from migrations for use with tests, so it cannot be manually edited. Any changes must be made through migrations.


**Applied to files:**
- `server/datastore/mysql/schema.sql`

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>server/datastore/mysql/migrations/tables/20250904115553_OptimizeHostScriptResultsIndex.go (2)</summary><blockquote>

`22-27`: **Good composite index; matches query access pattern.**

(host_id, script_id, canceled, created_at DESC) aligns with the new “latest-per-script-per-host” scans and canceled=0 filtering.

---

`40-43`: **No-op Down is consistent with Fleet’s migration policy.**

Matches the team’s standard (no rollbacks).

</blockquote></details>
<details>
<summary>server/datastore/mysql/schema.sql (3)</summary><blockquote>

`830-830`: **Index matches migration and ordering.**

New idx_host_script_canceled_created_at is present with DESC on created_at; consistent with the migration.

---

`1498-1498`: **AUTO_INCREMENT bump looks correct.**

AUTO_INCREMENT=419 matches the added migration row.

---

`1500-1501`: **New migration row recorded.**

Entry for version 20250904115553 is present; schema.sql stays in sync with migrations.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@getvictor
getvictor marked this pull request as ready for review September 4, 2025 17:49
@getvictor
getvictor requested a review from a team as a code owner September 4, 2025 17:49

@dantecatalfamo dantecatalfamo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool use of window function

@getvictor
getvictor merged commit 73b629e into main Sep 4, 2025
@getvictor
getvictor deleted the victor/32295-optimize-list-script-results branch September 4, 2025 20:48
getvictor added a commit that referenced this pull request Sep 22, 2025
…bers of script results. (#32595)

Fixes #32295

The issue was identified/fixed using this performance test:
https://github.com/proxy/gist.github.com/getvictor/b289b7b14981fb7bf77e57c80af117d1

With the fix:
  - 100 records: 2.6ms (similar)
  - 1,000 records: ~7ms (32x faster)
  - 5,000 records: ~10ms (530x faster)
  - 10,000 records: 13ms (1,430x faster)
  - 20,000 records: ~25ms (2,960x faster)
  - 40,000 records: 50ms (6,000x faster)

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- New Features
- Script details now surface the most relevant “latest” status per
script, prioritizing upcoming executions when present.
- Performance Improvements
- Significantly faster loading of host script results and script
details, especially at large scale.
  - Improved responsiveness when filtering/sorting script results.
- Documentation
- Added changelog entry describing the optimization to script results
handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

(cherry picked from commit 73b629e)
getvictor added a commit that referenced this pull request Sep 22, 2025
…bers of script results. (#32595) (#33305)

<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves
#32295

Cherry pick + schema update

This branch was previously deployed

1 inactive deployment
Docker Hub — be08cf8c Deployed Sep 4, 2025 by getvictor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

List script timeout on specific hosts due to large number of script results

2 participants