ChilliCream / ChilliCream/graphql-platform
Improve TotalCount's autogenerated Count(*) query performance avoiding redundant joins.
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 5.8k
- Forks
- 810
- Avg merge
- 15h 39m
- Merged PRs (30d)
- 98
Description
Product
Hot Chocolate
Is your feature request related to a problem?
Hello team, keep up the good work.
I've recently discovered this scenario that is having a big impact into several high importance queries in our application ( up to 4-5 seconds total impact for a costly but frequent sorted listing query :( ) :
-
Selecting TotalCount in a Paginated query automatically creates a Count(*) query for the base query, applying any FIltering as expected 🟢
-
HOWEVER, if the paginated query included Sorting and the Sorting parameters required joining other tables, e.g CostlySortingTableA, the Count(*) generated query keeps joins to these redundant tables. 🔴
Sample:
- Selecting Col1 and Col2 and ordering by a costly expression requiring other table.
-Pseudo query sample
- Pagination query 🟢
SELECT t.Col1,t.Col2
FROM Table1 t
INNER JOIN CostlySortingTableA csta
ORDER BY SUM( csta.ColX ).
- Count query 🔴
SELECT count(*)
FROM Table1 t
INNER JOIN CostlySortingTableA csta
Real example:
- Sorting introduces this very costly join to
vw_ReportedDealMetrics_Unifiedview in the HC autogenerated Count(*) query:
Execution time: 4,440ms
- Compared with the autogenerated Count(*) query where we're not sorting by a parameter that depends on
vw_ReportedDealMetrics_Unifiedview
Execution time: 332ms - 13X+ faster.
The solution you'd like
Count query should prune/avoid the redundant joins that are needed only for sorting.
In the example above
- Expected Count query
SELECT count(*)
FROM Table1 t
INNER JOIN CostlySortingTableA csta
Thoughts:
- I can see the complication with the current Pagination API, i.e
public static ValueTask<Connection> ApplyCursorPaginationAsync(
this IQueryable query,
IResolverContext context,
int? defaultPageSize = null)
where the full composed IQueryable query including Sorting is passed, making it complicated & slow to prune redundant joins.
I guess that something along the lines of:
- Adding an specific method overload to request sorting to be added but not compose it into the IQueryable input
- This allows this method to use the original - non Sorted IQueryable in the Count(*) query while composing the Sorting into the core pagination query.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with ApplyCursorPaginationAsync and trace how the composed IQueryable produces both the paginated query and the autogenerated Count(*) query. Done means sorting remains in the pagination query while sorting-only joins are omitted from the count query; the issue does not name a test or implementation file to run first.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100