orm dont kill your db, developers do

115
http://www.flickr.com/photos/hoyvinmayvin/5103806609/ Database Developers ORM Guilherme Blanco Thursday, March 1, 2012

Upload: guilherme-blanco

Post on 09-May-2015

7.799 views

Category:

Technology


2 download

DESCRIPTION

Presentation gave at ConFoo 2012 (2012-03-01)As soon as you decide to use an ORM tool, one of the biggest factors is Rapid Application Development.Everything is wonderful during development phase, but when it hits production, performance doesn't work like you expect.You may think it's ORM's fault, your expected it to write as efficient queries as you manually do, but like guns, ORMs don't kill your database, developers do!This talk will go deep into Doctrine 2 ORM by exploring performance tips that can save your application from its deepest nightmare.

TRANSCRIPT

Page 1: ORM dont kill your DB, developers do

http://www.flickr.com/photos/hoyvinmayvin/5103806609/

Database

Developers

ORM

Guilherme BlancoThursday, March 1, 2012

Page 2: ORM dont kill your DB, developers do

ORMs donʼt kill your DB, developers do!

@guilhermeblanco

http://github.com/guilhermeblanco

Learning about good ORM practices on @guilhermeblanco

talk at @confooca!

InstaClick Inc.

Thursday, March 1, 2012

Page 3: ORM dont kill your DB, developers do

Agenda

http://www.flickr.com/photos/emerzh/3072428824/Thursday, March 1, 2012

Page 4: ORM dont kill your DB, developers do

General Rule

RTFMThursday, March 1, 2012

Page 5: ORM dont kill your DB, developers do

Dependency management

http://www.flickr.com/photos/ollesvensson/3694625903/Thursday, March 1, 2012

Page 6: ORM dont kill your DB, developers do

Dependency Management

Thursday, March 1, 2012

Page 7: ORM dont kill your DB, developers do

Dependency Managementnamespace App\Bundle\BlogBundle\Entity;

/** * @ORM\Entity */class Post{    /**     * @ORM\OneToMany(     *   targetEntity="AppComment:Comment",     *   mappedBy="post"     * )     */    protected $comments;}

namespace App\Bundle\CommentBundle\Entity;

/** * @ORM\Entity */class Comment{    /**     * @ORM\ManyToOne(     *   targetEntity="AppBlog:Post",     *   inversedBy="comments"     * )      */    protected $post;}

Thursday, March 1, 2012

Page 8: ORM dont kill your DB, developers do

Dependency Management

Thursday, March 1, 2012

Page 9: ORM dont kill your DB, developers do

Dependency Management

Thursday, March 1, 2012

Page 10: ORM dont kill your DB, developers do

Dependency Management

namespace App\Bundle\BlogBundle\Entity;

