I'm using Sequelize in Node.js with Apollo-Server and Express.js.
When making queries that go deeper and deeper, GraphQL is looping my models and doing a separate query by ID on each of those.
For example, if I get user(userId) > playthroughs > scores
, this will do a lookup for that user (no problem), then a lookup for all the playthroughs with that userId
(still no a big deal), but then to get the scores, it loops each playthroughId
and does a completely separate query on each. This is ridiculously inefficient and causes my queries to take way longer than they should.
Instead of looping:
SELECT scoreValue
FROM scores
WHERE playthroughId = id
I'd really like to grab the array myself and do that loop like this:
SELECT scoreValue
FROM scores
WHERE playthroughId IN (...ids)
This also happened when I used the reference GraphQL from Facebook last year, so I don't think it's specific to Apollo's implementation.
I'd like to know how I can tweak these queries so they're not taking such a performance hit.
Example resolvers:
const resolvers = {
Query: {
user: (_, values) => User.findOne(formatQuery(values))
.then(getDataValues),
},
Playthrough: {
score: ({ playthroughId }) => Score.findOne(formatQuery({ playthroughId }))
.then(getDataValues),
},
User: {
playthroughs: ({ userId }, { take }) => Playthrough.findAll(formatQuery({ userId, take, order: 'playthroughId DESC' }))
.then(getAllDataValues),
},
}
In addition to graphql, facebook has also released a much lesser known project, dataloader.
What it does it batch several requests in the same tick into one. So your code would be something like
Of course, having a load for each field is going to be tedious. So instead you can use dataloader-sequelize, which wrap all calls to association.get (i.e.
Playthrough.getScores()
) and calls to findOne / findById to dataloader calls, so several calls are batched in one.Since you are building a graphql API backed by sequelize, you might also be interested in https://github.com/mickhansen/graphql-sequelize/, which provides sequelize specific helpers for grahpql, and uses dataloader-sequelize below the hood