Devez-vous abandonner une infrastructure ORM lorsque vous devez implémenter une opération en bloc?


15

Voici une situation courante:

  • Vous devez implémenter une opération en bloc dans une application qui utilise une infrastructure ORM.
  • Après la première passe, vous avez remarqué des problèmes de performances importants.

Voici ma question:

  • Dans cette situation, devriez-vous privilégier une solution qui inclut du SQL brut?
  • Ou existe-t-il des modèles de conception bien connus qui peuvent vous aider à atténuer les problèmes généralement associés aux opérations en bloc avec les infrastructures ORM?

ÉDITER:

  • Je ne vous demande pas si vous devez supprimer le cadre ORM de l'application entière.
  • Je demande: devriez-vous renoncer au cadre ORM pour cette petite tranche de l'application?

Je ne sais pas si vous devez faire quelque chose, mais avez - vous essayé Batching votre opération en vrac?
ChrisAnnODell

Réponses:


13

Les ORM ne sont pas destinés à prendre complètement le contrôle de l'accès à votre base de données. Utilisez-les pour ces 80% de code CRUD, ce qui est trop fastidieux pour être écrit par vous-même. Utilisez des procédures stockées, du SQL dynamique ou tout ce que vous voulez pour les 20% restants qui doivent être soigneusement optimisés.


4
Cela fonctionnerait si l'abstraction de la base de données n'était pas l'une des principales raisons pour lesquelles vous avez décidé d'utiliser un ORM.

@ Pierre303, j'ai du mal à comprendre votre commentaire. Que voulez-vous dire?
Mark Canlas

@MarkCanlas: Je pense qu'il veut dire "faire abstraction de la base de données", en ce sens que vous pouvez changer la base de données (par exemple passer de SQL Server à MySQL) si vous le souhaitez. En pratique, ce cas d'utilisation se produit rarement.
Robert Harvey

1
Vous pouvez toujours créer des abstractions. La plupart des ORM qui prennent en charge plusieurs fournisseurs / dialectes prennent en charge le code spécifique au fournisseur / dialecte. Vous pouvez implémenter des opérations en tant qu'insertion en bloc / liaison de tableau / TVP / quoi que ce soit pour des bases de données spécifiques et le laisser retomber lentement par lent pour les fournisseurs non pris en charge comme SQLite. Au pire, vous pouvez diviser la fonctionnalité en bloc en une interface / classe distincte et une sous-implémentation dans une implémentation différente basée sur des paramètres de construction ou de configuration.
Aaronaught

Oui, des dialectes personnalisés peuvent vous aider, ainsi qu'un code spécifique pour des problèmes spécifiques. Cependant, pour que cela soit viable d'un point de vue financier, cela doit être limité au strict minimum. Notre personnalisation grâce aux fonctions personnalisées (dialectes) représente moins de 0,1% de la base totale des codes d'accès aux données. Je serais vraiment inquiet si c'était plus que cela.

7

J'utilise un ORM (nHibernate) dans une application qui nécessite de hautes performances et gère des milliards d'enregistrements. Avec le temps, nous avons remarqué que les problèmes de performances les plus importants étaient liés à notre propre façon d'utiliser l'ORM plutôt qu'à l'ORM seul.

L'ORM ne doit pas remplacer vos connaissances de base de données obligatoires. C'est un outil que vous utilisez pour obtenir plus de productivité et de flexibilité dans votre code, mais vous devrez connaître les processus sous-jacents pour optimiser vos performances.

Vous n'avez pas spécifié d'ORM spécifique, voici donc ce que nous avons fait pour améliorer les performances:

  • Nous avons utilisé un profileur ORM. (nous avons utilisé nhprof)
  • Nous avons utilisé un profileur de base de données. (nous avons utilisé SQL Server Profiler)
  • Nous avons lu autant d'articles que possible sur le sujet. (Beaucoup étaient disponibles pour nHibernate en plus du chapitre entier sur le sujet dans la documentation)
  • Nous avons acheté des livres spécifiques sur les performances et l'évolutivité.
  • Nous avons créé un système de benchmarking pour tester nos propres optimisations.
  • et plus important encore, nous avons pu tester notre code avec des clients réels avec d'énormes données. Cette dernière chose à elle seule nous a aidé à repérer la plupart des problèmes dans notre application.

1

Nous avons réussi à le faire avec Entity Framework, mais notre application a fait beaucoup d'opérations de style batch (nous écrivions un grand nombre d'enregistrements dans des tables individuelles), donc c'était un bon ajustement. Je verrais certainement s'il serait possible de conserver le cadre ORM si possible, juste pour réduire la quantité de code à usage spécial dans votre application. Est-il possible de tamponner les écritures, puis de les exécuter en groupe? Vous perdez la sémantique des transactions, mais si vous optez pour des opérations en bloc, je suppose que vous avez déjà accepté cela.


1

