Avec mon binôme, nous avons perdu une bonne demi-journée à résoudre un problème de performance tortueux. Le contexte est le suivant :

  • Base de données Oracle
  • Client .NET Microsoft (System.Data.Oracle.Client)
  • NHibernate

Nous avons constaté qu'une requête NHibernate prenait un peu trop son temps : environ 40 secondes !! Voici à peu près le code incriminé :

IList articles = session.CreateCriteria(typeof(Article))
        .Add( Expression.In("Code", listeDeCodes) ).List();

listeDeCodes est une liste de 1000 codes.

Je passe les détails de nos investigations mais nous avons fini par faire un programme de test sans NHibernate dont voici le pseudo-code :

requete1 = "select * from articles where code in ('code1', 'code2', ..., 'code100')";
command = new OracleCommand(requete1);
TesterCommande(command, "Liste directe de codes");
 
requete2 = "select * from articles where code in (:code1, :code2, ..., :code100)";
command = new OracleCommand(requete2);
AjouterParametre(command, ":code1", "code1");
AjouterParametre(command, ":code2", "code2");
...
AjouterParametre(command, ":code100", "code100");
TesterCommande(command, "Avec paramètres");
private TesterCommand(IDbCommand cmd, string nomDuTest)
{
  reader = cmd.ExecuteReader();
  chrono.RAZ();
  while (reader.Read())
  {
 
  }
  Console.WriteLine("{0} : {1}ms", nomDuTest, chrono.TotalMilliseconds)
}

Les résultats sont pour le moins surprenants :



Liste directe de codes : 43ms
Avec paramètres : 41000ms

Nous avons donc décidé de faire les mêmes tests avec le client fourni par Oracle : Oracle Data Provider .NET (ODP.NET). Voici les résultats :

Liste directe de codes : 43ms
Avec paramètres : 15ms

NHibernate utilise intensément les requêtes paramétrées (qui sont bien sûr sensées être plus efficaces, le deuxième test le prouve) et ses performances sont donc drastiquement dégradées par la gestion catastrophique des commandes du client Microsoft.