Чтение из огромной таблицы базы данных - PullRequest
3 голосов
/ 25 июля 2011

Я использую LINQ для доступа к своим таблицам базы данных.Некоторые из таблиц могут иметь (сотни тысяч) записей.

Чтение из таблицы с помощью следующего выражения:

var records = db.Logs;

сделает приложение очень очень медленным.Он будет загружать все записи одновременно.

Мне нужно отфильтровать результат с более чем условием, например:

if (UserID != null)
{
    records = records.Where(r => r.User == UserID);
}

if (UserIP != null)
{
    records = records.Where(r => r.IP   == UserIP);
}

Проблема в том, что мое первое чтение из таблицы принесет мневсе записи и сделает приложение очень медленным.

Есть ли способ задать условия в операторе LINQ (если, switch), как мы привыкли делать с операторами SQL?

Этосколько лет создавалась логика:

string sql = "SELECT * FROM Log WHERE 1=1";
if (UserID != null)
{
    sql += " AND User = '" + UserID + "'";
}

if (UserIP != null)
{
    sql += " AND IP = '" + UserIP + "'";
}

sqlCmd.query(sql);

Ответы [ 8 ]

6 голосов
/ 25 июля 2011

На самом деле присвоение, подобное:

  var records = db.Logs;

, не выполняет запрос немедленно.Он только готовит структуру данных для последующего использования.Выполнение запроса происходит только тогда, когда код нуждается в данных, и любые предложения where интегрированы в запрос, не позволяя ему вернуть всю таблицу.

Совершенно возможно выполнить такие вещи:

  var records = db.Logs;

  if (filter1) records = records.Where(r => r.Field1 == condition1);
  if (filter2) records = records.Where(r => r.Field2 == condition2);

Это закончится выполнением одного запроса с (своего рода) динамическим оператором where.

Однако вы должны определить правильные индексы.

2 голосов
/ 25 июля 2011

Что такое db.Logs? Разве это не IEnumerable<T> или IQueryable<T>? Обычно в Linq2SQL запросы не выполняются, пока вы не вызовете .ToArray или .ToList, поэтому сначала вы можете построить дерево запросов.

2 голосов
/ 25 июля 2011

Я думаю, что вы не правы.Вызов db.Logs должен возвращать IQueryable - это означает, что запрос не будет выполнен, пока данные не должны быть получены.Например, точка доступа к свойству класса Log или преобразование коллекции в список .ToList ()

1 голос
/ 25 июля 2011

Лучше использовать Пейджинг, заставить ваши данные делать что угодно, а затем получить другую страницу.

1 голос
/ 25 июля 2011

Проблема в том, что мое первое чтение из таблицы принесет мне все записи и сделает приложение очень медленным.

var records = db.Logs

не читает из таблицы.Вы ничего не сделали, кроме создания запроса (это аналогично созданию текста команды SQL без отправки текста команды в базу данных для выполнения).Включите функцию, которая позволяет видеть команды SQL, отправляемые в базу данных, и вы увидите, что эта строка кода ничего не отправляет в базу данных.Фактически, эта строка также не имеет значения:

records = records.Where(r => r.User == UserID);

Это просто изменение запроса с именем records (вы должны действительно назвать его recordsQuery) для добавления условия на User.До тех пор, пока вы не выполните итерацию запроса, он фактически отправляется в базу данных для выполнения.Так что либо

records.ToList();

, либо

foreach(var record in records) {
    // something something
}

, либо множество других способов выполнения запроса.

Вот как давно создавалась логика:

Надеюсь нет.Привет, инъекционные атаки!

Некоторые таблицы могут содержать (сотни тысяч) записей.

Сотни тысяч НИЧЕГО.

0 голосов
/ 25 июля 2011

если вы используете лямбда-выражение, запрос не будет выполняться, пока вы его не используете, например, преобразовать в список или перечислить все данные.

var filtered = (from l in db.Logs
where l => l.User == UserID
select l).ToList();
0 голосов
/ 25 июля 2011

Если вы используете SQL Server, сотни тысяч строк далеко не огромны.

Если вернуться к теме, если вы передаете IQueryable<T>, тогда SQL будет выполняться каждый раз, когда онперечислены.Если ваш старый код верен, а ваш новый код медленный, это, скорее всего, ваша проблема.Таким образом, вы можете избежать вызова, вызвав ToList(), преобразовав его в IEnumerable<T> и поместив все данные в память.

Наконец, вы можете вывести данные на страницу, вызвав .Skip(PageSize * PageIndex).Take(PageSize).

0 голосов
/ 25 июля 2011

Попробуйте это:

List<Records> records;

if (UserID != null)
{
    records = db.Logs.Where(r => r.User == UserID).ToList();
}
else
{
    records = db.Logs.ToList();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...