2009-04-08 2 views
2

У меня есть проект C#, который использует компактную версию sqlserver и структуру сущности для доступа к данным. Мне нужно вставить или обновить большое количество строк, более 5000 или более, в db, поэтому, если ключ существует, обновите запись, если не вставьте ее. Я не могу найти способ сделать это с компактной версией и EF с ужасной производительностью, т. Е. Взять 2 минуты плюс на ядро ​​i7. Я попытался найти запись, чтобы увидеть, существует ли она, а затем вставлять, если нет, или обновлять, если это так, поиск - это убийца. Я попытался скомпилировать поисковый запрос и это только немного улучшилось. Еще одна вещь, которую я попытался - вставить запись в try catch, и если она не обновляется, но это заставляет меня сохранять изменения в каждой записи, чтобы получить исключение, а не в конце, которое является убийцей производительности. Очевидно, что я не могу использовать хранимые процедуры, так как это компактная версия. Кроме того, я посмотрел на просто выполнение t-sql непосредственно так или иначе на db, но отсутствие инструкций процесса в компактном, похоже, не допускает этого. Я искал мир из идей. Я действительно хотел использовать компактный, если мог, чтобы выразить за преимущества развертывания и способность помешать пользователю копаться вокруг db. Любые предложения будут оценены.Выполнение вставки ИЛИ Обновление (upsert) на SQL Server compact edition

Благодаря

+0

Спасибо за предложения. Я собираюсь потратить некоторое время на завтра, проверяя эти идеи. Сегодня я пробовал различные способы использования sql express и его молниеносно, даже не используя хранимые процедуры. Использование хранимых процедур и нового оператора слияния почти мгновенно. – RBear

ответ

2

Может быть, вы могли бы получить результат, которую вы ищете с помощью простых запросов. Скажем, таблица, которую нужно вставить в или обновление как этот

TABLE original 
    id integer, 
    value char(100) 

первым можно создать временную таблицу с новые значения (вы можете использовать SELECT INTO или другие способы его создания)

TABLE temp 
    id integer, 
    value char(100) 

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

UPDATE original 
SET original.value = temp.value 
FROM original, temp 
WHERE original.id = temp.id 

INSERT INTO original 
SELECT * from temp 
WHERE temp.id not IN (select o.id from original o) 
+0

Спасибо, что это дает хорошее улучшение, но все же ниже производительности, в которой я нуждаюсь. Это сводит к минимуму мои потребности в данных для Compact Edition. – RBear

2

Учитывая вашу проблему заявление, я собираюсь предположить, что это программное обеспечение предполагает относительно мускулистый среду. Считаете ли вы, что нужно выполнить задачу определения sqlce и сделать это самостоятельно? По существу, возьмите отсортированный список всех идентификаторов (ключей?) Из соответствующей таблицы и проверив каждый ключ объекта против этого списка перед его очередью для вставки?

Это делает несколько предположений, которые были бы плохими новостями с типичной БД, но что вы, вероятно, можете обойтись в sqlce. Например, он предполагает, что строки не будут вставлены или значительно изменены другим пользователем во время выполнения этой вставки.

Если список ключей слишком длинный для разумного хранения в памяти для такой проверки, я боюсь, что я скажу, что SQLIll просто не может быть правильным инструментом для работы. :(

2

Я не уверен, что это возможно или нет, поскольку я не использовал Entity Framework, но вы сначала попробовали запустить обновление и проверили rowcount - вставив, если строки не были обновлены? Это может быть быстрее, чем устранение исключений. Как правило, плохая практика заключается в использовании исключений для потока управления и часто замедляет работу.

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

INSERT INTO original 
SELECT * FROM temp 
LEFT JOIN original ON original.id = temp.id 
WHERE original.id IS NULL 
2

Я бы рекомендовал использовать SqlCeResultSet напрямую ,Вы теряете приятную типу безопасности EF, но производительность невероятно быстро. Мы переключились с ADD.NET 2.0 типа TypeDataSets на SqlCeResultSet и SqlCeDataReader и видели в 20-50 раз увеличение скорости.

0

SQL Server compact edition довольно рано развивается на этом этапе. Кроме того, в зависимости от вашего устройства доступ к диску с памятью может быть довольно медленным, а накладные расходы на безопасность типа SQLCE plus .NET довольно интенсивны. Он работает лучше всего с довольно статическим хранилищем данных.

Предлагаю вам использовать API с более легким весом или рассмотреть SQLite.

1

См. SqlCeResultSet. Для проекта .NETCF я удалил почти весь код sql в пользу этого класса. Просто найдите «SqlCeResultSet» здесь и msdn.

Краткий обзор:

  1. Открыть Resultset. Если вам нужен поиск (для проверки существования), вам нужно будет указать индекс для набора результатов.

  2. Ищите в результирующем наборе &, чтобы убедиться, что вы нашли строку. Это очень быстро даже на таблицах с десятками тысяч строк (потому что поиск использует индекс).

  3. Вставьте или обновите запись (см. SqlCeResultSet.NewRecord).


Мы успешно разработали проект с базой данных SQLCE с основной таблицей продуктов с более чем 65000 строк (чтение/запись с 4-мя индексами).

6

Когда мы используем SQL CE (и SQL Express Express), мы всегда вызываем обновление сначала, а затем вызываем вставку, если udate дает количество строк в 0. Это очень просто реализовать и не делает требуют затратных пакетов try..catch для потока управления.

+0

Как вы выполняете 'INSERT' * if *, значение строки равно 0, когда CE не поддерживает' IF'? –

+1

@Sahuagin - Мы называем SQL UPDATE отдельно и используем результат 'ExecuteNonQuery' в .NET, чтобы решить, нужно ли нам называть' INSERT'. – stevehipwell

Смежные вопросы