Data Loaders (the N+1 problem) - GRAPHQL API IN .NET w/ HOT CHOCOLATE #6

SingletonSean
5 Feb 202216:52

Summary

TLDRThis video script discusses optimizing GraphQL application performance by integrating a DataLoader to address the 'n plus one problem'. It covers removing unnecessary joins, fetching data only when requested, and demonstrating how DataLoaders can batch multiple queries into a single database request, ultimately improving efficiency.

Takeaways

  • πŸ”§ The video discusses performance considerations when integrating a GraphQL application with a database, specifically focusing on query optimization to prevent frequent or inefficient database hits.
  • πŸ€” The 'n plus one problem' in GraphQL is highlighted, where multiple queries are made for each item in a list, leading to performance degradation.
  • πŸ”„ To address the n plus one problem, the video introduces the use of a DataLoader to batch multiple queries into a single database request, improving efficiency.
  • πŸ›  The script demonstrates removing unnecessary joins in the database queries to prevent over-fetching data when not required by the GraphQL client.
  • πŸ“š The importance of conditional data fetching is emphasized, where data is fetched only when requested by the client to avoid unnecessary database hits.
  • πŸ”§ The process of creating a service and repository for instructors is shown, to handle database operations related to instructor data separately from courses.
  • πŸ”„ The concept of using a DataLoader is further explained by creating an 'InstructorDataLoader' that batches queries for multiple instructor IDs into one database call.
  • πŸ“ The script covers the implementation of the DataLoader in the GraphQL resolver, showing how to pass the DataLoader into the resolver and use it to fetch data.
  • πŸ”— The video explains how to pass data from one resolver to a nested resolver using a property on a class, which can be included or excluded from the GraphQL schema.
  • πŸ›  The process of creating a method in the repository to handle batch fetching of instructors by multiple IDs is detailed, which is crucial for the DataLoader to function.
  • πŸ” The script concludes with a demonstration of the DataLoader in action, showing how it reduces the number of database hits from multiple to a single query for all required data.

Q & A

  • What is the 'n plus one problem' in the context of GraphQL?

    -The 'n plus one problem' in GraphQL refers to a performance issue where a single query returns a list of items, and for each item in the list, an additional query is made to fetch related data. This results in n+1 queries being executed, which can significantly degrade performance.

  • Why is over-fetching data a concern in GraphQL?

    -Over-fetching data in GraphQL is a concern because it can lead to unnecessary network traffic and database load, which can impact the performance of the application. It happens when more data is requested than what is actually needed by the client.

  • How does a DataLoader help in improving GraphQL query performance?

    -A DataLoader helps in improving GraphQL query performance by batching multiple requests for the same resource into a single query to the database. This reduces the number of database hits and solves the 'n plus one problem' by fetching all related data in one go.

  • What changes were made to the Courses repository in the script?

    -In the script, the joins on the Instructor and Students tables were removed from the Courses repository to prevent unnecessary data fetching when the client does not request that data.

  • Why can't the properties for Instructor and Student be removed from the Course DTO?

    -The properties for Instructor and Student cannot be removed from the Course DTO because they are used to describe the relationships between tables in the schema of the application, which is necessary for the GraphQL framework to understand the data structure.

  • How is the Instructor data fetched in the script's resolver?

    -The Instructor data is fetched in the resolver by implementing a service that hits the database to retrieve the Instructor information only when the GraphQL client requests it, thus avoiding over-fetching.

  • What is the purpose of creating a separate Instructor repository in the script?

    -The purpose of creating a separate Instructor repository is to encapsulate the data access logic for Instructor entities and to facilitate the use of DataLoader for batching queries to improve performance.

  • How does the script demonstrate passing data from one resolver to a nested resolver?

    -The script demonstrates passing data from one resolver to a nested resolver by defining a property on the query type that can be used in the nested resolver, allowing the Instructor ID to be passed down to the Instructor resolver.

  • What is the role of the Instructor DataLoader in the script?

    -The Instructor DataLoader in the script is used to batch multiple requests for Instructor data into a single database query, thus solving the 'n plus one problem' and improving the efficiency of data fetching.

  • How does the script address the potential inefficiency of making two separate database queries?

    -The script addresses the potential inefficiency by using a DataLoader to batch all the Instructor queries into one database request, reducing the number of database hits and improving performance.

  • What is the trade-off mentioned in the script regarding the use of joins versus separate queries?

    -The trade-off mentioned is that while using joins might be more efficient when querying for related data, making separate queries can be faster when the related data is not needed, as it avoids unnecessary data fetching.

Outlines

00:00

πŸ” Optimizing GraphQL Queries with DataLoader

In this segment, the focus is on optimizing a GraphQL application's performance when querying a database. The issue of over-fetching data and the 'n plus one' problem are discussed, where multiple queries are made for each item in a list. The solution proposed is the use of a DataLoader to batch these queries. The speaker demonstrates how to integrate a DataLoader into a GraphQL application, starting with removing unnecessary joins in the database queries to prevent over-fetching. The process involves modifying the repository to fetch data only when requested by the client, thus avoiding unnecessary database hits. The speaker also shows how to implement database logic in a service and use the Instructor repository to fetch data efficiently.

05:01

πŸ”— Passing Data Between Resolvers in GraphQL

This paragraph delves into the mechanics of passing data between resolvers in a GraphQL application. The speaker explains how to pass the instructor ID from the root courses resolvers to nested resolvers using a property on the query type. Initially, the instructor ID is considered for GraphQL ignore, but the speaker reconsiders and decides to leave it in the schema for direct querying. The process involves defining a property on the query type, mapping the instructor DTO to an instructor type, and setting the instructor ID in the course type. The speaker also demonstrates the 'n plus one' problem by executing a query for all courses and observing the number of times the database is hit, highlighting the inefficiency of multiple queries for each item in a list.

10:03

πŸš€ Implementing DataLoader to Solve n plus One Problem

The speaker introduces the DataLoader concept to address the 'n plus one' problem, which involves making multiple queries for each item in a list. The DataLoader is implemented by creating a new folder for data loaders and defining an Instructor DataLoader that inherits from BatchDataLoader. The DataLoader is designed to batch all queries for instructors into a single database request. The speaker demonstrates how to use the DataLoader in the course type resolver, showing how it batches queries for instructor IDs into one query. The implementation involves registering the DataLoader in the Startup.cs file and using it in the course type to fetch instructors efficiently. The speaker also discusses the potential for using DataLoaders when dealing with data from different databases or APIs, emphasizing their utility in such scenarios.

15:06

πŸ“š Summary of Database Query Optimization Techniques

In the final paragraph, the speaker summarizes the steps taken to optimize database queries in a GraphQL application. The process included removing unnecessary joins in the courses repository to speed up queries when instructors are not needed, demonstrating the trade-off between speed and efficiency based on query requirements. The speaker also discusses the use of DataLoader to batch requests for instructor IDs into a single database query, effectively solving the 'n plus one' problem. The speaker emphasizes the importance of using DataLoaders in scenarios where data is spread across different databases or APIs, and invites viewers to apply these techniques to their own applications. The segment concludes with an invitation for feedback and a reminder to subscribe or become a member for more content.

Mindmap

Keywords

πŸ’‘GraphQL

GraphQL is a query language for APIs and a runtime for executing those queries against your data. It allows clients to define the structure of the data required, and exactly the same structure of the data is returned from the server. In the video, GraphQL is used as the interface through which the application interacts with the database, and performance issues like the 'n plus one problem' are discussed in the context of GraphQL queries.

πŸ’‘Database Integration

Database integration refers to the process of connecting an application with a database system to manage and manipulate data. In the script, the focus is on the considerations and challenges that arise when a GraphQL application is integrated with a database, such as query optimization and performance.

πŸ’‘N plus One Problem

The 'n plus one problem' is a common performance issue in applications that use GraphQL, where a single initial query results in multiple subsequent queries, one for each item in a list returned by the initial query. The video demonstrates this problem with a GraphQL application, showing how it can lead to excessive database hits and how it can be mitigated using a DataLoader.

πŸ’‘DataLoader

DataLoader is a utility that helps batch multiple requests to a data source, such as a database, into a single request, thus reducing the number of database hits and improving performance. The script explains how to implement a DataLoader in a GraphQL application using Hot Chocolate to solve the 'n plus one problem'.

