performance issue on Spring Data Mongodb

2020-07-10 10:52发布

I've got an issue on spring data mongodb, in a method, I request a simple "find" wich retrieve ~1000 Documents.

my spring data code is here :

Query myquery = query(where("ipp").is(ipp).and(CODE_MESURE).in(codes).and(DATE_MESURE).gte(iDateDebut).lt(iDateFin));
return template.find(myquery, MessageMongo.class);

And with JProfiler, i've got ~1,4sec in the "find" method of MongoTemplate class. Note : The request to MongoDB is not the problem, execution take less than 20ms. enter image description here

But if try to request the same query with mongo java driver by traditional way :

final DBCollection collection = template.getCollection(Constantes.MONGO_COLLECTION_MESSAGES_PARAMETRES_VITAUX);
 final DBCursor cursor = collection.find(myquery.getQueryObject());
final List<MessageMongo> tab = new ArrayList<>();
 while (cursor.hasNext()) {
  final DBObject d = cursor.next();
  tab.add(new MessageMongo((String) d.get("origine"), (String) d.get("appareil"),
      (String) d.get("chambre"), (String) d.get("lit"), (String) d.get("uf"), (String) d.get("ipp"),
      (String) d.get("domaineIpp"), (String) d.get("iep"), (String) d.get("domaineIep"), (String) d.get("ej"),
      ((Date) d.get("dateReception")).toInstant(), (String) d.get("codeMesure"),
      (String) d.get("uniteMesure"), (Double) d.get("valeurMesure"), ((Date) d.get("dateMesure")).toInstant()));
 }
return tab;

My method execute in ~140ms (10x faster than mongoTemplate style !) enter image description here is there a bug in Spring Data Mongo, or I missed something to configure ? I prefer to write with, it is easier to read, but performance is so poor :'(

the Document class :

@Document(collection = Constantes.MONGO_COLLECTION_MESSAGES_PARAMETRES_VITAUX)
public class MessageMongo implements MessageModel {
  @Id
  private String id;
  private final String origine;
  private final String appareil;
  private final String chambre;
  private final String lit;
  private final String uf;
  @Indexed
  private final String ipp;
  private final String domaineIpp;
  private final String iep;
  private final String domaineIep;
  private final String ej;
  private final Instant dateReception;
  @Indexed
  private final String codeMesure;
  private final String uniteMesure;
  private final Double valeurMesure;
  @Indexed
  private final Instant dateMesure;
. . .

EDIT : 1,67sec if I use MongoRepository with the named method :

public List<MessageMongo> findByIppAndCodeMesureInAndDateMesureBetween(final String ipp, final List<String> codesMesure, final Instant from, final Instant to);

enter image description here

EDIT2: logs of spring data :

2017/12/04 15:44:59,455 INFO  [nio-8180-exec-4] fr.sib.sillage.biometrie.service.impl.MongoMessageService    : findByIppAndCodesBetweenDate ipp=102828799, codes=[147842], dateDebut=2017-12-02T13:46:59,dateFin=2017-12-03T01:46:59  
2017/12/04 15:44:59,482 DEBUG [nio-8180-exec-4] o.s.data.mongodb.repository.query.MongoQueryCreator          : Created query Query: { "ipp" : "102828799", "codeMesure" : { "$in" : [ "147842"]}, "dateMesure" : { "$gt" : { $java : 2017-12-02T12:46:59Z }, "$lt" : { $java : 2017-12-03T00:46:59Z } } }, Fields: null, Sort: null
2017/12/04 15:44:59,517 DEBUG [nio-8180-exec-4] org.springframework.data.mongodb.core.MongoTemplate          : find using query: { "ipp" : "102828799" , "codeMesure" : { "$in" : [ "147842"]} , "dateMesure" : { "$gt" : { "$date" : "2017-12-02T12:46:59.000Z"} , "$lt" : { "$date" : "2017-12-03T00:46:59.000Z"}}} fields: null for class: class fr.sib.sillage.biometrie.model.MessageMongo in collection: parametresVitaux
2017/12/04 15:44:59,517 DEBUG [nio-8180-exec-4] org.springframework.data.mongodb.core.MongoDbUtils           : Getting Mongo Database name=[LilleNoSQLDatabase]
2017/12/04 15:44:59,567 INFO  [nio-8180-exec-4] org.mongodb.driver.connection                                : Opened connection [connectionId{localValue:6, serverValue:3003}] to hades:27017
2017/12/04 15:44:59,567 DEBUG [nio-8180-exec-4] org.mongodb.driver.protocol.command                          : Sending command {find : BsonString{value='parametresVitaux'}} to database LilleNoSQLDatabase on connection [connectionId{localValue:6, serverValue:3003}] to server hades:27017
2017/12/04 15:44:59,592 DEBUG [nio-8180-exec-4] org.mongodb.driver.protocol.command                          : Command execution completed
2017/12/04 15:44:59,796 DEBUG [nio-8180-exec-4] org.mongodb.driver.protocol.command                          : Sending command {getMore : BsonInt64{value=63695089133}} to database LilleNoSQLDatabase on connection [connectionId{localValue:5, serverValue:3004}] to server hades:27017
2017/12/04 15:44:59,862 DEBUG [nio-8180-exec-4] org.mongodb.driver.protocol.command                          : Command execution completed
2017/12/04 15:45:01,213 INFO  [nio-8180-exec-4] fr.sib.sillage.biometrie.service.impl.MongoMessageService    : findByIppAndCodesBetweenDate size=1281

EDIT 3 : I've expand the call Tree with org.springframework in full view in JProfiler, so I can view what's wrong with Spring Data MongoDB, and here is the majority of time spended : enter image description here 2,5 sec total with

  • 1,290 calls of
    org.springframework.data.convert.DefaultTypeMapper.readType (1,462
    ms)

  • 1,290 calls of org.springframework.data.mongodb.core.convert.MappingMongoConverter.read (1,026 ms)

And what's the composition of two methods : A majority of Class.forName (erk !) in the first readType enter image description here

And it's less clear on the second call to MappingMongoConverter.read enter image description here

I hope it will be easier to find the issue.

1条回答
等我变得足够好
2楼-- · 2020-07-10 11:44

I'm not sure if this applies to your exact case but I had a very similar situation with a lot of time being wasted in ClassUtils.forName() and ClassLoader.load().

I've inspected the situation under the debugger and the root cause in my case was that the class I was trying to deserialize the document to had been moved to a different package. In this case, Spring Data can't properly cache type information and issues a slow and expensive ClassLoader.load() on the persisted _class field for each document!

Of course, this class load is doomed to fail because it references a class that no longer exists at the location stored int the _class field of the document.

查看更多
登录 后发表回答