/** * @ORM\Entity */class Post{    // ...}

namespace App\Bundle\CommentBundle\Entity;

/** * @ORM\Entity */class Comment{    /**     * @ORM\ManyToOne(targetEntity="AppBlog:Post")     */    protected $post;}

Thursday, March 1, 2012

Page 11: ORM dont kill your DB, developers do

Fetch Mode

http://www.flickr.com/photos/comedynose/5318259802/Thursday, March 1, 2012

Page 12: ORM dont kill your DB, developers do

Fetch Mode

A fetching strategy is what ORM will use to retrieve associated objects if the application needs to navigate

through them

Thursday, March 1, 2012

Page 13: ORM dont kill your DB, developers do

Fetch Mode

Supported by all association types...

Thursday, March 1, 2012

Page 14: ORM dont kill your DB, developers do

Fetch Mode

• OneToOne

• OneToMany

• ManyToOne

• ManyToMany

Thursday, March 1, 2012

Page 15: ORM dont kill your DB, developers do

Fetch Mode

Available fetch modes...

Thursday, March 1, 2012

Page 16: ORM dont kill your DB, developers do

Fetch Mode

• EAGER

• LAZY (default)

• EXTRA_LAZY

Thursday, March 1, 2012

Page 17: ORM dont kill your DB, developers do

Fetch Mode

• EAGER

• LAZY (default)

• EXTRA_LAZY

An association (collection or attribute), is fetched immediately when owner is loaded

Thursday, March 1, 2012

Page 18: ORM dont kill your DB, developers do

Fetch Mode

• EAGER

• LAZY (default)

• EXTRA_LAZY

An association (collection or attribute), is fetched immediately when owner is loaded

An association (collection or attribute), is fetched when the application invokes

an operation over it

Thursday, March 1, 2012

Page 19: ORM dont kill your DB, developers do

Fetch Mode

• EAGER

• LAZY (default)

• EXTRA_LAZY

An association (collection or attribute), is fetched immediately when owner is loaded

An association (collection or attribute), is fetched when the application invokes

an operation over it

Individual elements from association are accessed from Database as needed. ORM

does not fetch the whole association unless it is absolutely necessary

Thursday, March 1, 2012

Page 20: ORM dont kill your DB, developers do

Fetch Mode/** * @ORM\Entity */class Post {    /**     * @ORM\ManyToOne(targetEntity="User", fetchMode="EAGER")     */    protected $author;

    /**     * @ORM\ManyToMany(targetEntity="Tags", fetchMode="EXTRA_LAZY")     * @ORM\JoinTable(name="posts_tags")     */    protected $tagList;}

/** * @ORM\Entity */class Comment {    /**     * @ORM\OneToMany(targetEntity="Post", fetchMode="LAZY")     * @JoinColumn(name="post_id", referencedColumnName="id")     */    protected $post;}

Thursday, March 1, 2012

Page 21: ORM dont kill your DB, developers do

Fetch Mode/** * @ORM\Entity */class Post {    /**     * @ORM\ManyToOne(targetEntity="User", fetchMode="EAGER")     */    protected $author;

    /**     * @ORM\ManyToMany(targetEntity="Tags", fetchMode="EXTRA_LAZY")     * @ORM\JoinTable(name="posts_tags")     */    protected $tagList;}

/** * @ORM\Entity */class Comment {    /**     * @ORM\OneToMany(targetEntity="Post", fetchMode="LAZY")     * @JoinColumn(name="post_id", referencedColumnName="id")     */    protected $post;}

Deadly sin

Thursday, March 1, 2012

Page 22: ORM dont kill your DB, developers do

Querying

http://www.flickr.com/photos/pschadler/4932737690/Thursday, March 1, 2012

Page 23: ORM dont kill your DB, developers do

Querying

$query    = $entityManager->createQuery('    SELECT p       FROM Post p');$postList = $query->getResult();

foreach ($postList as $post) {    $tagList = $post->getTagList();

    foreach ($tagList as $tag) {        echo $tag->getName();    }}

Thursday, March 1, 2012

Page 24: ORM dont kill your DB, developers do

Querying

$query    = $entityManager->createQuery('    SELECT p       FROM Post p');$postList = $query->getResult();

foreach ($postList as $post) {    $tagList = $post->getTagList();

    foreach ($tagList as $tag) {        echo $tag->getName();    }}

N + 1 trolls?

Thursday, March 1, 2012

Page 25: ORM dont kill your DB, developers do

Querying

$query    = $entityManager->createQuery('    SELECT p, t       FROM Post p       LEFT JOIN p.tagList t');$postList = $query->getResult();

foreach ($postList as $post) {    $tagList = $post->getTagList();

    foreach ($tagList as $tag) {        echo $tag->getName();    }}

Thursday, March 1, 2012

Page 26: ORM dont kill your DB, developers do

Querying

$query    = $entityManager->createQuery('    SELECT p, t       FROM Post p       LEFT JOIN p.tagList t');$postList = $query->getResult();

foreach ($postList as $post) {    $tagList = $post->getTagList();

    foreach ($tagList as $tag) {        echo $tag->getName();    }}

Pardon? DQL is powerful! RTFM

Thursday, March 1, 2012

Page 27: ORM dont kill your DB, developers do

Querying

I know you all don’t trust me...

Thursday, March 1, 2012

Page 28: ORM dont kill your DB, developers do

Querying

...but take a look at its EBNF grammar...

Thursday, March 1, 2012

Page 29: ORM dont kill your DB, developers do

QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatementSelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]UpdateStatement ::= UpdateClause [WhereClause]DeleteStatement ::= DeleteClause [WhereClause]JoinAssociationPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField)AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpressionSingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpressionStateFieldPathExpression ::= IdentificationVariable "." StateField | SingleValuedAssociationPathExpression "." StateFieldSingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationFieldCollectionValuedPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* CollectionValuedAssociationFieldStateField ::= {EmbeddedClassStateField "."}* SimpleStateFieldSimpleStateFieldPathExpression ::= IdentificationVariable "." StateFieldSelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}*SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpressionUpdateClause ::= "UPDATE" AbstractSchemaName ["AS"] AliasIdentificationVariable "SET" UpdateItem {"," UpdateItem}*DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName ["AS"] AliasIdentificationVariableFromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}*SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*WhereClause ::= "WHERE" ConditionalExpressionHavingClause ::= "HAVING" ConditionalExpressionGroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}*OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]UpdateItem ::= IdentificationVariable "." (StateField | SingleValuedAssociationField) "=" NewValueOrderByItem ::= (ResultVariable | SingleValuedPathExpression) ["ASC" | "DESC"]GroupByItem ::= IdentificationVariable | SingleValuedPathExpressionNewValue ::= ScalarExpression | SimpleEntityExpression | "NULL"IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable)JoinVariableDeclaration ::= Join [IndexBy]RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariableJoin ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression ["AS"] AliasIdentificationVariable ["WITH" ConditionalExpression]IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpressionSelectExpression ::= IdentificationVariable | PartialObjectExpression | (AggregateExpression | "(" Subselect ")" | FunctionDeclaration | ScalarExpression) [["AS"] AliasResultVariable]SimpleSelectExpression ::= ScalarExpression | IdentificationVariable | (AggregateExpression [["AS"] AliasResultVariable])PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSetPartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}*ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}*ConditionalFactor ::= ["NOT"] ConditionalPrimaryConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"SimpleConditionalExpression ::= ComparisonExpression | BetweenExpression | LikeExpression | InExpression | NullComparisonExpression | ExistsExpression | EmptyCollectionComparisonExpression | CollectionMemberExpression | InstanceOfExpressionEmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpressionLiteral ::= string | char | integer | float | booleanInParameter ::= Literal | InputParameterInputParameter ::= PositionalParameter | NamedParameterPositionalParameter ::= "?" integerNamedParameter ::= ":" stringArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}*ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}*ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimaryArithmeticPrimary ::= SingleValuedPathExpression | Literal | "(" SimpleArithmeticExpression ")" | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings | FunctionsReturningDatetime | IdentificationVariable | InputParameter | CaseExpressionScalarExpression ::= SimpleArithmeticExpression | StringPrimary | DateTimePrimary | StateFieldPathExpression | BooleanPrimary | EntityTypeExpression | CaseExpressionStringExpression ::= StringPrimary | "(" Subselect ")"StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression | CaseExpressionBooleanExpression ::= BooleanPrimary | "(" Subselect ")"BooleanPrimary ::= StateFieldPathExpression | boolean | InputParameterEntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpressionSimpleEntityExpression ::= IdentificationVariable | InputParameterDatetimeExpression ::= DatetimePrimary | "(" Subselect ")"DatetimePrimary ::= StateFieldPathExpression | InputParameter | FunctionsReturningDatetime | AggregateExpressionAggregateExpression ::= ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" | "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedPathExpression) ")"CaseExpression ::= GeneralCaseExpression | SimpleCaseExpression | CoalesceExpression | NullifExpressionGeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END"WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpressionSimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END"CaseOperand ::= StateFieldPathExpression | TypeDiscriminatorSimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpressionCoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")"NullifExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")"QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")"BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpressionComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression )InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")"InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")")InstanceOfParameter ::= AbstractSchemaName | InputParameterLikeExpression ::= StringExpression ["NOT"] "LIKE" string ["ESCAPE" char]NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")"ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="FunctionDeclaration ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDateTimeFunctionsReturningNumerics ::= "LENGTH" "(" StringPrimary ")" | "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" | "ABS" "(" SimpleArithmeticExpression ")" | "SQRT" "(" SimpleArithmeticExpression ")" | "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | "SIZE" "(" CollectionValuedPathExpression ")"FunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP"FunctionsReturningStrings ::= "CONCAT" "(" StringPrimary "," StringPrimary ")" | "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" | "LOWER" "(" StringPrimary ")" | "UPPER" "(" StringPrimary ")"

Thursday, March 1, 2012

Page 30: ORM dont kill your DB, developers do

Querying

Since the letter size is 6, you may still not believe me

Thursday, March 1, 2012

Page 31: ORM dont kill your DB, developers do

Querying

let’s try a real world example!

Thursday, March 1, 2012

Page 32: ORM dont kill your DB, developers do

Querying

Do you know Facebook activity wall?

Thursday, March 1, 2012

Page 33: ORM dont kill your DB, developers do

Querying

Do you know Facebook activity wall?Let’s show it!

Thursday, March 1, 2012

Page 34: ORM dont kill your DB, developers do

SELECT e, a FROM Entry e JOIN e.wall w JOIN e.user u LEFT JOIN u.avatar av WHERE u = :user OR w IN ( SELECT uw FROM UserWall uw WHERE uw.user = :user OR uw.user IN ( SELECT CASE WHEN ua = us.subscriber THEN ub.id ELSE ua.id END FROM UserSubscription us JOIN us.friendship f JOIN f.userA ua JOIN f.userB ub WHERE us.muted = FALSE AND us.subscriber = :user AND f.status = 'Approved' ) ) OR w IN ( SELECT gw FROM GroupWall gw WHERE gw.group IN ( SELECT DISTINCT g.id FROM GroupSubscription gs JOIN gs.group g WHERE gs.subscriber = :user AND gs.muted = FALSE AND gs.status = 'Approved' ) ) ORDER BY e.created DESC

Thursday, March 1, 2012

Page 35: ORM dont kill your DB, developers do

SELECT e, a FROM Entry e JOIN e.wall w JOIN e.user u LEFT JOIN u.avatar av WHERE u = :user OR w IN ( SELECT uw FROM UserWall uw WHERE uw.user = :user OR uw.user IN ( SELECT CASE WHEN ua = us.subscriber THEN ub.id ELSE ua.id END FROM UserSubscription us JOIN us.friendship f JOIN f.userA ua JOIN f.userB ub WHERE us.muted = FALSE AND us.subscriber = :user AND f.status = 'Approved' ) ) OR w IN ( SELECT gw FROM GroupWall gw WHERE gw.group IN ( SELECT DISTINCT g.id FROM GroupSubscription gs JOIN gs.group g WHERE gs.subscriber = :user AND gs.muted = FALSE AND gs.status = 'Approved' ) ) ORDER BY e.created DESC

Entry you wrote

Thursday, March 1, 2012

Page 36: ORM dont kill your DB, developers do

SELECT e, a FROM Entry e JOIN e.wall w JOIN e.user u LEFT JOIN u.avatar av WHERE u = :user OR w IN ( SELECT uw FROM UserWall uw WHERE uw.user = :user OR uw.user IN ( SELECT CASE WHEN ua = us.subscriber THEN ub.id ELSE ua.id END FROM UserSubscription us JOIN us.friendship f JOIN f.userA ua JOIN f.userB ub WHERE us.muted = FALSE AND us.subscriber = :user AND f.status = 'Approved' ) ) OR w IN ( SELECT gw FROM GroupWall gw WHERE gw.group IN ( SELECT DISTINCT g.id FROM GroupSubscription gs JOIN gs.group g WHERE gs.subscriber = :user AND gs.muted = FALSE AND gs.status = 'Approved' ) ) ORDER BY e.created DESC

Entry you wrote

Entry was in your Wall

Thursday, March 1, 2012

Page 37: ORM dont kill your DB, developers do

SELECT e, a FROM Entry e JOIN e.wall w JOIN e.user u LEFT JOIN u.avatar av WHERE u = :user OR w IN ( SELECT uw FROM UserWall uw WHERE uw.user = :user OR uw.user IN ( SELECT CASE WHEN ua = us.subscriber THEN ub.id ELSE ua.id END FROM UserSubscription us JOIN us.friendship f JOIN f.userA ua JOIN f.userB ub WHERE us.muted = FALSE AND us.subscriber = :user AND f.status = 'Approved' ) ) OR w IN ( SELECT gw FROM GroupWall gw WHERE gw.group IN ( SELECT DISTINCT g.id FROM GroupSubscription gs JOIN gs.group g WHERE gs.subscriber = :user AND gs.muted = FALSE AND gs.status = 'Approved' ) ) ORDER BY e.created DESC

Entry you wrote

User is your friend, the friendship is approved and subscription is not muted

Entry was in your Wall

Thursday, March 1, 2012

Page 38: ORM dont kill your DB, developers do