πŸ’‘Hot Chocolate

Hot Chocolate is a GraphQL server for .NET that allows developers to build GraphQL APIs. In the video, Hot Chocolate is used as the GraphQL framework for the application, and the script walks through the process of integrating a DataLoader to optimize database queries.

πŸ’‘Entity Framework

Entity Framework is an object-relational mapper (ORM) for .NET that enables developers to work with a database using .NET objects, eliminating the need for most of the data-access code that developers usually need to write. The script mentions Entity Framework in the context of executing joins on database tables, which is later optimized using a DataLoader.

πŸ’‘DTO (Data Transfer Object)

A Data Transfer Object (DTO) is an object that carries data between processes, often used in application layers. In the video, the script discusses how DTOs are used to describe the relationships between tables in the application's schema and how they are used in the context of GraphQL resolvers.

πŸ’‘Resolver

In GraphQL, a resolver is a function that fetches the data for a particular field in a GraphQL query. The script explains how resolvers are used in the application to fetch data from the database, and how they are optimized by fetching only the required data when requested by the client.

πŸ’‘Batch Data Loading

Batch data loading is the process of collecting multiple data requests and executing them together to reduce the number of individual requests made to a data source. The script demonstrates the creation of a custom DataLoader to batch load instructor data, which is a key part of solving the 'n plus one problem'.

πŸ’‘Green Donut

Green Donut is a .NET library that provides DataLoader implementations. It is mentioned in the script as the underlying library that Hot Chocolate uses to implement DataLoader, which helps in batching database queries.

πŸ’‘Service Attribute

In the context of .NET and dependency injection, the Service Attribute is used to mark a method parameter as a service that should be injected by the dependency injection container. The script describes using the Service Attribute to inject the Instructor Repository into a resolver method in Hot Chocolate.

Highlights

Integration of a hot chocolate GraphQL application with a database leads to performance considerations.

GraphQL can suffer from the 'n plus one problem' where multiple queries are made for a single result.

Data loaders are introduced to solve the inefficiency of multiple queries in GraphQL.

Removing unnecessary joins in the courses repository to prevent overfetching data.

Adjusting the course DTO to return null for instructor and student properties when not queried.

Demonstration of fetching instructor data only when requested by the GraphQL client.

Introduction of a new instructor repository to handle database operations for instructors.

Using the instructor repository to fetch instructor data in the course type resolver.

Passing the instructor ID from the course DTO to the nested resolver for fetching data.

Discussion on the trade-off between removing joins and making separate database queries.

Implementation of a custom data loader to batch multiple instructor queries into one.

Creating a 'get many by ids' method in the instructor repository for batch querying.

Registering the instructor data loader in the startup configuration for use in the application.

Using the data loader in the course type to load instructor data efficiently.

Explanation of how to pass a list of keys to the data loader for batching multiple requests.

Demonstration of the n plus one problem and its solution using the data loader.

Summary of the process, including the removal of joins, resolver adjustments, and data loader implementation.

Highlighting the importance of data loaders in scenarios where database joins are not possible.

Encouragement for viewers to apply the demonstrated techniques to their own applications.

Transcripts

play00:00

last time we integrated our hot

play00:01

chocolate graphql application with a

play00:04

database now whenever you integrate with

play00:05

the database you have to start thinking

play00:07

about your application's performance

play00:10

when executing queries against the

play00:11

database are we executing queries too

play00:14

often are our queries not optimized are

play00:17

we over fetching data and this is

play00:19

definitely a big problem in graphql

play00:22

because sometimes we suffer from

play00:23

something called the n plus one problem

play00:25

where we make one query and then we get

play00:28

a bunch of results and say it's a list

play00:29

of results well then for every item in

play00:32

that list we have to make another query

play00:35

so if you get n items back from the list

play00:37

you're gonna have to make n more queries

play00:40

and in graphql we solve that with a data

play00:43

loader so in this video i'm going to

play00:44

make some performance adjustments and we

play00:47

are going to integrate a data loader to

play00:49

make our queries more efficient so first

play00:52

off i want to head into the courses

play00:54

repository and what i did last time was

play00:57

i included all of this data so what this

