Skip to content

ls: push max limit down with SELECT TOP when no client-side filter#70

Merged
mkrueger merged 3 commits into
mainfrom
dev/mkrueger/ls-select-top
May 4, 2026
Merged

ls: push max limit down with SELECT TOP when no client-side filter#70
mkrueger merged 3 commits into
mainfrom
dev/mkrueger/ls-select-top

Conversation

@mkrueger
Copy link
Copy Markdown
Contributor

Fixes #66.

Background

ListCommand.ListContainerItemsAsync issued an unbounded SELECT * FROM c query and relied on:

  1. QueryRequestOptions.MaxItemCount (per-page hint, not a total cap).
  2. A manual break once the client-side accumulator reached the user's -m limit.

The server kept producing pages even though the shell only ever consumed up to effectiveMaxItemCount rows. The issue asks us to consider SELECT TOP <n> * FROM c so the cap is applied server-side.

Change

Introduced ListCommand.BuildItemQueryText(int? effectiveMaxItemCount, string? filter):

  • Returns SELECT TOP <n> * FROM c when there is a finite limit and no client-side filter that could discard rows. The shell treats both no-filter and the * wildcard as 'match everything', so both are safe to push down.
  • Returns SELECT * FROM c otherwise, because the substring filter is applied in the shell against the partition or custom key. Capping rows server-side in that case would silently drop matching items.

QueryRequestOptions.MaxItemCount is still set as the page-size hint in both paths, and the existing client-side break is unchanged.

Tests

New unit tests in CosmosDBShell.Tests/CommandTests/ListCommandTests.cs cover every branch of the helper:

  • no limit, no filter → unbounded
  • limit, no filter → SELECT TOP n
  • limit, * wildcard → SELECT TOP n
  • limit, substring filter → unbounded
  • no limit, substring filter → unbounded
  • limit, empty filter → SELECT TOP n

Existing emulator-backed integration tests (DataOperationTests, QueryCommandTests, EndToEndScriptTests) continue to exercise ls end-to-end and pass locally.

Fixes #66. Previously 'ls' inside a container always issued an unbounded 'SELECT * FROM c' and capped the result client-side via QueryRequestOptions.MaxItemCount (which is per-page, not a total cap) plus a manual loop break. When no client-side substring filter is in play (no 'filter' argument or '*' wildcard), the SDK now sends 'SELECT TOP <n> * FROM c' so the server stops scanning once the requested row count has been produced. With a substring filter we still fall back to 'SELECT * FROM c' because the match is applied in the shell against the partition or custom key and capping rows server-side could silently drop matches. Added unit tests covering the helper across all branches.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the ls container-items listing behavior to apply the effective max item limit server-side (via SELECT TOP n) when doing so is safe, reducing unnecessary paging/scan work in Cosmos DB.

Changes:

  • Introduces ListCommand.BuildItemQueryText(...) to choose between SELECT * and SELECT TOP n * based on limit/filter conditions.
  • Updates ListContainerItemsAsync to use the new query builder for item listing.
  • Adds unit tests covering all branches of the query builder logic.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/ListCommand.cs Adds query-text helper and switches item listing to use SELECT TOP n when no client-side filter applies.
CosmosDBShell.Tests/CommandTests/ListCommandTests.cs Adds unit tests validating query-text selection across limit/filter combinations.

Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/ListCommand.cs Outdated
Comment thread CosmosDBShell/Azure.Data.Cosmos.Shell.Commands/ListCommand.cs
Treat '*' as no client-side filter in ExecuteAsync, matching the TOP pushdown helper's assumptions. Preserve the limit-reached message for the server-side TOP path when the requested cap is hit even if the iterator has no continuation token. Add unit tests for filter classification and limit-message behavior.
@mkrueger mkrueger requested a review from sevoku May 4, 2026 08:18
@mkrueger mkrueger enabled auto-merge May 4, 2026 09:22
…t-top

# Conflicts:
#	CosmosDBShell.Tests/CommandTests/ListCommandTests.cs
Copilot AI review requested due to automatic review settings May 4, 2026 11:26
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@mkrueger mkrueger merged commit 9f3bdc7 into main May 4, 2026
12 checks passed
@mkrueger mkrueger deleted the dev/mkrueger/ls-select-top branch May 4, 2026 11:44
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.

Measure/Validate QueryRequestOptions.MaxItemCount vs TOP X query perf

3 participants