Les ORM ne font rien de magique. Ils traduisent les méthodes d'accès aux objets en SQL. Les instructions SQL qu'elles exécutent ne sont pas nécessairement plus lentes que celles que vous écririez manuellement. Cela dit, il y a quelques problèmes sur lesquels vous pourriez tomber:

  1. Transactions: une grande opération en vrac est presque toujours plus rapide que de nombreuses petites transactions qui, ensemble, accomplissent la même chose. Par conséquent, si vos appels de méthode ORM utilisent des transactions à granularité fine (les méthodes de style d'enregistrement actives dans les entités Spring Roo par exemple sont annotées comme @Transactional par défaut), les opérations en bloc seront lentes. Si tel est le cas dans votre application, vous devez examiner votre logique de transaction.
  2. Mise en cache: dans Hibernate, un cache de premier niveau permet à votre gestionnaire d'entités d'éviter les allers-retours inutiles dans la base de données. Bonne chose en général, mais mauvaise pour les insertions en vrac, où cela conduit à un obstruction du cache inutile, entraînant une dégradation des performances des applications. Si c'est votre problème, vous devriez regarder le modèle de traitement par lots suggéré ci-dessus par ChrisAnnODell. Nous l'utilisons chez nos importateurs et cela accélère beaucoup les insertions en vrac.

Il n'y a rien de mal à utiliser SQL natif pour améliorer les performances. Mais assurez-vous d'abord de comprendre ce qui vous ralentit.


Pour éviter le cache, utilisez une StatelessSession. Évitez également les ID d'incrémentation automatique. HiLo ou Guid doivent être utilisés à la place.

1

Contournez l'ORM. Non seulement cela, mais contournez également le sql "normal". Utilisez un utilitaire en vrac de votre base de données pour insérer des ensembles de données extrêmement volumineux dans une table intermédiaire. Utilisez ensuite sql pour effectuer vos activités de mise en scène.

Votre ORM "saveur du blog" peut ne pas fonctionner dans toutes les situations.


Bon, ce genre d'outils back-end est difficile à apprendre, mais après environ 3 ou 4 fois, vous serez un expert et pourrez faire les choses plus rapidement et parfois des choses qui ne peuvent pas être faites autrement. C'est comme la différence entre une pelle et un bulldozer. J'ai écrit des outils contrôlés par script pour diverses plates-formes pour lire des fichiers d'entrée de texte et mettre à jour des données avec des opérations de bas niveau. Écrire un tel outil peut aussi vous rendre la vie plus facile (ou du moins plus intéressante). Des choses comme celle-ci peuvent être utilisées pour modifier les données de personnalisation sur les installations client lors des mises à jour logicielles.

0

Été dans cette situation. Parfois, vous devez.

Certains ORM permettent au développeur d'ignorer le modèle d'objet et d'aller directement à la couche de base de données.

Il existe également des ORM, qui utilisent des opérations en bloc, encapsulées, comme orientées objet.


0

Comme mentionné par umlcat , il existe des ORM qui vous permettront d'utiliser des opérations en bloc.

Encore mieux, de nombreux ORM sont extensibles, vous pouvez donc simplement écrire votre propre méthode pour exécuter des opérations en bloc, si ce n'est déjà fait. Si l'opération en bloc dans votre application est quelque chose que vous pouvez prendre en compte, je l'ajouterais en tant que couche sur l'ORM (pour ce faire, vous devrez probablement écrire du SQL brut), mais ensuite dans l'application, utilisez l'ORM méthode que vous avez implémentée.

Cela facilite également les tests unitaires et le débogage. Une fois que vous avez une bonne couverture de test pour vos méthodes ORM, vous êtes libre de l'utiliser dans vos applications. Sinon, le débogage de SQL brut (en particulier les plus gros avec des transactions et de nombreuses JOIN) peut être pénible.

Il m'a fallu près d'une journée pour repérer un bogue dans un appel SQL brut qui faisait presque 100 LOC, et le bogue n'était qu'un seul caractère! Depuis lors, j'essaie d'éviter d'avoir du SQL brut dans l'application et de faire tester séparément toutes les procédures SQL séparément.


0

Eh bien, je ne connais aucun motif de conception. Je suppose que vous avez pris la décision pour l'ORM pour une raison, donc abandonner l'ORM n'est probablement pas ce que vous voulez. Cependant, dans ces cas, je pense qu'il est possible de mélanger les deux solutions. Il n'y a rien de mal à cela, tant que vous le faites de manière concise et expliquez pourquoi vous vous écartez de l'utilisation par défaut de l'ORM dans votre logiciel. En plus de cela, certains frameworks ORM ont certaines fonctionnalités pour effectuer des opérations en masse. Je sais que nHibernate (ORM pour le framework .NET) a appelé StatelessSessions, qui ont beaucoup moins de frais généraux, mais cela pourrait ne pas vous donner le coup de pouce de performance que vous recherchez. Dans ce cas, utilisez simplement du SQL brut.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.