play00:59

is telling entity framework to do is to

play01:01

execute joins on the instructor table

play01:04

and the students table but what if i

play01:07

query for a course and i don't ask for

play01:10

that data back well then i'm doing this

play01:12

join for no reason so for this demo i'm

play01:14

gonna get rid of these joints so let me

play01:17

just clear those out and all we're gonna

play01:19

get back is the courses now this is kind

play01:21

of weird because we're returning this

play01:23

course dto and it has properties for the

play01:26

instructor and student and they're going

play01:27

to be null so ideally i would just

play01:29

remove these but i can't do that because

play01:31

i'm using all these dtos to describe my

play01:34

nad framework schema so these describe

play01:36

the relationships between my tables so

play01:38

can't remove those so ideally i would

play01:40

map this to like some other object where

play01:42

i didn't have those properties but

play01:43

anyways we're not going to be including

play01:46

that data it's going to be null and same

play01:48

for get by id and that should be

play01:50

everything we have to change here so now

play01:52

let's head into our query and as you can

play01:54

see whenever we get a course

play01:57

we're grabbing data from our course dto

play02:01

which has an instructor dto but this

play02:03

instructor dto is going to be gnaw so we

play02:05

can't really do this let's just let's

play02:08

just get rid of that and same for get

play02:10

course by id let's get rid of that too

play02:13

so now our course type is going to

play02:16

return null for the instructor which is

play02:18

okay if we're not querying for the

play02:20

instructor but if we are querying for

play02:23

the instructor we're going to get an

play02:24

exception because we can't allow this

play02:26

value to be null plus we should return

play02:28

the data because the client is asking

play02:30

for it so what we're going to do is

play02:33

fetch the data in our course type so

play02:35

we're going to open this up as a

play02:37

resolver and inside here we're going to

play02:39

hit our database and get the instructor

play02:41

back so essentially what we're doing is

play02:44

only fetching the instructor if the

play02:46

graphql client is asking for the

play02:48

instructor so no overfetching but we are

play02:50

gonna have to hit our database again

play02:52

here

play02:53

so let's actually implement that

play02:56

database logic i'm gonna put this into a

play02:58

service let's put a new folder in here

play03:00

i'll call this instructors and similar

play03:02

to how we had a courses repository we're

play03:05

going to have an

play03:06

instructor's

play03:09

repository there we go and in fact i'm

play03:12

just going to copy

play03:13

some of this stuff from my courses

play03:15

repository because we're going to need

play03:16

this db context factory and even some of

play03:19

these methods are going to be the same

play03:20

so i'm just going to copy everything

play03:22

from get by id up to the context factory

play03:26

field

play03:27

and paste that in my repository and

play03:30

let's go through and rename everything

play03:32

import everything we need so all good

play03:34

here constructor that takes our context

play03:36

factory and then we're not going to have

play03:38

a get all method we're going to have

play03:40

something similar in the future but we

play03:42

are going to have a get by id and this

play03:44

is going to return an instructor dto

play03:46

we're going to pass in an instructor id

play03:49

we'll create our db context and then

play03:52

we'll take our instructor's db set on

play03:54

our db context

play03:56

and we'll get the first instructor where

play03:57

their id matches the instructor

play04:00

that we pass in that should be all good

play04:02

for our repository this is all going to

play04:04

change once we implement our data loader

play04:07

to optimize our data fetching but let me

play04:10

head into my startup.cs and add the

play04:13

instructors repository and import that

play04:16

and now we're ready to use this

play04:18

repository

play04:19

to fetch the instructor in our course

play04:21

type so we're going to need our

play04:23

instructor repository passed into our

play04:26

resolver i think having it as a

play04:29

parameter and using the service

play04:31

attribute is going to be the easiest way

play04:32

to do this so we don't have to have a

play04:34

constructor and pass that in it'll just

play04:36

get injected into this method by hot

play04:38

chocolate so we'll take the instructor

play04:42

repository

play04:43

that's what we want as the parameter

play04:45

here and this is now going to be an

play04:47

async method because we're hitting our

play04:48

database and all we're going to do is

play04:50

take our repository

play04:52

and get an instructor by id and pass in

play04:55

the instructor id and return that from

