Doctrine 1.2 Optimization

7,903 views

Published on

Also covers a little Doctrine 2.0

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
7,903
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
43
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Doctrine 1.2 Optimization

  1. 1. Doctrine Optimizationphp|tek, May 25, 2011
  2. 2. Anna FilinaPHP Quebec - user group, organizerConFoo - non for profit Web conference, organizerFooLab Inc. - IT solutions for businesses, founderI write code
  3. 3. Content Doctrine 1.2 optimization Profiling tools Find bad DQL Fix bad DQL Doctrine 2.0 Share your DQL concerns
  4. 4. Tools Used Doctrine 1.2 MySQL 5.1 PHP 5.3 Xdebug eZ Components (now Zeta Components)
  5. 5. Database SchemaInvoice (2000 rows) Items (7000 rows) Tags (1-2 per item)
  6. 6. Let’s make it explode!
  7. 7. Two queries$query1 = Doctrine::getTable(Invoice) ->createQuery(inv) ->leftJoin(inv.Items.Tags) ->where(inv.number LIKE "%10") ->orderBy(inv.subtotal DESC);$query2 = Doctrine::getTable(Invoice) ->createQuery(inv) ->leftJoin(inv.Items.Tags);
  8. 8. Execution Time AverageezcDebug timed each query 3xQuery 1: 0.20 secQuery 2: 16.26 secWhat’s taking so long?
  9. 9. MySQL or PHP?Query took 0.002 sec in MySQL~18,000 objects in PHPDoctrine hydrates results
  10. 10. Hydration ProcessCreate objectsCopy propertiesReindex resultsConvert results to multi-dimensional arrays/collectionsAnd lots of other good (and slow) things
  11. 11. Query VariationsNo tags: 9.21 sec->leftJoin(inv.Items);No relations: 2.39 sec (~4x faster);Limit results: 0.21 sec (~77x faster)->leftJoin(inv.Items.Tags);->limit(25);
  12. 12. Doctrine_Pager$pager = new Doctrine_Pager( $query, $page, $pageSize);$results = $pager->execute();
  13. 13. More Bad DQL Examples
  14. 14. Count$inv = Doctrine::getTable(Invoice) ->createQuery(inv) ->leftJoin(inv.Items) ->execute();$inv[0]->Items->count();
  15. 15. CountUsing left join: 8.91 sec->leftJoin(inv.Items);Using subquery: 2.39 sec->addSelect((SELECT COUNT(*) FROM InvoiceItem item WHERE item.invoice_id = inv.id ) AS num_items)$inv[0]->num_items;
  16. 16. MemoryUsing default hydration: 10.24 MB->execute();Using HYDRATE_ARRAY: 0.64 MB, ~16x less->execute(Doctrine_Core::HYDRATE_ARRAY);
  17. 17. Lazy LoadingRelations without leftJoin: 0.10 sec$invoice->Items[0]->Tags[0];Relations with leftJoin: 0.02 sec, 5x faster->leftJoin(inv.Items.Tags tag)Lazy loading especially bad when iterating
  18. 18. Lazy LoadingUsing relation: 0.03 sec$inv->Items[] = $item;Using associative entity: 0.00065 sec (~46x faster)$invoiceItem = new InvoiceItem();$invoiceItem->invoice_id = $inv->id;$invoiceItem->item_id = $item->id;
  19. 19. Lessons LearnedLimit resultsSelect only what neededUse COUNT subqueries where appropriateUse ARRAY hydration when possibleAvoid lazy-loading in most casesAlso look into database optimization(index columns, de-normalization, storage engine, etc.)This also applies to Doctrine 2.0
  20. 20. Doctrine 2.0
  21. 21. Lighter and Faster1 year of planning, 98% rewriteIndependent modelFaster hydration (3x)New lazy loading techniquesBatch processing
  22. 22. ExamplesHydrate the results on-demand in an iteration$iteratable = $query->iterate();foreach ($iteratable as $item) {}COUNT relationsCOUNT(inv.Items) ... GROUP BY inv.ItemsSmart batch saving$item1->persist();$item2->persist();$entityManager->flush();
  23. 23. Caching LayersAnnotations to ClassMetadataDQL to SQLSQL to Collection
  24. 24. ResourcesCode used in this talk:http://annafilina.com/blog/wp-content/uploads/doctrine-opt.zipTips from the Doctrine team:http://www.doctrine-project.org/projects/orm/1.2/docs/manual/improving-performance/enDerick Rethan’s “Profiling PHP Applications”Ligaya Turmelle’s “Optimizing MySQL Essentials”
  25. 25. Special thanks toGuilherme Blanco & Raphael Dohms

×