SELECT e, a FROM Entry e JOIN e.wall w JOIN e.user u LEFT JOIN u.avatar av WHERE u = :user OR w IN ( SELECT uw FROM UserWall uw WHERE uw.user = :user OR uw.user IN ( SELECT CASE WHEN ua = us.subscriber THEN ub.id ELSE ua.id END FROM UserSubscription us JOIN us.friendship f JOIN f.userA ua JOIN f.userB ub WHERE us.muted = FALSE AND us.subscriber = :user AND f.status = 'Approved' ) ) OR w IN ( SELECT gw FROM GroupWall gw WHERE gw.group IN ( SELECT DISTINCT g.id FROM GroupSubscription gs JOIN gs.group g WHERE gs.subscriber = :user AND gs.muted = FALSE AND gs.status = 'Approved' ) ) ORDER BY e.created DESC

Entry you wrote

User is your friend, the friendship is approved and subscription is not muted

Entry was in your Wall

Group that you participate, is not muted and have an approved status

Thursday, March 1, 2012

Page 39: ORM dont kill your DB, developers do

Caching

http://www.flickr.com/photos/eszter/3851576235/Thursday, March 1, 2012

Page 40: ORM dont kill your DB, developers do

Caching

Doctrine supports 3 levels of caching...

Thursday, March 1, 2012

Page 41: ORM dont kill your DB, developers do

Caching

• Metadata cache

• Query cache

• Result cache

Thursday, March 1, 2012

Page 42: ORM dont kill your DB, developers do

Caching

• Metadata cache

• Query cache

• Result cache

Cache mapping of entities

Thursday, March 1, 2012

Page 43: ORM dont kill your DB, developers do

Caching

• Metadata cache

• Query cache

• Result cache

Cache mapping of entities

Cache DQL to SQL conversion

Thursday, March 1, 2012

Page 44: ORM dont kill your DB, developers do

Caching

• Metadata cache

• Query cache

• Result cache

Cache mapping of entities

Cache PDO result set

Cache DQL to SQL conversion

Thursday, March 1, 2012

Page 45: ORM dont kill your DB, developers do

Caching

$query   = $entityManager->createQuery('    SELECT p       FROM Post p');

$query->useResultCache(true, 600, 'find-all-posts');

$postList = $query->getResult();

Thursday, March 1, 2012

Page 46: ORM dont kill your DB, developers do

Indexing

http://www.flickr.com/photos/osuarchives/2659419894/Thursday, March 1, 2012

Page 47: ORM dont kill your DB, developers do

Indexing

Doctrine is able to hint the Schema Tool to generate database indexes on specified table columns

Thursday, March 1, 2012

Page 48: ORM dont kill your DB, developers do

