Удаление строк с помощью LINQ To SQL очень медленно в Windows Phone 7.1 - PullRequest
2 голосов
/ 03 ноября 2011

Существует приложение для Windows Phone 7, использующее базу данных SQL CE. Мне нужно удалить 1000-2000 строк. Нет другого выбора, кроме как использовать LINQ To SQL в Windows Phone 7 Mango - база данных SQL CE.

То, что я делаю, очень просто (псевдокод):

Entity[] tmp = null;
do
{
    tmp = datacontext.mytable.Where( ...expression here ...).Take(200).ToArray();
    if (temp.Length > 0)
    {
        mytable.DeleteAllOnSubmit(tmp);
        datacontext.SubmitChanges();
    }
} while (temp.Length > 0);

Проблема в том, что удаление 200 строк занимает 7 секунд! Все время занято внутри datacontext.SubmitChanges().

Есть ли способ сделать это быстрее?

Есть ли возможность использовать «пакетное удаление»? ('batch_insert' также приветствуется)

Несколько технических деталей:

  • DataContext был создан инструментом SqlMetal и выглядит довольно тяжело.
  • Сущность имеет 2 отношения внешнего ключа.

Ответы [ 6 ]

2 голосов
/ 03 ноября 2011

Вы пытались вызвать SubmitChanges () вне цикла?

using(var datacontext = new MyDataContext())
{
var entities = datacontext.mytable.Where( ...expression here ...);
datacontext.DeleteAllOnSubmit(entities);
datacontext.SubmitChanges();
}

Но вы упомянули инструмент для создания текста данных. Это ваша схема / граф объектов является сложным? Я не использую какой-либо инструмент для своего текста данных, потому что моя схема очень проста: никакого отношения.

1 голос
/ 20 августа 2012

Я думаю, что это распространенная проблема, если вам нужно управлять синхронизацией БД в вашем приложении.

Настоящая проблема связана с Linq To Sql и с тем, как он создает операторы DELETE.

Итак, у вас есть два решения:

  1. переопределить стандартное поведение Linq To Sql DELETE (я этого не предлагаю): http://msdn.microsoft.com/en-us/library/bb882646.aspx
  2. используйте столбец ROWVERSION в вашей таблице (более доступный в качестве решения), который помогает Linq To Sql управлять крупными пакетными обновлениями / удалениями.

Я дам вам подробности о втором решении, гораздо более простом в реализации:

Если вы добавите в свою таблицу двоичный столбец с атрибутом IsVersion, установленным в значение true, например:

[Column(IsVersion = true)]
private Binary _version;

вы значительно улучшите производительность для пакетных УДАЛЕНИЙ и ОБНОВЛЕНИЙ.

НО, БУДЬТЕ ОСТОРОЖНЫ !!! Если вы используете столбец ROWVERSION в таблице, вы должны удалить любой другой уникальный индекс, связанный с вашим первичным ключом, в противном случае ваше приложение будет аварийно завершено без каких-либо исключений !! Поверьте мне, это будет очень раздражать !!

См. Этот пример:

[Table(Name = "_customers")]
[Index(Columns = "Uid", IsUnique = true)] // <- THIS WILL GIVE YOU AN UNEXPECTED CRASH!
[Index(Columns = "Code", IsUnique = true)]
public class Customer : BaseModel, IBaseTable
{    
    [Column(IsVersion = true)]
    private Binary _version;

    [Column(IsPrimaryKey = true, IsDbGenerated = false, DbType = "UNIQUEIDENTIFIER NOT NULL", CanBeNull = false)]
    public Guid Uid {...}

    ...
}

Просто несколько самодельных статистик для моих таблиц (я знаю, что я не показываю вам схему, но поверьте мне: у меня есть все внешние ключи, которые вы можете себе представить, и это отлично работает!) ...

Клиенты -> от 34492 мс до 3230 мс (613 записей)

Продукты -> от 37233 мс до 7264 мс (416 записей)

Expiries -> от 3713 мс до 228 мс (2386 записей)

Единицы измерения продуктов -> от 66347 мс до 7321 мс (808 записей)

0 голосов
/ 04 ноября 2015

[Столбец (IsVersion = true)] private Binary _version;

Решил мою проблему;

0 голосов
/ 08 ноября 2011

Возможно, кто-нибудь найдет это полезным: Лучшие практики для выигрыша телефона

Я использовал несколько подсказок из статьи выше, а также переработанный алгоритм, который пытается изменить (переработать) записи вместо команд удаления / вставки. Это дало заметный прирост производительности, но, сравнивая одно и то же приложение на Android и WinPhone, кажется, что WP7 намного медленнее.

К сожалению, я подозреваю, что лучше использовать SqlLite для приложений с тяжелыми базами данных.

0 голосов
/ 03 ноября 2011

Возможно, проблема не на стороне клиента. Проверьте таблицу на наличие триггеров. Проверьте любые каскадно удаленные таблицы на наличие триггеров. Если они являются причиной проблемы, никакие изменения на клиенте не могут ее исправить.

LinqToSql удаляет с оптимистичным параллелизмом. Хотя SubmitChanges использует неявную транзакцию для 200 ваших элементов, каждый элемент отправляется в базу данных индивидуально со всеми первоначально прочитанными значениями для удаления.

Если вы хотите обойти оптимистичный параллелизм, самый простой путь - DataContext.ExecuteCommand. Используя это, вы можете удалить, даже не загружая эти строки на клиенте.


Редактировать: спасибо за ссылку.

На основании этого описания из msdn память телефона может быть ограничивающим фактором. Обязательно утилизируйте ваш текстовый текст после каждого вызова SubmitChanges, как советует статья.

0 голосов
/ 03 ноября 2011

По моему опыту, медленные операции SQL для небольших наборов данных, такие как это, происходили потому, что каждый запрос заключался в отдельной транзакции.Вы должны быть в состоянии обернуть все запросы в одну транзакцию или, как вы выразились, в «пакет».

Приведенная ниже ссылка будет содержать дополнительную информацию о транзакциях LINQ to SQL:

http://msdn.microsoft.com/en-us/library/bb386995.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...