September 10

Пагинация SQL + EF

1) Обычный запрос на SQL для выборки определенного кол-ва строк (lines) на определенной странице (page)

[HttpGet("/rawSQL")]
public async Task<IActionResult> SQL()
{
    using (var context = new ApplicationContext()) 
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();

        int lines = 10;
        int page = 3;

        int skip = (page - 1) * lines;

        var res = await context.Tests.FromSqlInterpolated(
            quot;SELECT * FROM \"Tests\" WHERE \"Name\" LIKE '%A%' ORDER BY \"Id\" OFFSET {skip} ROWS FETCH NEXT {lines} ROWS ONLY"
            ).ToListAsync();


        stopwatch.Stop();
        var timeResult = stopwatch.ElapsedMilliseconds;

        var result = new
        {
            timeResult = quot;Затраченное время {timeResult}",
            res
        };

        return Ok(result);
    }
}

В итоге первый раз запрос выполняется ~500мс.

Все последующие разы ~ от 1 до 10мс

2) Запрос на EF Core с довольно тупой выборкой :)

[HttpGet("/veryStupidMethod")]
public async Task<IActionResult> Dumb()
{
    using (var context = new ApplicationContext())
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();

        int lines = 10;
        int page = 3;

        int skip = (page - 1) * lines;

        List<Test> res = await context.Tests.Where(x => x.Name.Contains("A")).ToListAsync();

        var a = res.Skip(skip);

        var b = a.Take(lines);

        stopwatch.Stop();
        var timeResult = stopwatch.ElapsedMilliseconds;

        var result = new
        {
            timeResult = quot;Затраченное время {timeResult}",
            b
        };

        return Ok(result);

    }
}

В итоге первый раз запрос выполняется ~500мс.

Все последующие разы ~ 300мс

3) Запрос с включенным Skip и Take в запрос

[HttpGet("/usingSkipAndTask")]
public async Task<IActionResult> UsingSkipAndTask()
{
    using(var context = new ApplicationContext())
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();

        IQueryable<Test> TomBombadil = context.Tests;

        int lines = 10;
        int page = 3;

        int skip = (page - 1) * lines; // Условно 3 - 1 = 2 * 10 = 20. 20 Элементов мы пропускаем
                

        List<Test> res = await TomBombadil
            .Where(x => x.Name.Contains("A"))
            .Skip(skip)
            .Take(lines)
            .ToListAsync();

        stopwatch.Stop();
        var timeResult = stopwatch.ElapsedMilliseconds;

        var result = new
        {
            timeResult = quot;Затраченное время {timeResult}",
            res
        };

        return Ok(result);
    }
}

В итоге первый раз запрос выполняется ~200мс (что странно!).

Все последующие разы ~ 1 - 10мс