Indexing/** * @ORM\Entity * @ORM\Table( *     name = "users", *     uniqueConstraints = { *         @ORM\UniqueConstraint( *             name    = "user_unique", *             columns = { "name" } *         ) *     }, *     indexes = { *         @ORM\Index( *             name    = "login_idx",  *             columns = { "name", "password" } *         ) *     } * ) */class User{    // ...}

Thursday, March 1, 2012

Page 49: ORM dont kill your DB, developers do

Indexing

@ORM\UniqueConstraint(    name    = "user_unique",     columns = { "name" })

CREATE UNIQUE INDEX user_unique ON TABLE users (name);

Thursday, March 1, 2012

Page 50: ORM dont kill your DB, developers do

Indexing

@ORM\Index(    name    = "login_idx",     columns = { "name", "password" })

CREATE INDEX login_idx ON TABLE users (name, password);

Thursday, March 1, 2012

Page 51: ORM dont kill your DB, developers do

Indexing

@ORM\Index(    name    = "login_idx",     columns = { "name", "password" })

CREATE INDEX login_idx ON TABLE users (name, password);

Some drivers restrict to 32 chars as index name

Thursday, March 1, 2012

Page 52: ORM dont kill your DB, developers do

Inheritance

http://www.flickr.com/photos/duanekeys/307005468/Thursday, March 1, 2012

Page 53: ORM dont kill your DB, developers do

Inheritance

Inheritance is a very deep topic in ORMs

Thursday, March 1, 2012

Page 54: ORM dont kill your DB, developers do

Inheritance

Each inheritance type has advantages and disadvantages

Thursday, March 1, 2012

Page 55: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Single Table Inheritance

• Class Table Inheritance

Thursday, March 1, 2012

Page 56: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Single Table Inheritance

• Class Table Inheritance

One Class, one Table

Thursday, March 1, 2012

Page 57: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Single Table Inheritance

• Class Table Inheritance

One Class, one Table

Multiple Classes, one Table

Thursday, March 1, 2012

Page 58: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Single Table Inheritance

• Class Table Inheritance

One Class, one Table

Multiple Classes, one Table

Multiple Classes, multiple Tables

Thursday, March 1, 2012

Page 59: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

Thursday, March 1, 2012

Page 60: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Pros

Thursday, March 1, 2012

Page 61: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Pros• No locking problems

Thursday, March 1, 2012

Page 62: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Pros• No locking problems

• No irrelevant columns

Thursday, March 1, 2012

Page 63: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Pros• No locking problems

• No irrelevant columns

• Cons

Thursday, March 1, 2012

Page 64: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Pros• No locking problems

• No irrelevant columns

• Cons• Difficult to deal with primary keys

Thursday, March 1, 2012

Page 65: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Pros• No locking problems

• No irrelevant columns

• Cons• Difficult to deal with primary keys

• Search base class means search all tables

Thursday, March 1, 2012

Page 66: ORM dont kill your DB, developers do

Inheritance

• Concrete Table Inheritance

• Pros• No locking problems

• No irrelevant columns

• Cons• Difficult to deal with primary keys

• Search base class means search all tables

• Update on columns means update on all hierarchy tables

Thursday, March 1, 2012

Page 67: ORM dont kill your DB, developers do

Inheritance/** * @ORM\MappedSuperclass */class Person{    /**     * @ORM\Column(type="string", length=50)     */    protected $firstName;

    /**     * @ORM\Column(type="string", length=50)     */    protected $lastName;}

/** * @ORM\Entity * @ORM\Table(name="users") */class User extends Person{    /**     * @ORM\Id     * @ORM\GeneratedValue     * @ORM\Column(type="integer")     */    protected $id;}

Thursday, March 1, 2012

Page 68: ORM dont kill your DB, developers do

Inheritance

CREATE TABLE users ( id INTEGER AUTO_INCREMENT NOT NULL, firstName VARCHAR(50) NOT NULL, lastName VARCHAR(50) NOT NULL, PRIMARY KEY (id)) ENGINE=InnoDB;

Thursday, March 1, 2012

Page 69: ORM dont kill your DB, developers do

Inheritance

• Single Table Inheritance

Thursday, March 1, 2012

Page 70: ORM dont kill your DB, developers do

Inheritance

• Single Table Inheritance

• Pros

Thursday, March 1, 2012

Page 71: ORM dont kill your DB, developers do

Inheritance

• Single Table Inheritance

• Pros• Only one table for hierarchy

Thursday, March 1, 2012

Page 72: ORM dont kill your DB, developers do

Inheritance

• Single Table Inheritance

• Pros• Only one table for hierarchy

• No joins

Thursday, March 1, 2012

Page 73: ORM dont kill your DB, developers do

Inheritance

• Single Table Inheritance

• Pros• Only one table for hierarchy

• No joins

• Refactoring of fields means no change to database table

Thursday, March 1, 2012

Page 74: ORM dont kill your DB, developers do

Inheritance

• Single Table Inheritance

• Pros• Only one table for hierarchy

• No joins

• Refactoring of fields means no change to database table

• Cons

Thursday, March 1, 2012

Page 75: ORM dont kill your DB, developers do

Inheritance

• Single Table Inheritance

• Pros• Only one table for hierarchy

• No joins

• Refactoring of fields means no change to database table

• Cons• Waste of space in database

Thursday, March 1, 2012

Page 76: ORM dont kill your DB, developers do

Inheritance

• Single Table Inheritance

• Pros• Only one table for hierarchy

• No joins

• Refactoring of fields means no change to database table

• Cons• Waste of space in database

• Too many locks due to many accesses

Thursday, March 1, 2012

Page 77: ORM dont kill your DB, developers do

Inheritance

• Single Table Inheritance

• Pros• Only one table for hierarchy

• No joins

• Refactoring of fields means no change to database table

• Cons• Waste of space in database

• Too many locks due to many accesses

• No duplicated field names with different meanings

Thursday, March 1, 2012

Page 78: ORM dont kill your DB, developers do

Inheritancenamespace MyApp\Entity;

/** * @ORM\Entity * @ORM\Table(name= "people") * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\DiscriminatorColumn(name="discr", type="string") * @ORM\DiscriminatorMap({ *     "user"     = "MyApp\Entity\User", *     "employee" = "MyApp\Entity\Employee" * }) */class User{    // ...}

/** * @ORM\Entity */class Employee extends User{     // ...}

Thursday, March 1, 2012

Page 79: ORM dont kill your DB, developers do

Inheritance

CREATE TABLE people ( id INT AUTO_INCREMENT NOT NULL, firstName VARCHAR(50) NOT NULL, lastName VARCHAR(50) NOT NULL, discr VARCHAR(20) NOT NULL, role VARCHAR(100) DEFAULT NULL, PRIMARY KEY (id)) ENGINE=InnoDB;

Thursday, March 1, 2012

Page 80: ORM dont kill your DB, developers do

Inheritance

• Class Table Inheritance

Thursday, March 1, 2012

Page 81: ORM dont kill your DB, developers do

Inheritance

• Class Table Inheritance

• Pros

Thursday, March 1, 2012

Page 82: ORM dont kill your DB, developers do

Inheritance

• Class Table Inheritance

• Pros• Easy to understand

Thursday, March 1, 2012

Page 83: ORM dont kill your DB, developers do

Inheritance

• Class Table Inheritance

• Pros• Easy to understand

• Database space is optimized due to table normalization

Thursday, March 1, 2012

Page 84: ORM dont kill your DB, developers do

Inheritance

• Class Table Inheritance

• Pros• Easy to understand

• Database space is optimized due to table normalization

• Direct relationship between Domain Model and Database

Thursday, March 1, 2012

Page 85: ORM dont kill your DB, developers do

Inheritance

• Class Table Inheritance

• Pros• Easy to understand

• Database space is optimized due to table normalization

• Direct relationship between Domain Model and Database

• Cons

Thursday, March 1, 2012

Page 86: ORM dont kill your DB, developers do

Inheritance

• Class Table Inheritance

• Pros• Easy to understand

• Database space is optimized due to table normalization

• Direct relationship between Domain Model and Database

• Cons• Too many joins

Thursday, March 1, 2012

Page 87: ORM dont kill your DB, developers do

Inheritance

• Class Table Inheritance

• Pros• Easy to understand

• Database space is optimized due to table normalization

• Direct relationship between Domain Model and Database

• Cons• Too many joins

• Refactoring of fields needs a database schema update

Thursday, March 1, 2012

Page 88: ORM dont kill your DB, developers do

Inheritance

• Class Table Inheritance

• Pros• Easy to understand

• Database space is optimized due to table normalization

• Direct relationship between Domain Model and Database

• Cons• Too many joins

• Refactoring of fields needs a database schema update

• Superclass table accessed a lot, it means it may enter in lock mode

Thursday, March 1, 2012

Page 89: ORM dont kill your DB, developers do

Inheritancenamespace MyApp\Entity;

/** * @ORM\Entity * @ORM\Table(name="users") * @ORM\InheritanceType("JOINED") * @ORM\DiscriminatorColumn( * name = "discr",  * type = "string", * length = 20 * ) * @ORM\DiscriminatorMap({ *     "user"     = "MyApp\Entity\User", *     "employee" = "MyApp\Entity\Employee" * }) */class User{    // ...}

/** * @ORM\Entity * @ORM\Table(name= "employees") */class Employee extends User{     // ...}

Thursday, March 1, 2012

Page 90: ORM dont kill your DB, developers do

Inheritance

CREATE TABLE users ( id INT AUTO_INCREMENT NOT NULL, firstName VARCHAR(50) NOT NULL, lastName VARCHAR(50) NOT NULL, discr VARCHAR(20) NOT NULL, PRIMARY KEY (id)) ENGINE = InnoDB;

CREATE TABLE employees ( id INT NOT NULL, role VARCHAR(100) NOT NULL, PRIMARY KEY (id)) ENGINE = InnoDB;

ALTER TABLE employees ADD CONSTRAINT FK_BA82C300BF396750 FOREIGN KEY (id) REFERENCES users (id) ON DELETE CASCADE;

Thursday, March 1, 2012

Page 91: ORM dont kill your DB, developers do

Inheritance

What’s the problem with inheritance?

Thursday, March 1, 2012

Page 92: ORM dont kill your DB, developers do

Inheritance

What’s the problem with inheritance?Hydration

Thursday, March 1, 2012

Page 93: ORM dont kill your DB, developers do

Inheritance

Thursday, March 1, 2012

Page 94: ORM dont kill your DB, developers do

Inheritance

• Inverse side *ToOne

Thursday, March 1, 2012

Page 95: ORM dont kill your DB, developers do

Inheritance

• Inverse side *ToOne

• Owning side *ToOne with Inheritance

Thursday, March 1, 2012

Page 96: ORM dont kill your DB, developers do

Inheritance

• Inverse side *ToOne

• Owning side *ToOne with Inheritance

• Disabled deferEagerLoad while Querying

Thursday, March 1, 2012

Page 97: ORM dont kill your DB, developers do

Cascades

http://www.flickr.com/photos/over_kind_man/3158552109/Thursday, March 1, 2012

Page 98: ORM dont kill your DB, developers do

Cascades

Ability to tell Unit Of Work of Doctrine how it should act when inspecting an association for graph changes

Thursday, March 1, 2012

Page 99: ORM dont kill your DB, developers do

Cascades

Use judiciously

Thursday, March 1, 2012

Page 100: ORM dont kill your DB, developers do

Cascades

It can heavily increase the graph edges to be navigated once the Compute Changeset algorithm is ran

Thursday, March 1, 2012

Page 101: ORM dont kill your DB, developers do

Cascades

This means more time to persist, delete, merge, detach, refresh...

Thursday, March 1, 2012

Page 102: ORM dont kill your DB, developers do

Cascades

/** * @ORM\Entity */class User{    //...

    /**     * Bidirectional - One-To-Many (INVERSE SIDE)     *     * @ORM\OneToMany(     *     targetEntity = "Comment",      *     mappedBy     = "author",      *     cascade  = { "persist", "remove" }     * )     */    protected $commentsAuthored;}

Thursday, March 1, 2012

Page 103: ORM dont kill your DB, developers do

Hydrators

http://crimsonnightstock.deviantart.com/art/Yellow-Fire-Hydrant-Stock-100121929Thursday, March 1, 2012

Page 104: ORM dont kill your DB, developers do

Hydrators

Doctrine comes with some useful result hydrators

Thursday, March 1, 2012

Page 105: ORM dont kill your DB, developers do

Hydrators

This means that not all times you need to retrieve objects

Thursday, March 1, 2012

Page 106: ORM dont kill your DB, developers do

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

Thursday, March 1, 2012

Page 107: ORM dont kill your DB, developers do

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

$resultList = $query->getResult();

Thursday, March 1, 2012

Page 108: ORM dont kill your DB, developers do

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

$resultList = $query->getResult();

$resultArray = $query->getArrayResult();

Thursday, March 1, 2012

Page 109: ORM dont kill your DB, developers do

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

$resultList = $query->getResult();

$resultArray = $query->getArrayResult();

$result = $query->getScalarResult();

Thursday, March 1, 2012

Page 110: ORM dont kill your DB, developers do

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

$resultList = $query->getResult();

$resultArray = $query->getArrayResult();

$result = $query->getScalarResult();

$iterator = $query->iterate();

Thursday, March 1, 2012

Page 111: ORM dont kill your DB, developers do

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

$resultList = $query->getResult();

$resultArray = $query->getArrayResult();

$result = $query->getScalarResult();

$iterator = $query->iterate();

$result = $query->getSingleResult();

Thursday, March 1, 2012

Page 112: ORM dont kill your DB, developers do

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

$resultList = $query->getResult();

$resultArray = $query->getArrayResult();

$result = $query->getScalarResult();

$iterator = $query->iterate();

$result = $query->getSingleResult();

$result = $query->getSingleScalarResult();

Thursday, March 1, 2012

Page 113: ORM dont kill your DB, developers do

http://joind.in/6053

Questions?

@guilhermeblanco

http://github.com/guilhermeblanco

InstaClick Inc.

Thursday, March 1, 2012

Page 114: ORM dont kill your DB, developers do

http://joind.in/6053

Questions?

@guilhermeblanco

http://github.com/guilhermeblanco

InstaClick Inc. We are hiring! Talk to me privately if interested

Thursday, March 1, 2012

Page 115: ORM dont kill your DB, developers do

http://joind.in/6053

Questions?Thank you!

@guilhermeblanco

http://github.com/guilhermeblanco

InstaClick Inc. We are hiring! Talk to me privately if interested

Thursday, March 1, 2012