Upload
cihad-guendogdu
View
221
Download
0
Embed Size (px)
Citation preview
8/4/2019 unjoinify
1/36
unjoinify: a module to tame the SQLbeast
Matt WestcottDjangoCon Europe, 7th June 2011
8/4/2019 unjoinify
2/36
The n+1 query problem
8/4/2019 unjoinify
3/36
The n+1 query problem
Eager loading
8/4/2019 unjoinify
4/36
The n+1 query problem
Eager loading
"that thing that really bugs meabout select_related"
8/4/2019 unjoinify
5/36
8/4/2019 unjoinify
6/36
Festival
8/4/2019 unjoinify
7/36
Festival Award
8/4/2019 unjoinify
8/36
Festival Award Nomination
8/4/2019 unjoinify
9/36
Festival Award Nomination Movie
8/4/2019 unjoinify
10/36
Festival Award Nomination Movie Person (director)
8/4/2019 unjoinify
11/36
Festival Award Nomination Movie Person (director)
Company
8/4/2019 unjoinify
12/36
def show(request, festival_id):festival = get_object_or_404(Festival, id = festival_id)return render(request, 'festivals/show.html', {
'festival': festival} )
{{ festival.name }}
{% for award in festival.awards %}{{ award }}
{% for nomination in award.nominations %}
{{ nomination.movie.name }}(...)
{% endfor %}
{% endfor %}
8/4/2019 unjoinify
13/36
def show(request, festival_id):festival = get_object_or_404(Festival, id = festival_id,
select_related('award__nomination__movie'))return render(request, 'festivals/show.html', {
'festival': festival} )
{{ festival.name }}
{% for award in festival.awards %}{{ award }}
{% for nomination in award.nominations %}
{{ nomination.movie.name }}(...)
{% endfor %}
{% endfor %}
8/4/2019 unjoinify
14/36
8/4/2019 unjoinify
15/36
8/4/2019 unjoinify
16/36
people = Person.objects.filter(movies_directed__nominations__award__festival_id =
festival_id)
{% regroup people by award as award_list %}{% for award in award_list %}{{ award.grouper }}
{% regroup award.list by movie as movie_list %}{% for movie in movie_list %}
{{ movie.grouper }}
{% endfor %}{% endfor %}
8/4/2019 unjoinify
17/36
SELECTimdb_award.id,imdb_award.name,imdb_nomination.id AS nomination__id,imdb_nomination.ranking AS nomination__ranking,imdb_movie.id AS nomination__movie__id,imdb_movie.title AS nomination__movie__title,imdb_person.id AS nomination__movie__directors__id,imdb_person.first_name AS nomination__movie__directors__first_nameimdb_person.surname AS nomination__movie__directors__surname
FROM
imdb_awardLEFT JOIN imdb_nomination ON (imdb_award.id = imdb_nomination.award_id)LEFT JOIN imdb_movie ON (imdb_nomination.movie_id = imdb_movie.id)LEFT JOIN imdb_movie_directors ON (imdb_movie.id =
imdb_movie_directors.movie_id)LEFT JOIN imdb_person ON (imdb_movie_directors.person_id =
imdb_person.id)
WHEREimdb_award.festival_id = ?
ORDER BYimdb_award.name,imdb_nomination.ranking
8/4/2019 unjoinify
18/36
id | name | nomination_id | rank | movie_id | movie_title | director_id | director_name---+---------------+---------------+------+----------+-------------------+-------------+---------------2 | Best Director | 4 | 1 | 1 | The King's Speech | 1 | Iain Canning2 | Best Director | 4 | 1 | 1 | The King's Speech | 2 | Emile Sherman2 | Best Director | 4 | 1 | 1 | The King's Speech | 3 | Gareth Unwin2 | Best Director | 5 | 2 | 2 | 127 Hours | 4 | Danny Boyle2 | Best Director | 5 | 2 | 2 | 127 Hours | 5 | Christian Colson2 | Best Director | 6 | 3 | 4 | True Grit | 10 | Joel Coen2 | Best Director | 6 | 3 | 4 | True Grit | 9 | Ethan Coen2 | Best Director | 6 | 3 | 4 | True Grit | 11 | Scott Rudin1 | Best Picture | 1 | 1 | 1 | The King's Speech | 1 | Iain Canning1 | Best Picture | 1 | 1 | 1 | The King's Speech | 2 | Emile Sherman1 | Best Picture | 1 | 1 | 1 | The King's Speech | 3 | Gareth Unwin1 | Best Picture | 2 | 2 | 2 | 127 Hours | 4 | Danny Boyle1 | Best Picture | 2 | 2 | 2 | 127 Hours | 5 | Christian Colson1 | Best Picture | 3 | 3 | 3 | Black Swan | 6 | Scott Franklin
1 | Best Picture | 3 | 3 | 3 | Black Swan | 7 | Mike Medavoy1 | Best Picture | 3 | 3 | 3 | Black Swan | 8 | Brian Oliver
8/4/2019 unjoinify
19/36
id | name | nomination_id | rank | movie_id | movie_title | director_id | director_name---+---------------+---------------+------+----------+-------------------+-------------+---------------2 | Best Director | 4 | 1 | 1 | The King's Speech | 1 | Iain Canning2 | Best Director | 4 | 1 | 1 | The King's Speech | 2 | Emile Sherman2 | Best Director | 4 | 1 | 1 | The King's Speech | 3 | Gareth Unwin2 | Best Director | 5 | 2 | 2 | 127 Hours | 4 | Danny Boyle2 | Best Director | 5 | 2 | 2 | 127 Hours | 5 | Christian Colson
2 | Best Director | 6 | 3 | 4 | True Grit | 10 | Joel Coen2 | Best Director | 6 | 3 | 4 | True Grit | 9 | Ethan Coen2 | Best Director | 6 | 3 | 4 | True Grit | 11 | Scott Rudin1 | Best Picture | 1 | 1 | 1 | The King's Speech | 1 | Iain Canning1 | Best Picture | 1 | 1 | 1 | The King's Speech | 2 | Emile Sherman1 | Best Picture | 1 | 1 | 1 | The King's Speech | 3 | Gareth Unwin1 | Best Picture | 2 | 2 | 2 | 127 Hours | 4 | Danny Boyle1 | Best Picture | 2 | 2 | 2 | 127 Hours | 5 | Christian Colson1 | Best Picture | 3 | 3 | 3 | Black Swan | 6 | Scott Franklin
1 | Best Picture | 3 | 3 | 3 | Black Swan | 7 | Mike Medavoy1 | Best Picture | 3 | 3 | 3 | Black Swan | 8 | Brian Oliver
{{ movie }}
8/4/2019 unjoinify
20/36
my_results = cursor.execute('''SELECT id, name, nomination.id AS nomination__id,FROM ...
WHERE ...''')
awards = do_some_magic(my_results);
return render(request, 'festivals/show.html', {
'festival': festival,'awards': awards,
})
8/4/2019 unjoinify
21/36
my_results = cursor.execute('''SELECT id, name, nomination.id AS nomination__id,FROM ...
WHERE ...''')
awards = do_some_magic(my_results);
return render(request, 'festivals/show.html', {
'festival': festival,'awards': awards,
})
django-unjoinify:
it isn't magic.
8/4/2019 unjoinify
22/36
from unjoinify import unjoinifyquery = '''
SELECT
imdb_award.id,imdb_award.name,imdb_nomination.id AS nomination__id,imdb_nomination.ranking AS nomination__ranking,imdb_movie.id AS nomination__movie__id,imdb_movie.title AS nomination__movie__title,
FROMimdb_awardLEFT JOIN imdb_nomination ON (imdb_award.id =
imdb_nomination.award_id)LEFT JOIN imdb_movie ON (imdb_nomination.movie_id =
imdb_movie.id)WHERE imdb_award.festival_id = %s'''
awards = unjoinify(Award, query, (festival.id,))
8/4/2019 unjoinify
23/36
idnamenomination__id
nomination__rankingnomination__movie__idnomination__movie__titlenomination__movie__directors__idnomination__movie__directors__first_name
nomination__movie__directors__surnamenomination__movie__production_companies__idnomination__movie__production_companies__name
8/4/2019 unjoinify
24/36
idnamenomination__id
nomination__rankingnomination__movie__idnomination__movie__titlenomination__movie__directors__idnomination__movie__directors__first_name
nomination__movie__directors__surnamenomination__movie__production_companies__idnomination__movie__production_companies__name
awards = (award, [nominations])where:
nominations = (nomination, movie, directors, companies)
{% for award in awards %}
8/4/2019 unjoinify
25/36
{% for award in awards %}{{ award.name }}
{% for nomination in award.nominations %}
{{ nomination.movie.name }}
{% for director in nomination.movie.directors %}{{ director.first_name }}{{ director.surname }}
{% endfor %}
{% for company in nomination.movie.companies %}{{ company.name }}
{% endfor %}
{% endfor %}
{% endfor %}
{% for award nominations in awards %}
8/4/2019 unjoinify
26/36
{% for award, nominations in awards %}{{ award.name }}
{% for nomination, movie, directors, companies in
nominations %}{{ movie.name }}
{% for director in directors %}{{ director.first_name }}
{{ director.surname }}{% endfor %}
{% for company in companies %}
{{ company.name }}{% endfor %}
{% endfor %}
{% endfor %}
8/4/2019 unjoinify
27/36
make_unpack_plan(Movie, columns, prefix = 'nomination__movie__')
id
namenomination__idnomination__rankingnomination__movie__idnomination__movie__title
nomination__movie__directors__idnomination__movie__directors__first_namenomination__movie__directors__surnamenomination__movie__production_companies__idnomination__movie__production_companies__name
8/4/2019 unjoinify
28/36
make_unpack_plan(Movie, columns, prefix = 'nomination__movie__')
id
namenomination__idnomination__rankingnomination__movie__idnomination__movie__title
nomination__movie__directors__idnomination__movie__directors__first_namenomination__movie__directors__surnamenomination__movie__production_companies__idnomination__movie__production_companies__name
=> ({model: Movie, fields: ('id','title')},[{model: Person, fields: ('id','first_name','surname')}],[{model: Company, fields: ('id','name')}],
)
8/4/2019 unjoinify
29/36
id | name | nomination_id | rank | movie_id | movie_title | director_id | director_name
---+---------------+---------------+------+----------+-------------------+-------------+---------------2 | Best Director | 4 | 1 | 1 | The King's Speech | 1 | Iain Canning2 | Best Director | 4 | 1 | 1 | The King's Speech | 2 | Emile Sherman2 | Best Director | 4 | 1 | 1 | The King's Speech | 3 | Gareth Unwin2 | Best Director | 5 | 2 | 2 | 127 Hours | 4 | Danny Boyle2 | Best Director | 5 | 2 | 2 | 127 Hours | 5 | Christian Colson2 | Best Director | 6 | 3 | 4 | True Grit | 10 | Joel Coen2 | Best Director | 6 | 3 | 4 | True Grit | 9 | Ethan Coen2 | Best Director | 6 | 3 | 4 | True Grit | 11 | Scott Rudin
1 | Best Picture | 1 | 1 | 1 | The King's Speech | 1 | Iain Canning1 | Best Picture | 1 | 1 | 1 | The King's Speech | 2 | Emile Sherman1 | Best Picture | 1 | 1 | 1 | The King's Speech | 3 | Gareth Unwin1 | Best Picture | 2 | 2 | 2 | 127 Hours | 4 | Danny Boyle1 | Best Picture | 2 | 2 | 2 | 127 Hours | 5 | Christian Colson1 | Best Picture | 3 | 3 | 3 | Black Swan | 6 | Scott Franklin1 | Best Picture | 3 | 3 | 3 | Black Swan | 7 | Mike Medavoy1 | Best Picture | 3 | 3 | 3 | Black Swan | 8 | Brian Oliver
unpack_with_plan(plan, results)
8/4/2019 unjoinify
30/36
id | name | nomination_id | rank | movie_id | movie_title | director_id | director_name
---+---------------+---------------+------+----------+-------------------+-------------+---------------2 | Best Director | 4 | 1 | 1 | The King's Speech | 1 | Iain Canning2 | Best Director | 4 | 1 | 1 | The King's Speech | 2 | Emile Sherman2 | Best Director | 4 | 1 | 1 | The King's Speech | 3 | Gareth Unwin
2 | Best Director | 5 | 2 | 2 | 127 Hours | 4 | Danny Boyle2 | Best Director | 5 | 2 | 2 | 127 Hours | 5 | Christian Colson
2 | Best Director | 6 | 3 | 4 | True Grit | 10 | Joel Coen
2 | Best Director | 6 | 3 | 4 | True Grit | 9 | Ethan Coen2 | Best Director | 6 | 3 | 4 | True Grit | 11 | Scott Rudin
1 | Best Picture | 1 | 1 | 1 | The King's Speech | 1 | Iain Canning1 | Best Picture | 1 | 1 | 1 | The King's Speech | 2 | Emile Sherman1 | Best Picture | 1 | 1 | 1 | The King's Speech | 3 | Gareth Unwin
1 | Best Picture | 2 | 2 | 2 | 127 Hours | 4 | Danny Boyle1 | Best Picture | 2 | 2 | 2 | 127 Hours | 5 | Christian Colson
1 | Best Picture | 3 | 3 | 3 | Black Swan | 6 | Scott Franklin1 | Best Picture | 3 | 3 | 3 | Black Swan | 7 | Mike Medavoy1 | Best Picture | 3 | 3 | 3 | Black Swan | 8 | Brian Oliver
unpack_with_plan(plan, results)
8/4/2019 unjoinify
31/36
Festival Award Nomination Movie Person (director)
Company
beware the cartesian join
8/4/2019 unjoinify
32/36
a_very_long_column_alias_name_that_exceeds_the_limi
8/4/2019 unjoinify
33/36
a_very_long_column_alias_name_that_exceeds_the_limi
unjoinify(model, query, params, column_names)
8/4/2019 unjoinify
34/36
the masterplan
1. Get select_related to auto-generate the SQL
2. Reconstruct models from the resultset
3. 'Push' child objects into their respectiveRelatedManagers
4. Profit!
8/4/2019 unjoinify
35/36
github.com/simonw/django-queryset-transform
8/4/2019 unjoinify
36/36
https://github.com/gasman/django-unjoinify
pip install django-unjoinify
Thank you!Matt Westcott
http://matt.west.co.tt/@westdotcodottt