play04:58

this method but the instructor id we

play05:01

don't even have that how are we going to

play05:02

get that so essentially what we have to

play05:04

do is pass the instructor id on this

play05:07

course dto from our root courses

play05:10

resolvers

play05:11

down to our course type resolver so the

play05:14

way to pass data down to our nested

play05:16

resolvers is actually defining a field

play05:19

on our query type that we can use in

play05:21

this resolver so we want the instructor

play05:24

id in this method we're just going to

play05:25

define a property for it so a property

play05:28

it's going to be a good because it's the

play05:29

instructor id we'll call it that

play05:32

instructor id now since this instructor

play05:34

id

play05:35

is just a property that we're using to

play05:38

pass the id down to this resolver i

play05:41

don't really want this as part of my

play05:43

graphql schema so i am gonna have a

play05:45

graphql ignore here so it's ignored from

play05:48

the schema

play05:49

because if they want the instructor id

play05:52

then they can just query for the

play05:54

instructor actually now i think about it

play05:56

if they want the instructor id

play05:58

why not just let them query that so that

play06:01

they don't have to query the entire

play06:02

instructor so on that note maybe we can

play06:05

just leave it as part of our schema

play06:06

don't have to ignore it but anyways now

play06:08

that we have the instructor id as a

play06:10

property on this class we can pass that

play06:13

to our get by id method on our

play06:15

repository inside of this resolver and

play06:18

we get an error here uh because i forgot

play06:21

we have to do our mapping so this

play06:22

returns an instructor dto and we have to

play06:26

map that to an instructor type so this

play06:28

mapping is pretty straightforward all we

play06:30

have to do is instantiate our instructor

play06:33

type and pass in all of these properties

play06:36

so the id comes from our dto and i think

play06:39

we got three other properties on here

play06:41

first name last name

play06:43

and salary grab those out of our dto i

play06:47

really wish i had automapper set up

play06:50

we're going to do that eventually but

play06:51

anyways now we're ready to demonstrate

play06:53

the n plus 1 problem so i'm going to put

play06:56

a breakpoint

play06:58

right here in this instructor resolver

play07:00

and i am going to hit

play07:02

the query for all courses and let's see

play07:06

how many times we hit this breakpoint

play07:07

all right so first i'm going to create a

play07:09

bunch more courses

play07:11

so try and get some more data in my

play07:12

database they all have the same name but

play07:14

that's fine just want to demonstrate

play07:16

this

play07:17

and now we're going to get all courses

play07:19

so let's execute that all right so we

play07:22

hit a breakpoint in our repository we're

play07:23

going to get the instructor

play07:26

and oh the instruct oh i know what

play07:28

happened so the instructor id

play07:30

is just an empty guide because we never

play07:34

set the instructor id

play07:36

on our course type so we never set this

play07:40

property the way we need to do this we

play07:42

have to actually pass that instructor id

play07:44

down that is gonna be

play07:46

in our courses query so we're gonna have

play07:48

to set the instructor id to

play07:52

the instructor id that we get back

play07:54

from our course dtos and same thing for

play07:57

our other resolver down here let's try

play07:59

this again whoops wrong property name

play08:01

here fix that and let's get courses all

play08:04

right so we hit the breakpoint the

play08:05

instructor id was set that's better so

play08:08

let's continue all right so this is the

play08:10

second time third time fourth time fifth

play08:13

time six time seven all right so seven

play08:16

times i think we hit the database so

play08:19

that explains that n plus one so hitting

play08:22

the database end times

play08:24

for the instructor of a course and then

play08:26

hitting the database one more time just

play08:28

to get all the courses so ideally i

play08:31

don't want to do this i want to hit the

play08:32

database once to get all the courses

play08:35

and then hit the database just one more

play08:38

time to resolve all the instructors that

play08:41

i need

play08:41

for the courses so the way to do this is

play08:44

to use a data loader so that we can

play08:46

batch all the instructor queries into

play08:48

just one database query for all of our

play08:52

courses so data loaders are actually

play08:54

built into the hot chocolate package i

play08:56

think it implements the data litters

play08:58

using a sibling package called green

play09:00

donut continuing the little name theme

play09:03

we got going on here with hot chocolate

