В первой своей попытке закрыть дыру в производительности Entity Framework'а я рассматривал только материализацию. Но дальше в процессе работы, как того и следовало ожидать, я наткнулся и на другое, более весомое ограничение. Операции вставки, модификации и удаления записей происходят тоже медленно. На 100 вставок EF посылает в базу 100 запросов на вставку, никак не пытаясь их сгруппировать.
Кроме этого, в одном из проектов была обнаружена одна неприятная ошибка: EF версии 5.0.0, при работе с Oracle, в Clob/Xml поля не позволяет вставлять строки более 2000 символов.
Для решения был создан компонент, который я назвал Context Items, со следующими возможностями:
1) Bulk Insert (MS Sql): в таблицы, не имеющие Identity в качестве первичного ключа возможно осуществить вставку методом Bulk Insert, который поддерживается базой данных Ms Sql Server. В случае с Identity нет способа надежно получить назад ключи, сгенерированные базой при вставке с помощью Bulk Insert, поэтому для таблиц имеющих такие ключи используется группировка нескольких обычных Insert-запросов в один запрос. Это работает существенно медленнее, чем Bulk Insert, но все же быстрее, чем через EF.
2) Sequenced Bulk Insert (MS Sql): альтернативой Identity обычно служит Guid, это решает проблему вставки, но создает другую проблему – в силу большей длины ключа операции Join начинают работать медленнее, кроме этого Guid непоследователен, и поэтому Clustered индексы не приносят своих преимуществ. Как решение данной проблемы начиная с MS Sql Server 2012 есть возможность использовать Sequence для создания первичных ключей. Это позволяет использовать целочисленные последовательные ключи, что позволяет использовать Clustered индексы, аналогично Identity, и одновременно позволяет использовать Bulk Insert для вставки. Компонент поддерживает только ацикличные Sequence с инкрементом 1.
3) Bulk Update (MS Sql): самой по себе в базе данных такой операции не существует, компонент воплощает ее последовательно выполняя следующие 4 операции:
a) Создается временная таблица, имеющая тот же набор полей, что и целевая таблица b) Производится Bulk Insert данных во временную таблицу c) Выполняется Join-Update операция, которая переносит данные из записей временной таблицы в записи целевой таблицы, имеющие совпадающие первичные ключи. d) Временная таблица удаляется
a) Cоздается временная таблица имеющая набор полей совпадающий с первичным ключом целевой таблицы b) Производится Bulk Insert во временную таблицу первичных ключей для записей, которые надо удалить c) Выполняется Join-Delete операция d) Временная таблица удаляется
К сожалению, не доступен сервер mySQL