-2
\$\begingroup\$

I'm in need to optimize the following TRANSACT SQL statement :

SELECT Id, Type, StartTime, Amount, CurrencyCode, CorrelationStatus, ProviderId
FROM (
        SELECT UserId, Id, {=charge} Type, StartTime, Amount, CurrencyCode, CorrelationStatus, ProviderId
        FROM charge
        WHERE (@Type IS NULL OR @Type = {=charge})

        UNION ALL

        SELECT UserId, Id, {=recharge} Type, StartTime, Amount, CurrencyCode, CorrelationStatus, ProviderId
        FROM recharges
        WHERE (@Type IS NULL OR @Type = {=recharge})
     ) AS T
    WHERE UserId = @UserId
    AND StartTime BETWEEN @StartDate AND @EndDate
    AND (@ProviderId IS NULL OR ProviderId = @ProviderId)
    AND (@FilterCorrelationStatus = 0 OR CorrelationStatus IN @CorrelationStatuses)

    ORDER BY StartTime DESC
    OFFSET (@PageIndex - 1) * @PageSize ROWS
    FETCH NEXT @PageSize ROWS ONLY;

Can you give me some suggestions? Thanks, Simone

\$\endgroup\$
5
  • \$\begingroup\$ I gonna take a guess at your use case. - your trying to update lots (000s) of records as a "fix" or migration and this is one-off task. \$\endgroup\$
    – dunxz
    Commented Dec 14, 2022 at 10:42
  • \$\begingroup\$ @dunxz In the application I'm refacoring this query is used to show transaction list. \$\endgroup\$ Commented Dec 14, 2022 at 10:46
  • 1
    \$\begingroup\$ To help reviewers give you better answers, we need to know what the code is intended to achieve. Please add sufficient context to your question to describe the purpose of the code. We want to know why much more than how. The more you tell us about what your code is for, the easier it will be for reviewers to help you. Also, edit the title to simply summarise the task, rather than your concerns about the code. \$\endgroup\$ Commented Dec 14, 2022 at 12:04
  • 2
    \$\begingroup\$ You haven't shown the definition of your tables and indexes, without which it's hard to give a good review. I recommend you include these definitions (preferably as SQL statements, so that reviewers can reproduce your test environment). \$\endgroup\$ Commented Dec 14, 2022 at 12:04
  • \$\begingroup\$ @TobySpeight I solved my issue with the refactor below. Thanks. \$\endgroup\$ Commented Dec 15, 2022 at 15:49

1 Answer 1

0
\$\begingroup\$

As this is a application SQL (executed by stored proc?) returning DBSet (or similar) your choices are limited. I'd start by looking at the execution plans - look out for "Scans" - this would indicate a missing index.

use SET STATISTICS IO ON to see how many reads are being undertaken.

I would also look for the order of execution, you might be better off including the filter criteria in each of the unions, rather than having an outer

At a guess, though each of the UNION clauses is returning a large set of data, before then applying the filter.

Try something like this:

SELECT Id, Type, StartTime, Amount, CurrencyCode, CorrelationStatus, ProviderId 
FROM (
    SELECT UserId, Id, {=charge} Type, StartTime, Amount, CurrencyCode, CorrelationStatus, ProviderId
    FROM charge
    WHERE
        UserId = @UserId
        AND StartTime BETWEEN @StartDate AND @EndDate
        AND (@ProviderId IS NULL OR ProviderId = @ProviderId)
        AND (@FilterCorrelationStatus = 0 OR CorrelationStatus IN @CorrelationStatuses) 
        AND (@Type IS NULL OR @Type = {=charge})

    UNION ALL

    SELECT UserId, Id, {=recharge} Type, StartTime, Amount, CurrencyCode, CorrelationStatus, ProviderId
    FROM recharges
    WHERE
        UserId = @UserId
        AND StartTime BETWEEN @StartDate AND @EndDate
        AND (@ProviderId IS NULL OR ProviderId = @ProviderId)
        AND (@FilterCorrelationStatus = 0 OR CorrelationStatus IN @CorrelationStatuses)
        AND (@Type IS NULL OR @Type = {=recharge})
 ) AS T

ORDER BY StartTime DESC
OFFSET (@PageIndex - 1) * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;

An alternate approach (last resort?!) is to create a schema bound indexed view. In other words create a schema bound view of CREATE VIEW xxx WITH SCHEMABINDING AS SELECT fields FROM charge UNION ALL SELECT fields recharges. You can then add indexes to the view.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Welcome to Code Review! Please refrain from answering low-quality questions that are likely to get closed. Once you've answered, that limits what can be done to improve the question, making it more likely that your efforts are wasted. It's better to wait until the question is properly ready before you answer! \$\endgroup\$ Commented Dec 14, 2022 at 12:05
  • \$\begingroup\$ Could OPTION(RECOMPILE) improve performance at the end of the SQL statement? Thank you. \$\endgroup\$ Commented Dec 16, 2022 at 20:32
  • \$\begingroup\$ OPTION(RECOMPILE) is valid. This will force the creation of a new execution plan on every execution of the query. Execution plans are relatively expensive, so are best avoided, however this is an option where the type of data is volatile. see also UPDATE STATISTICS \$\endgroup\$
    – dunxz
    Commented Mar 13, 2023 at 13:51

Not the answer you're looking for? Browse other questions tagged or ask your own question.