play09:05

strawberry shake etc anyways let's

play09:07

create a new folder in our project for

play09:10

data loaders i assume you could put this

play09:12

in your services folder too but i'm just

play09:14

going to drop it in a new folder and

play09:16

inside here

play09:18

we are going to have our instructor data

play09:20

loader so create that and we're going to

play09:23

inherit from batch data loader so that

play09:26

makes sense because we're batching all

play09:28

of our queries for instructors into just

play09:30

one

play09:31

request to our database and this is a

play09:33

generic type it takes a key type and a

play09:36

value type so the key type is going to

play09:38

be a guide because we're querying for

play09:41

instructors by id and the id is a good

play09:45

so that is our key and the value we're

play09:46

getting back is

play09:48

our instructor dto so import that and

play09:52

let's implement this class and we also

play09:55

are going to have to generate a

play09:56

constructor to pass down to this base

play09:58

class so let's do that and then this

play10:00

class is also going to have to use

play10:03

our instructor repository because

play10:06

obviously we're gonna have to hit our

play10:07

database to actually get our instructors

play10:09

back so let's get a field for that going

play10:11

and just resolve that in the constructor

play10:13

so add that as a parameter and now we're

play10:15

good to go so this is gonna be an async

play10:18

method because we're going to hit our

play10:19

database and we get these keys passed in

play10:22

as a parameter and these keys represent

play10:24

all the instructor ids

play10:27

that we want to batch query for so we

play10:29

are going to pass all of those keys to

play10:31

our instructor's repository so instead

play10:33

of get by id we'll have another method

play10:35

that can take multiple keys and we'll

play10:38

call this get

play10:39

many by ids and just pass in our

play10:42

instructor ids so we're going to get

play10:44

back an i enumerable for all the

play10:46

instructor dtos so now let's generate

play10:50

this so this is going to be async i

play10:52

guess i should have awaited that method

play10:55

in our data later so it would have

play10:56

generated all that but anyways we're

play10:58

going to take our db context again

play11:00

so let's just paste that in there we're

play11:02

getting our instructor ids passed as a

play11:04

parameter and we're going to use these

play11:06

to get all the instructors for these ids

play11:10

so obviously instead of first or default

play11:12

we are going to use a where clause here

play11:15

and we only want the instructor if the

play11:18

instructor's id is inside of our

play11:21

instructor ids

play11:23

list here so we want to check if the

play11:25

instructor ids list contains the

play11:27

instructor id and then we'll execute

play11:30

that query with two list async so this

play11:33

will do the batch query for all the

play11:35

instructors so we should only hit this

play11:37

once to get all of our instructors now

play11:40

back in our data later let's actually

play11:42

use this so we're gonna have to await

play11:44

this and now all we have to do is

play11:46

convert these instructors to a

play11:47

dictionary that maps the instructor id

play11:50

to the instructor so that's super easy

play11:52

with some link we can just take the

play11:54

instructor's eye in the umbrable and do

play11:56

a to dictionary and the key for the

play11:59

dictionary is going to be the instructor

play12:01

id all right that is epic so let's go

play12:05

into our startup.cs we're all done with

play12:07

our data loader

play12:08

and are going to register this

play12:12

as scoped so the instructor

play12:15

data loader and now that is registered

play12:18

let's head back to our course type and

play12:20

we are going to get our instructor data

play12:23

loader resolved in here and we're going

play12:26

to use that data loader and that has a

play12:28

method to load async so load async takes

play12:32

the id of the instructor that we want to

play12:35

load so when we hit this resolver like

play12:38

seven times end times or whatever the

play12:40

data letter is going to batch all of the

play12:42

queries for the instructors into just

play12:44

one query but this method also takes a

play12:47

cancellation token so let's just pass in

play12:50

an empty one so we can do cancellation

play12:52

token

play12:53

import that

play12:55

and just specify none and then the other

play12:57

thing i wanted to point out before we

play12:58

try this out which is super exciting

play13:01

is that you can also pass in

play13:03

a list of keys right here obviously we

play13:06

don't have to do that now because

play13:07

there's only one instructor but we would

play13:09

definitely want to do that if we wanted

play13:10

to bachelor these students we would want

