You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

优化SQL Server/C#查询与自定义分页:交易数据分组技术问询

Hey there! Let's tackle your requirements step by step, covering grouped queries, SQL Server optimizations, and custom pagination in C# based on your table structure.

Grouped Query Example

First, here's a sample SQL query to group transactions by ItemID (and other relevant fields) while calculating key metrics like total sales quantity, revenue, and transaction count:

SELECT 
    ItemID,
    MAX(Title) AS ItemTitle, -- Use MAX since Title should be consistent per ItemID; adjust if needed
    SUM(QuantitySoldTransaction) AS TotalQuantitySold,
    SUM(TransactionPrice * QuantitySoldTransaction) AS TotalRevenue,
    COUNT_BIG(TransactionID) AS TotalTransactions
FROM YourTableName
-- Optional: Filter by date or other criteria to reduce data before grouping
WHERE TransactionDate >= '2023-01-01' AND TransactionDate < '2024-01-01'
GROUP BY ItemID
ORDER BY TotalRevenue DESC;

If you need to group by additional fields (like CountryName), just add them to the GROUP BY clause and adjust the SELECT accordingly.

SQL Server Query Optimization Tips

To make your grouped queries run efficiently, focus on these key areas:

  • Create Covering Indexes: Build indexes that include all fields used in filtering, grouping, and aggregation to avoid expensive table lookups. For the query above, this index would work well:
    CREATE NONCLUSTERED INDEX IX_Transactions_ItemID_Date
    ON YourTableName (ItemID, TransactionDate)
    INCLUDE (Title, QuantitySoldTransaction, TransactionPrice, TransactionID);
    
  • Filter Early: Use WHERE clauses to exclude irrelevant data before grouping—this reduces the number of rows the database needs to process during aggregation.
  • Avoid Unnecessary Data: Never use SELECT *; only fetch the fields you need. For counts, use COUNT_BIG(TransactionID) instead of COUNT(*) since TransactionID is non-null, which is slightly more efficient.
  • Analyze Execution Plans: Use SQL Server Management Studio's execution plan feature to spot bottlenecks like full table scans or key lookups. Adjust indexes or query logic based on what you see.
Custom Pagination in C#

There are two main approaches to pagination—database-side pagination (recommended for large datasets) and in-memory pagination (only for small datasets).

1. Database-Side Pagination (SQL Server 2012+)

Leverage SQL Server's OFFSET FETCH syntax to let the database handle pagination, which is far more efficient than pulling all data into memory first. Here's a C# example using Dapper (you can adapt this for Entity Framework Core too):

using System.Data.SqlClient;
using Dapper;
using System.Threading.Tasks;
using System.Collections.Generic;

public class TransactionService
{
    private readonly string _connectionString;

    public TransactionService(string connectionString)
    {
        _connectionString = connectionString;
    }

    public async Task<PagedResult<TransactionGroupDto>> GetGroupedTransactionsAsync(
        int pageNumber, 
        int pageSize, 
        DateTime? startDate = null)
    {
        // Query to get paginated grouped data
        const string dataSql = @"
            SELECT 
                ItemID,
                MAX(Title) AS ItemTitle,
                SUM(QuantitySoldTransaction) AS TotalQuantitySold,
                SUM(TransactionPrice * QuantitySoldTransaction) AS TotalRevenue,
                COUNT_BIG(TransactionID) AS TotalTransactions
            FROM YourTableName
            WHERE (@StartDate IS NULL OR TransactionDate >= @StartDate)
            GROUP BY ItemID
            ORDER BY TotalRevenue DESC
            OFFSET (@PageNumber - 1) * @PageSize ROWS
            FETCH NEXT @PageSize ROWS ONLY;
        ";

        // Query to get total number of groups for pagination metadata
        const string countSql = @"
            SELECT COUNT_BIG(DISTINCT ItemID) AS TotalGroups
            FROM YourTableName
            WHERE (@StartDate IS NULL OR TransactionDate >= @StartDate);
        ";

        using var connection = new SqlConnection(_connectionString);
        await connection.OpenAsync();

        var groupedData = (await connection.QueryAsync<TransactionGroupDto>(dataSql, new 
        { 
            PageNumber = pageNumber, 
            PageSize = pageSize, 
            StartDate = startDate 
        })).ToList();

        var totalGroups = await connection.ExecuteScalarAsync<long>(countSql, new { StartDate = startDate });
        var totalPages = (int)Math.Ceiling(totalGroups / (double)pageSize);

        return new PagedResult<TransactionGroupDto>
        {
            Data = groupedData,
            PageNumber = pageNumber,
            PageSize = pageSize,
            TotalItems = totalGroups,
            TotalPages = totalPages
        };
    }
}

// DTO for grouped transaction data
public class TransactionGroupDto
{
    public long ItemID { get; set; }
    public string ItemTitle { get; set; }
    public int TotalQuantitySold { get; set; }
    public double TotalRevenue { get; set; }
    public long TotalTransactions { get; set; }
}

// Pagination result wrapper
public class PagedResult<T>
{
    public List<T> Data { get; set; }
    public int PageNumber { get; set; }
    public int PageSize { get; set; }
    public long TotalItems { get; set; }
    public int TotalPages { get; set; }
}

2. In-Memory Pagination (Small Datasets Only)

If you already have all grouped data in memory (e.g., for small datasets), use LINQ to handle pagination:

public PagedResult<TransactionGroupDto> GetPagedGroupedData(
    List<TransactionGroupDto> allGroupedData, 
    int pageNumber, 
    int pageSize)
{
    var pagedData = allGroupedData
        .OrderByDescending(g => g.TotalRevenue)
        .Skip((pageNumber - 1) * pageSize)
        .Take(pageSize)
        .ToList();

    return new PagedResult<TransactionGroupDto>
    {
        Data = pagedData,
        PageNumber = pageNumber,
        PageSize = pageSize,
        TotalItems = allGroupedData.Count,
        TotalPages = (int)Math.Ceiling(allGroupedData.Count / (double)pageSize)
    };
}

⚠️ Important: Avoid this approach for large datasets—it will consume excessive memory and slow down your application. Always prefer database-side pagination when dealing with large amounts of data.

内容的提问来源于stack exchange,提问作者User987

火山引擎 最新活动