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.
2. ORMs donʼt kill your DB, developers do!
@guilhermeblanco
http://github.com/guilhermeblanco
InstaClick Inc.
Learning about good ORM
practices on @guilhermeblanco
talk at @confooca!
Thursday, March 1, 2012
3. Agenda
http://www.flickr.com/photos/emerzh/3072428824/
Thursday, March 1, 2012
10. Dependency Management
namespace AppBundleBlogBundleEntity;
/**
* @ORMEntity
*/
class Post
{
// ...
}
namespace AppBundleCommentBundleEntity;
/**
* @ORMEntity
*/
class Comment
{
/**
* @ORMManyToOne(targetEntity="AppBlog:Post")
*/
protected $post;
}
Thursday, March 1, 2012
11. Fetch Mode
http://www.flickr.com/photos/comedynose/5318259802/
Thursday, March 1, 2012
12. 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
13. Fetch Mode
Supported by all association types...
Thursday, March 1, 2012
17. Fetch Mode
An association (collection or attribute), is
fetched immediately when owner is loaded
• EAGER
• LAZY (default)
• EXTRA_LAZY
Thursday, March 1, 2012
18. Fetch Mode
An association (collection or attribute), is
fetched immediately when owner is loaded
• EAGER An association (collection or attribute),
• LAZY (default) is fetched when the application invokes
an operation over it
• EXTRA_LAZY
Thursday, March 1, 2012
19. Fetch Mode
An association (collection or attribute), is
fetched immediately when owner is loaded
• EAGER An association (collection or attribute),
• LAZY (default) is fetched when the application invokes
an operation over it
• EXTRA_LAZY
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
22. Querying
http://www.flickr.com/photos/pschadler/4932737690/
Thursday, March 1, 2012
23. 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
24. Querying
$query = $entityManager->createQuery('
SELECT p
FROM Post p
');
$postList = $query->getResult();
foreach ($postList as $post) {
$tagList = $post->getTagList(); N + 1 trolls?
foreach ($tagList as $tag) {
echo $tag->getName();
}
}
Thursday, March 1, 2012
25. 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
26. Querying
$query = $entityManager->createQuery('
SELECT p, t
FROM Post p Pardon? DQL is
LEFT JOIN p.tagList t
');
powerful! RTFM
$postList = $query->getResult();
foreach ($postList as $post) {
$tagList = $post->getTagList();
foreach ($tagList as $tag) {
echo $tag->getName();
}
}
Thursday, March 1, 2012
27. Querying
I know you all don’t trust me...
Thursday, March 1, 2012
28. Querying
...but take a look at its EBNF grammar...
Thursday, March 1, 2012
30. Querying
Since the letter size is 6, you may still not believe me
Thursday, March 1, 2012
31. Querying
let’s try a real world example!
Thursday, March 1, 2012
32. Querying
Do you know Facebook activity wall?
Thursday, March 1, 2012
33. Querying
Do you know Facebook activity wall?
Let’s show it!
Thursday, March 1, 2012
34. 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
35. SELECT e, a
FROM Entry e
JOIN e.wall w Entry you wrote
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
36. SELECT e, a
FROM Entry e
JOIN e.wall w Entry you wrote
JOIN e.user u
LEFT JOIN u.avatar av
WHERE u = :user
OR w IN ( Entry was in your Wall
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
37. SELECT e, a
FROM Entry e
JOIN e.wall w Entry you wrote
JOIN e.user u
LEFT JOIN u.avatar av
WHERE u = :user
OR w IN ( Entry was in your Wall
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
User is your friend, the friendship is
JOIN us.friendship f approved and subscription is not muted
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
38. SELECT e, a
FROM Entry e
JOIN e.wall w Entry you wrote
JOIN e.user u
LEFT JOIN u.avatar av
WHERE u = :user
OR w IN ( Entry was in your Wall
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
User is your friend, the friendship is
JOIN us.friendship f approved and subscription is not muted
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 Group that you participate, is not
WHERE gs.subscriber = :user
AND gs.muted = FALSE
muted and have an approved status
AND gs.status = 'Approved'
)
)
ORDER BY e.created DESC
Thursday, March 1, 2012
39. Caching
http://www.flickr.com/photos/eszter/3851576235/
Thursday, March 1, 2012
40. Caching
Doctrine supports 3 levels of caching...
Thursday, March 1, 2012
41. Caching
• Metadata cache
• Query cache
• Result cache
Thursday, March 1, 2012
42. Caching
Cache mapping of entities
• Metadata cache
• Query cache
• Result cache
Thursday, March 1, 2012
43. Caching
Cache mapping of entities
• Metadata cache
• Query cache Cache DQL to SQL conversion
• Result cache
Thursday, March 1, 2012
44. Caching
Cache mapping of entities
• Metadata cache
• Query cache Cache DQL to SQL conversion
• Result cache
Cache PDO result set
Thursday, March 1, 2012
45. Caching
$query = $entityManager->createQuery('
SELECT p
FROM Post p
');
$query->useResultCache(true, 600, 'find-all-posts');
$postList = $query->getResult();
Thursday, March 1, 2012
46. Indexing
http://www.flickr.com/photos/osuarchives/2659419894/
Thursday, March 1, 2012
47. Indexing
Doctrine is able to hint the Schema Tool to generate
database indexes on specified table columns
Thursday, March 1, 2012
49. Indexing
@ORMUniqueConstraint(
name = "user_unique",
columns = { "name" }
)
CREATE UNIQUE INDEX user_unique
ON TABLE users (name);
Thursday, March 1, 2012
50. Indexing
@ORMIndex(
name = "login_idx",
columns = { "name", "password" }
)
CREATE INDEX login_idx
ON TABLE users (name, password);
Thursday, March 1, 2012
51. Indexing
@ORMIndex(
name = "login_idx",
columns = { "name", "password" }
)
Some drivers restrict to
32 chars as index name
CREATE INDEX login_idx
ON TABLE users (name, password);
Thursday, March 1, 2012
52. Inheritance
http://www.flickr.com/photos/duanekeys/307005468/
Thursday, March 1, 2012
53. Inheritance
Inheritance is a very deep topic in ORMs
Thursday, March 1, 2012
54. Inheritance
Each inheritance type has advantages and disadvantages
Thursday, March 1, 2012
55. Inheritance
• Concrete Table Inheritance
• Single Table Inheritance
• Class Table Inheritance
Thursday, March 1, 2012
56. Inheritance
One Class, one Table
• Concrete Table Inheritance
• Single Table Inheritance
• Class Table Inheritance
Thursday, March 1, 2012
57. Inheritance
One Class, one Table
• Concrete Table Inheritance
• Single Table Inheritance Multiple Classes, one Table
• Class Table Inheritance
Thursday, March 1, 2012
58. Inheritance
One Class, one Table
• Concrete Table Inheritance
• Single Table Inheritance Multiple Classes, one Table
• Class Table Inheritance
Multiple Classes, multiple Tables
Thursday, March 1, 2012
59. Inheritance
• Concrete Table Inheritance
Thursday, March 1, 2012
61. Inheritance
• Concrete Table Inheritance
• Pros
• No locking problems
Thursday, March 1, 2012
62. Inheritance
• Concrete Table Inheritance
• Pros
• No locking problems
• No irrelevant columns
Thursday, March 1, 2012
63. Inheritance
• Concrete Table Inheritance
• Pros
• No locking problems
• No irrelevant columns
• Cons
Thursday, March 1, 2012
64. Inheritance
• Concrete Table Inheritance
• Pros
• No locking problems
• No irrelevant columns
• Cons
• Difficult to deal with primary keys
Thursday, March 1, 2012
65. 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
66. 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
67. Inheritance
/**
* @ORMMappedSuperclass
*/
class Person
{
/**
* @ORMColumn(type="string", length=50)
*/
protected $firstName;
/**
* @ORMColumn(type="string", length=50)
*/
protected $lastName;
}
/**
* @ORMEntity
* @ORMTable(name="users")
*/
class User extends Person
{
/**
* @ORMId
* @ORMGeneratedValue
* @ORMColumn(type="integer")
*/
protected $id;
}
Thursday, March 1, 2012
68. 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
69. Inheritance
• Single Table Inheritance
Thursday, March 1, 2012
70. Inheritance
• Single Table Inheritance
• Pros
Thursday, March 1, 2012
71. Inheritance
• Single Table Inheritance
• Pros
• Only one table for hierarchy
Thursday, March 1, 2012
72. Inheritance
• Single Table Inheritance
• Pros
• Only one table for hierarchy
• No joins
Thursday, March 1, 2012
73. 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
74. 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
75. 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
76. 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
77. 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
78. Inheritance
namespace MyAppEntity;
/**
* @ORMEntity
* @ORMTable(name= "people")
* @ORMInheritanceType("SINGLE_TABLE")
* @ORMDiscriminatorColumn(name="discr", type="string")
* @ORMDiscriminatorMap({
* "user" = "MyAppEntityUser",
* "employee" = "MyAppEntityEmployee"
* })
*/
class User
{
// ...
}
/**
* @ORMEntity
*/
class Employee extends User
{
// ...
}
Thursday, March 1, 2012
79. 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
80. Inheritance
• Class Table Inheritance
Thursday, March 1, 2012
81. Inheritance
• Class Table Inheritance
• Pros
Thursday, March 1, 2012
82. Inheritance
• Class Table Inheritance
• Pros
• Easy to understand
Thursday, March 1, 2012
83. Inheritance
• Class Table Inheritance
• Pros
• Easy to understand
• Database space is optimized due to table normalization
Thursday, March 1, 2012
84. 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
85. 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
86. 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
87. 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
88. 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
89. Inheritance
namespace MyAppEntity;
/**
* @ORMEntity
* @ORMTable(name="users")
* @ORMInheritanceType("JOINED")
* @ORMDiscriminatorColumn(
* name = "discr",
* type = "string",
* length = 20
* )
* @ORMDiscriminatorMap({
* "user" = "MyAppEntityUser",
* "employee" = "MyAppEntityEmployee"
* })
*/
class User
{
// ...
}
/**
* @ORMEntity
* @ORMTable(name= "employees")
*/
class Employee extends User
{
// ...
}
Thursday, March 1, 2012
90. 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
91. Inheritance
What’s the problem with inheritance?
Thursday, March 1, 2012
92. Inheritance
What’s the problem with inheritance?
Hydration
Thursday, March 1, 2012
113. http://joind.in/6053
Questions?
@guilhermeblanco
http://github.com/guilhermeblanco
InstaClick Inc.
Thursday, March 1, 2012
114. 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
115. 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