play13:13

to pass in all of the student ids into

play13:16

this load method although i don't even

play13:18

think that would be efficient based on

play13:20

our schema and how the students

play13:21

relationship is set up let's finally run

play13:24

this let's start the api let's execute

play13:28

this let me put one more breakpoint in

play13:30

the instructor resolver and let's

play13:32

execute all right so we're hitting our

play13:34

data later one two three four five six

play13:39

now we are hitting our database to get

play13:41

all of the instructors for all of our

play13:44

courses so instructor ids there's only

play13:46

one in here and i think that's because

play13:48

all of our courses have the same

play13:50

instructor so this actually isn't going

play13:52

to be as fun as i thought but regardless

play13:54

we're only hitting our database once to

play13:57

load all of our course instructors so

play13:58

let's continue uh we timed out okay but

play14:01

that's okay let's run it again let's see

play14:03

only hitting the database once all right

play14:05

there we go continue

play14:07

one hit on the database and we get all

play14:09

of the instructors back so yeah we only

play14:12

have one instructor maybe we can add

play14:14

another one real quick for fun so

play14:16

another instructor sean singleton

play14:18

100 salary let me just copy this old id

play14:22

paste that in here change it around a

play14:24

little bit let me copy it as well

play14:27

let's save this table i think we're good

play14:29

let's put a breakpoint back in our

play14:31

repository let's start this we're gonna

play14:33

have to create a new course

play14:35

that points to

play14:37

our other instructor so we can do that

play14:39

set the instructor id there we go

play14:42

created and now let's get our courses so

play14:45

hit that breakpoint and we got two

play14:47

instructor ids now so we batch load all

play14:50

of those in just one database query and

play14:53

there we go got back all of our data so

play14:55

we've solved the n plus one problem

play14:57

instead of n plus one database queries

play15:00

we now have one database query to get

play15:02

all the courses and then another single

play15:06

database query to get all of the

play15:08

instructors for the courses so just to

play15:10

summarize in our courses repository

play15:13

we've removed those joins on the

play15:15

instructors and students table we didn't

play15:17

really have to do that i feel like the

play15:19

joints would definitely be more

play15:20

efficient than making two separate

play15:23

database queries so one for all the

play15:25

courses and one for all the instructors

play15:26

but still if we're not querying for the

play15:28

instructors then this is definitely

play15:30

gonna be faster now i guess it's all

play15:32

kind of like a trade-off so if you don't

play15:33

want the instructor then now this is

play15:35

faster but if you do want the instructor

play15:38

then

play15:39

it's gonna be slower because we have two

play15:41

queries regardless i just want to show

play15:42

off data loaders because sometimes you

play15:44

just have to use a data later like what

play15:46

if our instructors were in a completely

play15:49

different database or on a completely

play15:52

different api then joining the data on a

play15:54

database query wouldn't even be possible

play15:56

so we would have to use the data later

play15:58

in that case anyways i'm just rambling

play16:00

at this point so we remove the joins on

play16:02

the course's query and now we query the

play16:04

instructor in a resolver i also

play16:06

demonstrated how you can pass data

play16:08

from one resolver to a nested resolver

play16:11

using a property which you could also

play16:13

ignore from your schema if you wanted to

play16:15

and then demonstrated the n plus one

play16:17

problem which we eventually solved by

play16:20

creating our custom data letter that

play16:24

batches a request for all of our

play16:25

instructor ids into just one database

play16:28

request so hopefully you can apply this

play16:30

to your own application so that you're

play16:32

not hitting the database n times because

play16:34

who knows n could be like a thousand

play16:36

definitely want to use a data later

play16:38

anyways if you have any questions

play16:39

criticisms or concerns be sure to leave

play16:41

them below in the comments section if

play16:43

you enjoyed the video or enjoying the

play16:45

channel consider becoming a member link

play16:47

in the description other than that leave

play16:49

a like or subscribe for more thank you

Rate This
β˜…
β˜…
β˜…
β˜…
β˜…

5.0 / 5 (0 votes)

Related Tags
GraphQLDatabasePerformanceDataLoaderHot ChocolateQuery OptimizationN+1 ProblemData FetchingInstructor RepositoryCourse Repository