orm dont kill your db, developers do

Post on 09-May-2015

7.799 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

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

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

Database

Developers

ORM

Guilherme BlancoThursday, March 1, 2012

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

Agenda

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

General Rule

RTFMThursday, March 1, 2012

Dependency management

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

Dependency Management

Thursday, March 1, 2012

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

Dependency Management

Thursday, March 1, 2012

Dependency Management

Thursday, March 1, 2012

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

Fetch Mode

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

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

Fetch Mode

Supported by all association types...

Thursday, March 1, 2012

Fetch Mode

• OneToOne

• OneToMany

• ManyToOne

• ManyToMany

Thursday, March 1, 2012

Fetch Mode

Available fetch modes...

Thursday, March 1, 2012

Fetch Mode

• EAGER

• LAZY (default)

• EXTRA_LAZY

Thursday, March 1, 2012

Fetch Mode

• EAGER

• LAZY (default)

• EXTRA_LAZY

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

Thursday, March 1, 2012

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

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

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

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

Querying

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

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

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

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

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

Querying

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

Thursday, March 1, 2012

Querying

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

Thursday, March 1, 2012

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

Querying

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

Thursday, March 1, 2012

Querying

let’s try a real world example!

Thursday, March 1, 2012

Querying

Do you know Facebook activity wall?

Thursday, March 1, 2012

Querying

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

Thursday, March 1, 2012

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

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

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

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

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

Caching

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

Caching

Doctrine supports 3 levels of caching...

Thursday, March 1, 2012

Caching

• Metadata cache

• Query cache

• Result cache

Thursday, March 1, 2012

Caching

• Metadata cache

• Query cache

• Result cache

Cache mapping of entities

Thursday, March 1, 2012

Caching

• Metadata cache

• Query cache

• Result cache

Cache mapping of entities

Cache DQL to SQL conversion

Thursday, March 1, 2012

Caching

• Metadata cache

• Query cache

• Result cache

Cache mapping of entities

Cache PDO result set

Cache DQL to SQL conversion

Thursday, March 1, 2012

Caching

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

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

$postList = $query->getResult();

Thursday, March 1, 2012

Indexing

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

Indexing

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

Thursday, March 1, 2012

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

Indexing

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

CREATE UNIQUE INDEX user_unique ON TABLE users (name);

Thursday, March 1, 2012

Indexing

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

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

Thursday, March 1, 2012

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

Inheritance

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

Inheritance

Inheritance is a very deep topic in ORMs

Thursday, March 1, 2012

Inheritance

Each inheritance type has advantages and disadvantages

Thursday, March 1, 2012

Inheritance

• Concrete Table Inheritance

• Single Table Inheritance

• Class Table Inheritance

Thursday, March 1, 2012

Inheritance

• Concrete Table Inheritance

• Single Table Inheritance

• Class Table Inheritance

One Class, one Table

Thursday, March 1, 2012

Inheritance

• Concrete Table Inheritance

• Single Table Inheritance

• Class Table Inheritance

One Class, one Table

Multiple Classes, one Table

Thursday, March 1, 2012

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

Inheritance

• Concrete Table Inheritance

Thursday, March 1, 2012

Inheritance

• Concrete Table Inheritance

• Pros

Thursday, March 1, 2012

Inheritance

• Concrete Table Inheritance

• Pros• No locking problems

Thursday, March 1, 2012

Inheritance

• Concrete Table Inheritance

• Pros• No locking problems

• No irrelevant columns

Thursday, March 1, 2012

Inheritance

• Concrete Table Inheritance

• Pros• No locking problems

• No irrelevant columns

• Cons

Thursday, March 1, 2012

Inheritance

• Concrete Table Inheritance

• Pros• No locking problems

• No irrelevant columns

• Cons• Difficult to deal with primary keys

Thursday, March 1, 2012

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

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

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

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

Inheritance

• Single Table Inheritance

Thursday, March 1, 2012

Inheritance

• Single Table Inheritance

• Pros

Thursday, March 1, 2012

Inheritance

• Single Table Inheritance

• Pros• Only one table for hierarchy

Thursday, March 1, 2012

Inheritance

• Single Table Inheritance

• Pros• Only one table for hierarchy

• No joins

Thursday, March 1, 2012

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

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

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

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

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

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

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

Inheritance

• Class Table Inheritance

Thursday, March 1, 2012

Inheritance

• Class Table Inheritance

• Pros

Thursday, March 1, 2012

Inheritance

• Class Table Inheritance

• Pros• Easy to understand

Thursday, March 1, 2012

Inheritance

• Class Table Inheritance

• Pros• Easy to understand

• Database space is optimized due to table normalization

Thursday, March 1, 2012

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

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

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

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

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

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

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

Inheritance

What’s the problem with inheritance?

Thursday, March 1, 2012

Inheritance

What’s the problem with inheritance?Hydration

Thursday, March 1, 2012

Inheritance

Thursday, March 1, 2012

Inheritance

• Inverse side *ToOne

Thursday, March 1, 2012

Inheritance

• Inverse side *ToOne

• Owning side *ToOne with Inheritance

Thursday, March 1, 2012

Inheritance

• Inverse side *ToOne

• Owning side *ToOne with Inheritance

• Disabled deferEagerLoad while Querying

Thursday, March 1, 2012

Cascades

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

Cascades

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

Thursday, March 1, 2012

Cascades

Use judiciously

Thursday, March 1, 2012

Cascades

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

Thursday, March 1, 2012

Cascades

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

Thursday, March 1, 2012

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

Hydrators

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

Hydrators

Doctrine comes with some useful result hydrators

Thursday, March 1, 2012

Hydrators

This means that not all times you need to retrieve objects

Thursday, March 1, 2012

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

Thursday, March 1, 2012

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

$resultList = $query->getResult();

Thursday, March 1, 2012

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

$resultList = $query->getResult();

$resultArray = $query->getArrayResult();

Thursday, March 1, 2012

Hydrators

• Object

• Array

• Scalar

• Iterable

• Simple Object

• Single Scalar

$resultList = $query->getResult();

$resultArray = $query->getArrayResult();

$result = $query->getScalarResult();

Thursday, March 1, 2012

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

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

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

http://joind.in/6053

Questions?

@guilhermeblanco

http://github.com/guilhermeblanco

InstaClick Inc.

Thursday, March 1, 2012

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

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

top related