Hello,

Je suis aujourd'hui confronté à un problème de performances, comme dit dans le titre, sur des requêtes d'insertion.
Ma crainte c'est que la réponse soit simplement le fait c'est la limite d'Entity Framework, que les Insert sont lents de façon inhérente à la techno (plus fait pour des "select/update" unitaire j'en conviens.

Pour préciser un peu plus le soucis, il s'agit d'insertions "massives".
Le programme en question extrait d'un fichier XML des lignes à insérer en base, environ 500 000 dans le fichier. Le traitement prend actuellement plusieurs heures (environ 4h), ce qui n'est pas compatible avec les contraintes métiers qui sont derrières.

Entity Framework avait été choisi à l'époque pour simplifier la vie de la maintenance (car Entity est utilisé pour d'autres applications) et parce que le problème de performance ne se posait pas à l'époque car le volume de données a été mal estimé par le client (~10x plus important que prévu)

Bref, j'ai essayé d'optimiser la structure de la base, supprimer des index pour gagner du temps, rien n'y fait ! (A noter qu'une contrainte réseau accentue le phénomène... comme si ça ne suffisait pas !)

Toujours est-il que ma question est là suivante :
Peut-on faire quelque chose pour améliorer ça avec Entity Framework ? Faut-il se rabattre sur une solution "à la mano" type requête SQL "en dur" (car NHibernate semble trop coûteux à mettre en place du fait de l'état d'avancement) ?
J'ajoute que les solutions type Bulk ou SSIS ont été exclues pour des raisons d'infra (pas d'"applicatif" sur le server SQL...).

Si cela peut aider voici un bon de code qui fait l'insertion en Linq to SQL :

Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 
using (CoverEntities context = new CoverEntities())
            {
                try
                {
                    T_G61_ITEMS Item = null;
 
                    // Get the XXX by ID
                    var xxx = context.XXX.First(x => x.ID == XID);
 
                    // Check if there is already an item for the given XXX, language and item
                    // It should only happen for some items described in multiple rows
                    var ExistingItems = from i in context.ITEMS
                                        where i.ITEMS_NM_ITEM.Equals(ItemID, StringComparison.CurrentCultureIgnoreCase)
                                        && i.ITEMS_ID_LANGUAGE_ID.Equals(LanguageID, StringComparison.CurrentCultureIgnoreCase)
                                        && i.XXX.ID == XXX
                                        select i;
 
                    // If there is no existing item
                    if (ExistingItems.ToList().Count == 0)
                    {
                        // Then create one
                        Item = new ITEMS
                        {
                            ITEMS_ID_LANGUAGE_ID = LanguageID,
                            ITEMS_NM_ITEM = ItemID,
                            ITEMS_NM_VALUE = ItemValue
                        };
 
                        // Add the reference to the XXX
                        xxx.ITEMS.Add(Item);
                    }
                    else
                    {
                        // Update the existing item
                        Item = ExistingItems.First();
                        Item.ITEMS_NM_VALUE = Item.ITEMS_NM_VALUE.TrimEnd() + ' ' + ItemValue.TrimStart();
                    }
 
                    // Save the context for change commit
                    context.SaveChanges();           
                }
                catch (Exception e)
                {
                    throw new DatabaseException(e.Message, e.InnerException);
                }
            }

PS : J'ai remplacé certains termes mais j'espère ne pas avoir cassé la sémantique...


Merci d'avance !