Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance benchamrks #13

Open
dryajov opened this issue Jun 2, 2017 · 7 comments
Open

Performance benchamrks #13

dryajov opened this issue Jun 2, 2017 · 7 comments
Labels

Comments

@dryajov
Copy link

dryajov commented Jun 2, 2017

Are there any performance benchmarks and recommendations?

@meirgottlieb
Copy link
Contributor

You can run the "bench" task using gulp. What do you mean by recommendations?

@dryajov
Copy link
Author

dryajov commented Jun 2, 2017

@meirgottlieb sorry for the vague question. I meant, some particular usage patterns that degrade performance that might not be immediately obvious, as well as suggestions around isolating issues when troubleshooting slowness when hydrate is being used.

The reason I bring it up is because there is some perceived slowness in the app i'm building which might or might not be related to hydrate, and I wanted to check if there are any easy ways of shooting yourself in the foot that I might be ignoring. Ultimately, I think the slowness is probably unrelated to hydrate, but knowing what to check for first should make things easier to isolate/troubleshoot.

@meirgottlieb
Copy link
Contributor

meirgottlieb commented Jun 3, 2017

Got it. No problem. I have lots of recommendations:

  1. Make sure you are defining appropriate indexes on the Entities and creating them in the database. To define indexes use the @Index decorator on an Entity. To create the indexes in the database call createIndexes on the SessionFactory. I do this on server start up when NODE_ENV does not equal "production". For production I call it as needed as part of my deployment process.

  2. The default ChangeTrackingType, DeferredImplicit, during a flush will dirty check, every Entity that is loaded in the Session. Although this is convenient, because you don't have to worry about when Entities are modified, the dirty checking is expensive. If you have entities that are frequently loaded and rarely modified, you should consider switching to DeferredExplicit change tracking. This will only dirty check entities when you explicitly call save on the Session. You can set change tracking on an entity using the @ChangeTracking decorator. You can switch to DeferredExplicit change tracking for all Entities instead by default by setting the changeTracking property on the Configuration.

  3. If you know Entities will never change, set them as immutable using the @Immutable decorator. This will disable change tracking and optimistic locking for the entity. This means the Entity will never be dirty checked or written to the database after the first time it's written.

  4. If you know your embedded classes will not change, set them to immutable as well using the @Immutable decorator. When an embedded class is immutable, it will be skipped when Hydrate is dirty checking the containing Entity and the embedded's document representation will be cached for serialization.

  5. If you are pulling back large amounts of data in situations where no domain logic will be used and the entity will not be modified, such as for reports, consider querying the database directly. You can access the underlying database connection with the connection property of the SessionFactory. For example: session.factory.connection.collection("user").aggregate(...)

  6. Duplicate data to avoid fetching Entity references. For example, let's say you have a Book entity that references an Author entity, and you often have to fetch the Author of the Book just to display the name of the author. Instead, store the name of the Author as a property on the Book (in addition to the reference to the Author) so that you don't need to fetch the Author every time you load a Book. This also helps with reporting if you are using the database connection directly for reporting (as suggested above).

  7. If you have a property on an Entity that stores large amounts of data, such as a binary file or photo, set it to lazy fetching with the @Fetch decorator. When a property is set to FetchType.Lazy, it is not loaded from the database when the Entity is loaded unless it is explicitly fetched using fetch on the Session.

  8. Generally avoid using FetchType.Eager on entity references since it could end up loading a large portion of your entity graph. Instead, fetch entity references as needed.

Please let me know if any of the suggestion above help.

@meirgottlieb
Copy link
Contributor

meirgottlieb commented Jun 3, 2017

Also, to help identify slow queries during development, add a bunyan logger with a log level of TRACE as the logger property in the Configuration. This will log all queries executed along with the amount of time it took to execute the query. You can then execute slow queries directly in the MongoDB shell with explain to determine what indexes will be helpful (or if your current indexes are working as expected). Note that ObjectId's logged in the queries are printed as strings so you need to make sure to wrap them with ObjectId when running a query in the MongoDB shell.

The logger will also print out summary information for a flush, such as the execution time, and the number of entities inserted, updated, removed, and dirty checked. If your flushes are slow, consider using the strategies mentioned above to reduce dirty checking and serialization time.

I do not recommend using the logger in a production environment.

@dryajov
Copy link
Author

dryajov commented Jun 3, 2017

Awesome pointers! Thanks so much, will try this out and report on findings.

@meirgottlieb
Copy link
Contributor

Hey @dryajov, Did any of these suggestions help?

@dryajov
Copy link
Author

dryajov commented Jul 14, 2017

We're starting performance testing shortly, so haven't had a time to test this out yet - but the tracing suggestion helped a for debugging. Tanks!

Will report back as soon as I have results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants