In order to have a better idea of the time spent into the database access layer, it can be interesting to get some statistics on that part of the code, knowing that most of the time spent into eXo JCR is mainly the database access. This statistics will then allow you to identify without using any profiler what is normally slow in this layer, which could help to fix the problem quickly.
In case you use
    org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.CQJDBCWorkspaceDataContainer
    or
    org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer
    as WorkspaceDataContainer, you can get statistics on the
    time spent on the database access layer. The database access layer (in
    eXo JCR) is represented by the methods of the
    org.exoplatform.services.jcr.storage.WorkspaceStorageConnection interface,
    so for all the methods defined in this interface, you can have the
    following figures:
The minimum time spent into the method.
The maximum time spent into the method.
The average time spent into the method.
The total amount of time spent into the method.
The total amount of time the method has been called.
Those figures are also available globally for all the methods which gives us the global behavior of this layer.
If you want to enable the statistics, you just need to set the JVM
      parameter called
      JDBCWorkspaceDataContainer.statistics.enabled
      to
      true. The corresponding CSV file is
      StatisticsJDBCStorageConnection-${creation-timestamp}.csv
      for more details about how the csv files are managed. See
      Statistics manager
      for more details.
    
The format of each column header is ${method-alias}-${metric-alias}.
    The metric alias are described in the statistics manager section.
The name of the category of statistics corresponding to these
    statistics is JDBCStorageConnection, this name is
    mostly needed to access to the statistics through JMX.
| global | This is the alias for all the methods. | 
| getItemDataById | This is the alias for the getItemData(String identifier)method. | 
| getItemDataByNodeDataNQPathEntry | This is the alias for the getItemData(NodeData parentData, QPathEntry
            name)method. | 
| getChildNodesData | This is the alias for the getChildNodesData(NodeData parent)method. | 
| getChildNodesCount | This is the alias for the  getChildNodesCount(NodeData parent)method. | 
| getChildPropertiesData | This is the alias for the getChildPropertiesData(NodeData parent)method. | 
| listChildPropertiesData | This is the alias for the listChildPropertiesData(NodeData parent)method. | 
| getReferencesData | This is the alias for the getReferencesData(String nodeIdentifier)method. | 
| commit | This is the alias for the commit()method. | 
| addNodeData | This is the alias for the add(NodeData data)method. | 
| addPropertyData | This is the alias for the add(PropertyData data)mehod. | 
| updateNodeData | This is the alias for the update(NodeData data)method. | 
| updatePropertyData | This is the alias for the update(PropertyData data)method. | 
| deleteNodeData | This is the alias for the delete(NodeData data)method. | 
| deletePropertyData | This is the alias for the delete(PropertyData data)method. | 
| renameNodeData | This is the alias for the rename(NodeData data)method. | 
| rollback | This is the alias for the rollback()method. | 
| isOpened | This is the alias for the isOpened()method. | 
| close | This is the alias for the close()method. |