Najszybszy sposób wstawiania w encji Framework
Szukam najszybszego sposobu wstawienia do encji frameworku.
Pytam o to ze względu na scenariusz, w którym masz aktywny TransactionScope i wstawianie jest ogromne(4000+). Potencjalnie może trwać dłużej niż 10 minut (domyślny limit czasu transakcji), co doprowadzi do niekompletnej transakcji.
25 answers
Do twojej uwagi w komentarzach do twojego pytania:
To najgorsza rzecz, jaką możesz zrobić! Wywołanie"...SavingChanges (dla każdego zapis )..."
SaveChanges()
dla każdego rekordu bardzo spowalnia wkładki masowe. Zrobiłbym kilka prostych testów, które prawdopodobnie poprawią wydajność:
- zadzwoń
SaveChanges()
raz po wszystkich rekordach. - wywołanie
SaveChanges()
PO na przykład 100 rekordach. - wywołaj
SaveChanges()
po np. 100 rekordach i usuwaj kontekst i stworzyć nowy. - Wyłącz wykrywanie zmian
Do wkładek luzem pracuję i eksperymentuję z takim wzorem:
using (TransactionScope scope = new TransactionScope())
{
MyDbContext context = null;
try
{
context = new MyDbContext();
context.Configuration.AutoDetectChangesEnabled = false;
int count = 0;
foreach (var entityToInsert in someCollectionOfEntitiesToInsert)
{
++count;
context = AddToContext(context, entityToInsert, count, 100, true);
}
context.SaveChanges();
}
finally
{
if (context != null)
context.Dispose();
}
scope.Complete();
}
private MyDbContext AddToContext(MyDbContext context,
Entity entity, int count, int commitCount, bool recreateContext)
{
context.Set<Entity>().Add(entity);
if (count % commitCount == 0)
{
context.SaveChanges();
if (recreateContext)
{
context.Dispose();
context = new MyDbContext();
context.Configuration.AutoDetectChangesEnabled = false;
}
}
return context;
}
Mam program testowy, który wstawia 560.000 encji (9 Właściwości skalarnych, brak właściwości nawigacji) do DB. Z tym kodem działa w mniej niż 3 minuty.
Dla wykonania ważne jest wywołanie SaveChanges()
po" wielu " rekordach ("wiele" około 100 lub 1000). Poprawia również wydajność usuwania kontekst po SaveChanges i utworzyć nowy. To usuwa kontekst ze wszystkich entites, SaveChanges
tego nie robi, encje są nadal dołączone do kontekstu w stanie Unchanged
. To rosnący rozmiar dołączonych podmiotów w kontekście spowalnia wstawianie krok po kroku. Tak więc pomocne jest wyczyszczenie go po pewnym czasie.
Oto kilka pomiarów dla moich 560.000 Bytów:
- commitCount = 1, recreateContext = false: many hours (to Twój current procedure)
- commitCount = 100, recreateContext = false: więcej niż 20 minut
- commitCount = 1000, recreateContext = false: 242 sec
- commitCount = 10000, recreateContext = false: 202 sec
- commitCount = 100000, recreateContext = false: 199 sec
- commitCount = 1000000, recreateContext = false: Out of memory exception
- commit = 1, recreateContext = true: więcej niż 10 minut
- commitCount = 10, recreateContext = true: 241 sec
- commitCount = 100, recreateContext = true: 164 sec
- commitCount = 1000, recreateContext = true: 191 sec
Zachowanie w pierwszym powyższym teście polega na tym, że wydajność jest bardzo nieliniowa i bardzo maleje w czasie. ("Wiele godzin" jest oszacowaniem, nigdy nie skończyłem tego testu, I zatrzymał się na 50.000 jednostek po 20 minutach.) To nieliniowe zachowanie nie jest tak istotne we wszystkich innych testach.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-09 20:39:36
Ta kombinacja wystarczająco zwiększa prędkość.
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-12 15:52:04
Najszybszym sposobem byłoby użycie rozszerzenia bulk insert , które opracowałem.
Używa SqlBulkCopy i custom datareader, aby uzyskać maksymalną wydajność. W rezultacie jest to ponad 20 razy szybsze niż użycie zwykłego insert lub AddRange
Użycie jest niezwykle proste
context.BulkInsert(hugeAmountOfEntities);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-09 07:17:54
Powinieneś spojrzeć na użycie System.Data.SqlClient.SqlBulkCopy
do tego. Oto Dokumentacja , i oczywiście istnieje wiele samouczków online.
Przepraszam, wiem, że szukałeś prostej odpowiedzi, aby zmusić EF do zrobienia tego, co chcesz, ale operacje masowe nie są tak naprawdę tym, do czego są przeznaczone ORM.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-09 17:17:37
Zgadzam się z Adamem Rackisem. SqlBulkCopy
jest najszybszym sposobem przesyłania masowych rekordów z jednego źródła danych do drugiego. Użyłem tego do skopiowania 20K rekordów i zajęło to mniej niż 3 sekundy. Spójrz na poniższy przykład.
public static void InsertIntoMembers(DataTable dataTable)
{
using (var connection = new SqlConnection(@"data source=;persist security info=True;user id=;password=;initial catalog=;MultipleActiveResultSets=True;App=EntityFramework"))
{
SqlTransaction transaction = null;
connection.Open();
try
{
transaction = connection.BeginTransaction();
using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction))
{
sqlBulkCopy.DestinationTableName = "Members";
sqlBulkCopy.ColumnMappings.Add("Firstname", "Firstname");
sqlBulkCopy.ColumnMappings.Add("Lastname", "Lastname");
sqlBulkCopy.ColumnMappings.Add("DOB", "DOB");
sqlBulkCopy.ColumnMappings.Add("Gender", "Gender");
sqlBulkCopy.ColumnMappings.Add("Email", "Email");
sqlBulkCopy.ColumnMappings.Add("Address1", "Address1");
sqlBulkCopy.ColumnMappings.Add("Address2", "Address2");
sqlBulkCopy.ColumnMappings.Add("Address3", "Address3");
sqlBulkCopy.ColumnMappings.Add("Address4", "Address4");
sqlBulkCopy.ColumnMappings.Add("Postcode", "Postcode");
sqlBulkCopy.ColumnMappings.Add("MobileNumber", "MobileNumber");
sqlBulkCopy.ColumnMappings.Add("TelephoneNumber", "TelephoneNumber");
sqlBulkCopy.ColumnMappings.Add("Deleted", "Deleted");
sqlBulkCopy.WriteToServer(dataTable);
}
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-15 10:56:44
Zbadałem odpowiedź Slauma (co jest niesamowite, dzięki za pomysł man), i zmniejszyłem rozmiar partii, aż osiągnę optymalną prędkość. Patrząc na wyniki Slauma:
- commitCount = 1, recreateContext = true: więcej niż 10 minut
- commitCount = 10, recreateContext = true: 241 sec
- commitCount = 100, recreateContext = true: 164 sec
- commitCount = 1000, recreateContext = true: 191 sec
Widać, że istnieje prędkość zwiększ przy przenoszeniu z 1 do 10 i z 10 do 100, ale z 100 do 1000 prędkość wprowadzania spada ponownie.
Więc skupiłem się na tym, co się dzieje, gdy zmniejszasz rozmiar partii do wartości gdzieś pomiędzy 10 a 100, a oto moje wyniki (używam innej zawartości wiersza, więc moje czasy mają inną wartość):
Quantity | Batch size | Interval
1000 1 3
10000 1 34
100000 1 368
1000 5 1
10000 5 12
100000 5 133
1000 10 1
10000 10 11
100000 10 101
1000 20 1
10000 20 9
100000 20 92
1000 27 0
10000 27 9
100000 27 92
1000 30 0
10000 30 9
100000 30 92
1000 35 1
10000 35 9
100000 35 94
1000 50 1
10000 50 10
100000 50 106
1000 100 1
10000 100 14
100000 100 141
Na podstawie moich wyników, rzeczywiste optimum jest około wartości 30 dla wielkości partii. Jest mniej niż 10 i 100. Problem w tym, że nie mam pojęcia dlaczego 30 jest optymalne, nie mogłem znaleźć na to żadnego logicznego wyjaśnienia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-26 08:46:42
Polecam ten artykuł o tym, jak zrobić wkładki luzem za pomocą EF.
Entity Framework i slow bulk INSERTs
Bada te obszary i porównuje perfomance:
- Default EF (57 minut do zakończenia dodawania 30 000 rekordów)
- zastępowanie przez ADO.NET kod (25 sekund dla tych samych 30 000)
- context Bloat-utrzymuj aktywny Wykres kontekstowy na małym poziomie, używając nowego kontekstu dla każdej jednostki pracy (te same 30 000 wstawek zajmuje 33 sekund)
- Duże listy-Wyłącz AutoDetectChangesEnabled (zmniejsza czas do około 20 sekund)
- dozowanie (do 16 sekund)
- DbTable.AddRange () - (wydajność jest w zakresie 12)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-20 03:10:55
Jak mówią inni ludzie, SqlBulkCopy jest sposobem na to, jeśli chcesz naprawdę dobrą wydajność wstawiania.
Jest to trochę kłopotliwe w implementacji, ale istnieją biblioteki, które mogą ci w tym pomóc. Jest ich kilka, ale tym razem będę miał własną bibliotekę: https://github.com/MikaelEliasson/EntityFramework.Utilities#batch-insert-entitiesPotrzebny jest tylko kod:
using (var db = new YourDbContext())
{
EFBatchOperation.For(db, db.BlogPosts).InsertAll(list);
}
O ile szybciej? Bardzo trudno powiedzieć, bo to zależy od tak wielu czynników, wydajności komputera, sieci, wielkości obiektu itp itp. Testy wydajności, które zrobiłem, sugerują, że 25k podmiotów można wstawić w okolicach 10s standardowym sposobem na localhost, jeśli zoptymalizujesz konfigurację EF, jak wspomniano w innych odpowiedziach. Z EFUtilities, który trwa około 300ms. jeszcze bardziej interesujące jest to, że zapisałem około 3 miliony jednostek w ciągu 15 sekund za pomocą tej metody, średnio około 200k jednostek na sekundę.
The one problem jest oczywiście, jeśli musisz wstawić releated data. Można to zrobić skutecznie w sql server za pomocą powyższej metody, ale wymaga to posiadania strategii generowania Id, która pozwala generować id w kodzie aplikacji dla rodzica, dzięki czemu można ustawić klucze obce. Można to zrobić za pomocą GUID lub czegoś w rodzaju Hilo id generation.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-19 10:44:11
Dispose()
context tworzenie problemów, jeśli encje Add()
opierają się na innych fabrycznie załadowanych encjach (np. właściwości nawigacji) w kontekście
Używam podobnej koncepcji, aby mój kontekst był mały, aby osiągnąć tę samą wydajność
Ale zamiast Dispose()
kontekstu i odtworzenia, po prostu odłączam byty, które już SaveChanges()
public void AddAndSave<TEntity>(List<TEntity> entities) where TEntity : class {
const int CommitCount = 1000; //set your own best performance number here
int currentCount = 0;
while (currentCount < entities.Count())
{
//make sure it don't commit more than the entities you have
int commitCount = CommitCount;
if ((entities.Count - currentCount) < commitCount)
commitCount = entities.Count - currentCount;
//e.g. Add entities [ i = 0 to 999, 1000 to 1999, ... , n to n+999... ] to conext
for (int i = currentCount; i < (currentCount + commitCount); i++)
_context.Entry(entities[i]).State = System.Data.EntityState.Added;
//same as calling _context.Set<TEntity>().Add(entities[i]);
//commit entities[n to n+999] to database
_context.SaveChanges();
//detach all entities in the context that committed to database
//so it won't overload the context
for (int i = currentCount; i < (currentCount + commitCount); i++)
_context.Entry(entities[i]).State = System.Data.EntityState.Detached;
currentCount += commitCount;
} }
Owiń go try catch i TrasactionScope()
jeśli potrzebujesz,
nie pokazując ich tutaj za utrzymanie czystego kodu
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-24 13:06:42
Spróbuj użyć procedury składowanej, która otrzyma XML danych, które chcesz wstawić.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-09 17:18:23
Zrobiłem ogólne rozszerzenie przykładu @Slauma S powyżej;
public static class DataExtensions
{
public static DbContext AddToContext<T>(this DbContext context, object entity, int count, int commitCount, bool recreateContext, Func<DbContext> contextCreator)
{
context.Set(typeof(T)).Add((T)entity);
if (count % commitCount == 0)
{
context.SaveChanges();
if (recreateContext)
{
context.Dispose();
context = contextCreator.Invoke();
context.Configuration.AutoDetectChangesEnabled = false;
}
}
return context;
}
}
Użycie:
public void AddEntities(List<YourEntity> entities)
{
using (var transactionScope = new TransactionScope())
{
DbContext context = new YourContext();
int count = 0;
foreach (var entity in entities)
{
++count;
context = context.AddToContext<TenancyNote>(entity, count, 100, true,
() => new YourContext());
}
context.SaveChanges();
transactionScope.Complete();
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-25 13:35:24
Wiem, że to bardzo stare pytanie, ale jeden z gości powiedział, że opracował metodę rozszerzenia do używania bulk insert z EF, a kiedy sprawdziłem, odkryłem, że biblioteka kosztuje 599 $dzisiaj (dla jednego dewelopera). Może to ma sens dla całej biblioteki, jednak dla samej wkładki zbiorczej to za dużo.
Oto bardzo prosta metoda rozszerzenia, którą zrobiłem. Używam tego na parze z bazy danych pierwszy (nie testowane z kodem najpierw, ale myślę, że działa to samo). Zmień YourEntities
z nazwa kontekstu:
public partial class YourEntities : DbContext
{
public async Task BulkInsertAllAsync<T>(IEnumerable<T> entities)
{
using (var conn = new SqlConnection(Database.Connection.ConnectionString))
{
conn.Open();
Type t = typeof(T);
var bulkCopy = new SqlBulkCopy(conn)
{
DestinationTableName = GetTableName(t)
};
var table = new DataTable();
var properties = t.GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string));
foreach (var property in properties)
{
Type propertyType = property.PropertyType;
if (propertyType.IsGenericType &&
propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = Nullable.GetUnderlyingType(propertyType);
}
table.Columns.Add(new DataColumn(property.Name, propertyType));
}
foreach (var entity in entities)
{
table.Rows.Add(
properties.Select(property => property.GetValue(entity, null) ?? DBNull.Value).ToArray());
}
bulkCopy.BulkCopyTimeout = 0;
await bulkCopy.WriteToServerAsync(table);
}
}
public void BulkInsertAll<T>(IEnumerable<T> entities)
{
using (var conn = new SqlConnection(Database.Connection.ConnectionString))
{
conn.Open();
Type t = typeof(T);
var bulkCopy = new SqlBulkCopy(conn)
{
DestinationTableName = GetTableName(t)
};
var table = new DataTable();
var properties = t.GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string));
foreach (var property in properties)
{
Type propertyType = property.PropertyType;
if (propertyType.IsGenericType &&
propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = Nullable.GetUnderlyingType(propertyType);
}
table.Columns.Add(new DataColumn(property.Name, propertyType));
}
foreach (var entity in entities)
{
table.Rows.Add(
properties.Select(property => property.GetValue(entity, null) ?? DBNull.Value).ToArray());
}
bulkCopy.BulkCopyTimeout = 0;
bulkCopy.WriteToServer(table);
}
}
public string GetTableName(Type type)
{
var metadata = ((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace;
var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace));
var entityType = metadata
.GetItems<EntityType>(DataSpace.OSpace)
.Single(e => objectItemCollection.GetClrType(e) == type);
var entitySet = metadata
.GetItems<EntityContainer>(DataSpace.CSpace)
.Single()
.EntitySets
.Single(s => s.ElementType.Name == entityType.Name);
var mapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace)
.Single()
.EntitySetMappings
.Single(s => s.EntitySet == entitySet);
var table = mapping
.EntityTypeMappings.Single()
.Fragments.Single()
.StoreEntitySet;
return (string)table.MetadataProperties["Table"].Value ?? table.Name;
}
}
Możesz użyć tego przeciwko dowolnej kolekcji, która dziedziczy z IEnumerable
, w ten sposób:
await context.BulkInsertAllAsync(items);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-22 04:48:05
Szukam najszybszego sposobu wstawiania do encji Framework
Dostępne są biblioteki innych firm obsługujące Bulk Insert:
- Z.Extensions (Recommended)
- EFUtilities
- EntityFramework.BulkInsert
Zobacz: Entity Framework Bulk Insert library
należy zachować ostrożność przy wyborze biblioteki wstawiania zbiorczego. Only Entity Framework Extensions supports all kind of Asocjacje i spadki i tylko to jest nadal wspierane.
Zastrzeżenie: jestem właścicielem Entity Framework Extensions
Ta biblioteka Pozwala na wykonywanie wszystkich operacji zbiorczych, których potrzebujesz do swoich scenariuszy:
- Bulk SaveChanges
- Bulk Insert
- Bulk Delete
- Bulk Update
- Bulk Merge
Przykład
// Easy to use
context.BulkSaveChanges();
// Easy to customize
context.BulkSaveChanges(bulk => bulk.BatchSize = 100);
// Perform Bulk Operations
context.BulkDelete(customers);
context.BulkInsert(customers);
context.BulkUpdate(customers);
// Customize Primary Key
context.BulkMerge(customers, operation => {
operation.ColumnPrimaryKeyExpression =
customer => customer.Code;
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-18 16:25:46
Zgodnie z moją wiedzą jest no BulkInsert
w EntityFramework
Aby zwiększyć wydajność ogromnych wkładek.
W tym scenariuszu możesz użyć SqlBulkCopy W ADO.net
, aby rozwiązać swój problem
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-09 17:20:03
Oto porównanie wydajności między używaniem encji Framework i używaniem klasy SqlBulkCopy na realistycznym przykładzie: Jak masowo wstawiać złożone obiekty do bazy danych SQL Server
Jak już podkreślali inni, ORM nie są przeznaczone do użycia w operacjach masowych. Oferują elastyczność, oddzielenie obaw i inne korzyści, ale operacje masowe (z wyjątkiem odczytu masowego) nie należą do nich.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-14 14:13:50
Inną opcją jest użycie SqlBulkTools dostępnego z Nuget. Jest bardzo łatwy w użyciu i ma kilka zaawansowanych funkcji.
Przykład:
var bulk = new BulkOperations();
var books = GetBooks();
using (TransactionScope trans = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager
.ConnectionStrings["SqlBulkToolsTest"].ConnectionString))
{
bulk.Setup<Book>()
.ForCollection(books)
.WithTable("Books")
.AddAllColumns()
.BulkInsert()
.Commit(conn);
}
trans.Complete();
}
Zobacz dokumentacja aby uzyskać więcej przykładów i zaawansowanych zastosowań. Zastrzeżenie: jestem autorem tej biblioteki i wszelkie poglądy są mojego własnego zdania.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 23:16:30
Użycie SqlBulkCopy
:
void BulkInsert(GpsReceiverTrack[] gpsReceiverTracks)
{
if (gpsReceiverTracks == null)
{
throw new ArgumentNullException(nameof(gpsReceiverTracks));
}
DataTable dataTable = new DataTable("GpsReceiverTracks");
dataTable.Columns.Add("ID", typeof(int));
dataTable.Columns.Add("DownloadedTrackID", typeof(int));
dataTable.Columns.Add("Time", typeof(TimeSpan));
dataTable.Columns.Add("Latitude", typeof(double));
dataTable.Columns.Add("Longitude", typeof(double));
dataTable.Columns.Add("Altitude", typeof(double));
for (int i = 0; i < gpsReceiverTracks.Length; i++)
{
dataTable.Rows.Add
(
new object[]
{
gpsReceiverTracks[i].ID,
gpsReceiverTracks[i].DownloadedTrackID,
gpsReceiverTracks[i].Time,
gpsReceiverTracks[i].Latitude,
gpsReceiverTracks[i].Longitude,
gpsReceiverTracks[i].Altitude
}
);
}
string connectionString = (new TeamTrackerEntities()).Database.Connection.ConnectionString;
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction))
{
sqlBulkCopy.DestinationTableName = dataTable.TableName;
foreach (DataColumn column in dataTable.Columns)
{
sqlBulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
}
sqlBulkCopy.WriteToServer(dataTable);
}
transaction.Commit();
}
}
return;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-04 22:06:11
Jeden z najszybszych sposobów na zapisanie listy należy zastosować następujący kod
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
AutoDetectChangesEnabled = false
Add, AddRange& SaveChanges: nie wykrywa zmian.
ValidateOnSaveEnabled = false;
Nie wykrywa śledzenia zmian
Musisz dodać nuget
Install-Package Z.EntityFramework.Extensions
Teraz możesz użyć następującego kodu
var context = new MyContext();
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
context.BulkInsert(list);
context.BulkSaveChanges();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-02 10:05:11
Sekretem jest wstawienie do identycznej pustej tabeli. Wkładki szybko się rozjaśniają. Następnie uruchom pojedynczy Wstaw z tego do głównej dużej tabeli. Następnie obcinaj stół przygotowawczy do następnej partii.
Ie.
insert into some_staging_table using Entity Framework.
-- Single insert into main table (this could be a tiny stored proc call)
insert into some_main_already_large_table (columns...)
select (columns...) from some_staging_table
truncate table some_staging_table
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-18 10:43:30
Czy kiedykolwiek próbowałeś wstawić przez pracownika lub zadanie w tle?
W moim przypadku wstawiam 7760 rejestrów, rozmieszczonych w 182 różnych tablicach z relacjami z kluczami obcymi (przez NavigationProperties).
Bez zadania zajęło to 2,5 minuty. Zadanie (Task.Factory.StartNew(...)
) zajęło 15 sekund.
Wykonuję SaveChanges()
tylko po dodaniu wszystkich encji do kontekstu. (w celu zapewnienia integralności danych)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-27 20:19:58
Wszystkie napisane tutaj rozwiązania nie pomagają, ponieważ gdy wykonujesz SaveChanges (), polecenia insert są wysyłane do bazy danych jeden po drugim, tak działa Entity.
A jeśli podróż do bazy danych i z powrotem wynosi np. 50 ms, to czas potrzebny na wstawienie to ilość rekordów x 50 ms.
Musisz użyć BulkInsert, oto link: https://efbulkinsert.codeplex.com/
Dzięki temu zmniejszyłem czas wstawiania z 5-6 minut do 10-12 sekund.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-01 13:05:03
Możesz użyć biblioteki Bulk package . Wersja Bulk Insert 1.0.0 jest używana w projektach mających Entity framework > = 6.0.0 .
Więcej opisów można znaleźć tutaj- Bulkoperation source code
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-17 13:54:31
[NOWE ROZWIĄZANIE DLA POSTGRESQL] Hej, wiem, że to dość stary post, ale ostatnio napotkałem podobny problem, ale używaliśmy Postgresql. Chciałem użyć skutecznego bulkinsert, co okazało się dość trudne. Nie znalazłem żadnej odpowiedniej wolnej biblioteki, aby to zrobić w tym DB. Znalazłem tylko tego pomocnika.: https://bytefish.de/blog/postgresql_bulk_insert / który jest również na Nuget. Napisałem mały mapper, który automatycznie mapuje właściwości w sposób Framework:
public static PostgreSQLCopyHelper<T> CreateHelper<T>(string schemaName, string tableName)
{
var helper = new PostgreSQLCopyHelper<T>("dbo", "\"" + tableName + "\"");
var properties = typeof(T).GetProperties();
foreach(var prop in properties)
{
var type = prop.PropertyType;
if (Attribute.IsDefined(prop, typeof(KeyAttribute)) || Attribute.IsDefined(prop, typeof(ForeignKeyAttribute)))
continue;
switch (type)
{
case Type intType when intType == typeof(int) || intType == typeof(int?):
{
helper = helper.MapInteger("\"" + prop.Name + "\"", x => (int?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type stringType when stringType == typeof(string):
{
helper = helper.MapText("\"" + prop.Name + "\"", x => (string)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type dateType when dateType == typeof(DateTime) || dateType == typeof(DateTime?):
{
helper = helper.MapTimeStamp("\"" + prop.Name + "\"", x => (DateTime?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type decimalType when decimalType == typeof(decimal) || decimalType == typeof(decimal?):
{
helper = helper.MapMoney("\"" + prop.Name + "\"", x => (decimal?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type doubleType when doubleType == typeof(double) || doubleType == typeof(double?):
{
helper = helper.MapDouble("\"" + prop.Name + "\"", x => (double?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type floatType when floatType == typeof(float) || floatType == typeof(float?):
{
helper = helper.MapReal("\"" + prop.Name + "\"", x => (float?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type guidType when guidType == typeof(Guid):
{
helper = helper.MapUUID("\"" + prop.Name + "\"", x => (Guid)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
}
}
return helper;
}
Używam go w następujący sposób (miałem podmiot o nazwie Przedsiębiorstwo):
var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking));
undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));
Pokazałem przykład z transakcją, ale można to zrobić również przy normalnym połączeniu pobranym z kontekstu. undertoadd jest wyliczany z normalnych rekordów entity, które chcę dodać do DB.
To rozwiązanie, do którego mam po kilku godzinach badań i prób, jest jak można się spodziewać znacznie szybsze i w końcu łatwe w użyciu i darmowe! Naprawdę radzę ci używać tego rozwiązanie, nie tylko z wyżej wymienionych powodów, ale także dlatego, że tylko z nim nie miałem problemów z samym Postgresqlem, wiele innych rozwiązań działa bez zarzutu np. z SqlServer.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-05 21:03:27
Ale dla więcej niż (+4000) wstawek zalecam użycie procedury składowanej. dołączony czas, jaki upłynął. Wstawiłem 11.788 wierszy w 20"
Thats it code
public void InsertDataBase(MyEntity entity)
{
repository.Database.ExecuteSqlCommand("sp_mystored " +
"@param1, @param2"
new SqlParameter("@param1", entity.property1),
new SqlParameter("@param2", entity.property2));
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-20 00:54:00
Użyj procedury składowanej, która pobiera dane wejściowe w postaci xml do wstawiania danych.
Z kodu c# podaj dane jako xml.
Np. w c# składnia będzie taka:
object id_application = db.ExecuteScalar("procSaveApplication", xml)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-07 03:33:19