orm - tuningujemy podejście do mapowania

16
ORM and.. Bad habits Patryk Szlagowski

Upload: 3camp

Post on 07-Jan-2017

2.715 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: ORM - tuningujemy podejście do mapowania

ORM and..Bad habits

Patryk Szlagowski

Page 2: ORM - tuningujemy podejście do mapowania

Patryk SzlagowskiBackend Developer at Logisfera Nova - lsn.io

@abdulklarapl

Captain at FunkyMonkeyLabs

Page 3: ORM - tuningujemy podejście do mapowania

1. ORM - what is it?

2. Problem 1 - greedy fetching3. Problem 2 - „lets map everything”

4. Performance table5. Conclusions

6. Conclusions - moar

Page 4: ORM - tuningujemy podejście do mapowania

1. ORMIn one picture

ORMDB applicationDBAL*

Page 5: ORM - tuningujemy podejście do mapowania

/** * @Route("/", name="homepage") */public function indexAction(Request $request) { return $this->render('default/index.html.twig', array( 'news' => $this->getDoctrine() ->getRepository('AppBundle:Post') ->findAll() )); }

2. Problem 1 - greedy fetching

Page 6: ORM - tuningujemy podejście do mapowania

/** * @return Post[] */public function getAll() { $qb = $this->createQueryBuilder("post"); $qb ->select("post, author, role, category, comments, commentsAuthor, commentsAuthorRole") ->join("post.category", "category") ->join("post.author", "author") ->join("author.role", "role") ->join("post.comments", "comments") ->join("comments.author", "commentsAuthor") ->join("commentsAuthor.role", "commentsAuthorRole"); return $qb->getQuery()->getResult(); }

That is nice. But wait.. How is possible, that results can be mapped to relations from this?

Let’s add custom method in repository and control the joins

2. Problem 1 - greedy fetching

Page 7: ORM - tuningujemy podejście do mapowania

2. Problem 1 - greedy fetching

Page 8: ORM - tuningujemy podejście do mapowania

SELECT {fields}FROM post p0_INNER JOIN dictionary_item d1_ ON p0_.category_id = d1_.idINNER JOIN person p2_ ON p0_.author_id = p2_.idINNER JOIN dictionary_item d3_ ON p2_.role_id = d3_.idINNER JOIN COMMENT c4_ ON p0_.id = c4_.post_idINNER JOIN person p5_ ON c4_.author_id = p5_.idINNER JOIN dictionary_item d6_ ON p5_.role_id = d6_.id

That is I expected. 3 rows for 1 post (3 comments). ORM mapped columns to many objects, grouped by primary key.

But let’s imagine, what if we have 100 records (A) with relation to B (10 records each) AND B-C (with another 10 records for each B)? 10000 records to map.

2. Problem 1 - greedy fetchingWhat’s going on?

Page 9: ORM - tuningujemy podejście do mapowania

What if..I tell you, that you can get all of the rows by one query, without multiply results rows number?

IMPOSSIBRU

Page 10: ORM - tuningujemy podejście do mapowania

Cons• PostgreSQL • JSON functions • complicated query • slower than simple

query

Pros

• JSON response • whole object in one row • what you see in results,

it’s what you get in app

SELECT array_to_json( array_agg( row_to_json({alias}) ) )FROM ( {subquery}) AS {alias}

SELECT array_to_json(array_agg(row_to_json(results)))FROM ( SELECT post.id, post.create_date, post.content, post.title, (SELECT row_to_json(author) FROM ( SELECT person.*, ( SELECT row_to_json(role) FROM ( SELECT * FROM dictionary_item di WHERE di.id = person.role_id ) AS role ) AS role FROM person WHERE person.id = post.author_id ) as author) AS author, ( SELECT row_to_json(category) FROM dictionary_item category WHERE category.id = post.category_id ) as category, ( SELECT array_to_json(array_agg(row_to_json(comments))) FROM ( SELECT comment.title, comment.content, ( SELECT row_to_json(comment_author) FROM ( SELECT person.*, ( SELECT row_to_json(role) FROM ( SELECT * FROM dictionary_item di WHERE di.id = person.role_id ) AS role ) AS role FROM person WHERE person.id = comment.author_id ) AS comment_author ) AS author FROM comment where comment.post_id = post.id ) AS comments ) as commentsFROM post) AS results

Page 11: ORM - tuningujemy podejście do mapowania

3. Problem 2 - results mapping

ORMDataSource response

application model

REST response

In most cases

for what?

Page 12: ORM - tuningujemy podejście do mapowania

3. Problem 2 - results mapping

DataSource response

array/hashmap response REST response

In most cases

Page 13: ORM - tuningujemy podejście do mapowania

Built-in findAll function

Simple query with joins, mapped to

objects

array_to_json query, mapped to objects

array_to_json query, no mapping, return

in REST Api

query time 2326ms 52ms 101ms 111ms

memory usage 82MB 51MB 33.5MB 17.2MB

total (with render) time 7464ms 2100ms 1755ms 364ms

number of queries 4405 1 1 1

4. All about performance

* tested with 400 posts, 10 comments per post, one author per comment, author per post, label per category

Page 14: ORM - tuningujemy podejście do mapowania

5. ConclusionsQuery buildersQuery builders

$this->repository->findAll()

4405

trolololovs

$this->repository->customFindAll()

1

Page 15: ORM - tuningujemy podejście do mapowania

1. Maybe we should start using aggregating functions to get data from DB

2. If you don’t have to to transform DB response to object - don’t do it

3. Don’t use built-in functions such as findBy, findAll, findOne, sth, sth

4. Write your own functions with joins, groups to take control over the query

5. Remember about lazy loading

6. Conclusions

Page 16: ORM - tuningujemy podejście do mapowania

Thank youI want to talk with you