Как отфильтровать GET-запрос веб-приложения Blazor-Server для небольшого количества записей из таблицы в миллион строк

У меня есть веб-приложение сервера C# Blazor с Entity Framework Core + база данных SQL Server. Мне нужно несколько фильтров выборки/GET, и я хочу знать, как лучше всего их закодировать на C# и T-SQL. Таблица базы данных может содержать несколько миллионов строк. Когда мы запрашиваем отфильтрованные данные из этой таблицы, мы ожидаем, что будет возвращено не более 500 строк.

Я ищу лучший/самый быстрый способ вернуть данные на страницу браузера пользователя - либо с помощью запроса С#, подобного этому...

// Filter query for the customer.
IEnumerable<Table1> getQuery =
      from recs in _dbContext.Table1()
      where (recs.UID_CUSTOMER == pUID_CUSTOMER)
      select recs;

// Fetch the data 
return getQuery.ToList();

Или... от использования хранимых процедур в этом примере.

int customerUID = 7;
FormattableString uspCommand = $"EXEC {storedProcName} @CustomerUID = {customerUID}";

returnValue = _dbContext.Table1.FromSqlInterpolated(sqlCommand).ToList();

Какой способ лучше?

В общем, правильно параметризованный SQL-запрос (и EF Core превращает ваши запросы Linq в правильно параметризованные запросы T-SQL) и хранимая процедура при выполнении действительно одинаковы, после того как план выполнения был изначально разработан. Хранимая процедура здесь не имеет никакого «магического» преимущества в скорости, но ее обычно гораздо сложнее использовать из EF Core. Поэтому я рекомендую использовать правильные запросы Linq и убедиться, что ваши базовые таблицы базы данных правильно проиндексированы.

marc_s 28.07.2024 18:31

Второй метод, если я не ошибаюсь, открыт для инъекций. Вы не параметризуете параметры процедуры, вы их вводите.

Thom A 28.07.2024 19:03

Том... Спасибо за ответ. Я думал, что предложение «FromSqlInterpolated» решает проблему инъекции. Я видел код, в котором параметры определяются в объекте new(). Я могу найти пример и применить его к своему коду, который мы видим в этом вопросе.

John D 28.07.2024 20:29

Спасибо @marc_s за ваш ответ. Показывает ли какой-нибудь мой код в этом вопросе выполнение «параметризованного запроса T-SQL»? Я не уверен, является ли приведенный выше код запроса запросом C# или SQL-запросом. Если можете, предоставьте мне действительный запрос, о котором вы говорите. Если да, то на С#. Спасибо.

John D 28.07.2024 20:37
FromSqlInterpolated избегайте инъекций, только если вы используете FormattableString полностью. Не используйте string посередине. Еще один вариант, который вы не рассмотрели: использование хранимой процедуры с параметром @UID_CUSTOMER.
Charlieface 28.07.2024 21:24

Спасибо @Charlieface... Я полностью принимаю ваш комментарий относительно FormattableString... Я исправлю свой код. Спасибо. Кроме того, я рассмотрел хранимую процедуру, передающую UID_CUSTOMER, поскольку она ограничивает количество строк специально для этого клиента. :-) Тогда я смогу "фильтровать" из этого огромного списка, меньшего, чем несколько миллионов строк. Спасибо.

John D 28.07.2024 22:20

Есть ли конкретная причина, по которой вы используете FromSqlInterpolated вместо создания запроса IQueryable к определенному DbSet в DbContext?

MrC aka Shaun Curtis 28.07.2024 23:41
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Самый быстрый способ в EF: используйте проекцию, чтобы получить от сущностей именно то, что вам нужно.

Этот код ужасен:

IEnumerable<Table1> getQuery =
    from recs in await this.GetAllCustomers()
    where (recs.UID_CUSTOMER == pUID_CUSTOMER)
    select recs;

... когда "GetAllCustomers()" делает что-то вроде:

await _dbContext.Table1!.ToListAsync();

Вышеупомянутое загружает ВСЕ строки в память.

Лучше было бы просто:

IEnumerable<Table1> getQuery = await _dbContext.Table1
    .Where (recs.UID_CUSTOMER == pUID_CUSTOMER)
    .ToListAsync();

Это указывает EF сгенерировать SQL-запрос, чтобы вернуть только X интересующих вас строк.

Еще лучше было бы посмотреть, какие поля из Таблицы 1 вам нужны, и составить ViewModel только из этих столбцов. Например, если таблица Table1 состоит из 50 столбцов, но вам нужно только 10, и/или есть значения, которые нужно извлечь из связанных таблиц, тогда использование Select позволит EF построить эффективный SQL для извлечения только необходимых столбцов, а не для извлечения всех 50. столбцы и/или создание декартова произведения (быстрая загрузка) или сценария SELECT N+1 (ленивая загрузка)

IEnumerable<Table1ViewModel> getQuery = await _dbContext.Table1
    .Where (recs => recs.UID_CUSTOMER == pUID_CUSTOMER)
    .Select(recs => new Table1ViewModel
    {
        Id = recs.Id,
        Value1 = recs.Value1,
        // ...
    }).ToListAsync();

Отсюда вы можете проверить использование индекса и при необходимости оптимизировать его. Хорошей идеей является разработка сортировки и нумерации страниц при извлечении данных, чтобы гарантировать, что пользователи сначала получают наиболее релевантные данные и избежать мин, где «большая часть» данных должна представлять собой управляемый объем, но в некоторых крайних случаях наблюдаются большие и медленные наборы результатов. потянул.

Для операций чтения используйте проекцию. Для операций обновления извлекайте объекты, поскольку вы обычно будете читать отдельные строки по PK, что происходит очень быстро.

Другие вопросы по теме