1. kemar
  2. Presentations

Commits

kemar  committed 758208f

added "It's over 9000!" presentation

  • Participants
  • Branches default

Comments (0)

Files changed (5)

File 2012.it.s.over.9000/autolib.strike.team.png

Added
New image

File 2012.it.s.over.9000/config.cfg

View file
+[landslide]
+source = it.s.over.9000.rst
+destination = it.s.over.9000.html
+css = django.css
+embed = True
+relative = True
+linenos = no

File 2012.it.s.over.9000/django.css

View file
+/*
+ * Django style
+ *
+ * Thanx 2 https://github.com/n1k0/Presentations/tree/master/2011-Djangocong
+ *
+ * Backgrounds:
+ * Green1: #94DA3A;
+ * Green2: #487858;
+ * Green3: #326343;
+ * Green4: #235033;
+ * Green5: #092d1f;
+ *
+ * Titles:
+ * Dark: #063233;
+ * GreenPastel: #7bb09c;
+ * Yellow: #ffe971;
+ *
+ */
+
+body {
+    font: 15px "Calibri", "Trebuchet MS", Verdana, sans-serif;
+    background: #235033;
+}
+
+a {
+    text-decoration: none !important;
+    border: 0 !important;
+}
+
+h1 {
+    font-size: 40px !important;
+}
+
+h2 {
+    font-size: 20px !important;
+}
+
+ul {
+    margin: 10px 0 0 20px !important;
+    padding: 0 !important;
+}
+
+ul li {
+    padding: 5px 0 !important;
+}
+
+img.solo {
+    margin-top: 20px;
+}
+
+pre, code {
+    font-family: Monaco, monospace;
+}
+
+pre {
+    border: 2px solid #326343;
+    padding: 1em;
+    border-radius: 10px;
+}
+
+p code, li code {
+    color: #487858;
+}
+
+div.slide strong {
+    color: #326343;
+}
+
+div.slide {
+    background: #092d1f;
+}
+
+div.slide .inner {
+    background: #fff;
+    border-radius: 13px;
+    width: 880px;
+    margin: 0 auto;
+}
+
+section {
+    min-height: 590px;
+}
+
+header:not(:only-child) {
+    font-family: "Calibri";
+    color: #fff;
+}
+
+aside {
+    font-family: "Calibri";
+    color: #092d1f;
+    bottom: 16px;
+}
+
+div.slide.home header {
+    display: none;
+}
+
+div.slide.home section {
+    margin-top: 55px;
+}
+
+div.slide.home img {
+    width: 80%;
+    margin-left: 80px;
+}
+
+div.slide.title header {
+    background: #092d1f;
+    border-radius: 10px;
+}
+
+div.slide.title header h1 {
+    color: #fff;
+}
+
+div.slide blockquote p {
+    color: #444;
+    font-family: Georgia, serif;
+    font-size: 2em;
+    font-style: italic;
+    line-height: 1.4em;
+    text-align: center;
+}
+
+div.slide.fullimage section {
+    text-align: center;
+}
+
+div.slide.fullimage li {
+    text-align: left;
+}
+
+div.slide.fullimage img {
+    max-width: 96%;
+    max-height: 78%;
+    border-radius: 4px;
+}
+
+div.slide p.cite {
+    text-align: right;
+}
+
+div.slide .smallest {
+    font-size: 80%;
+}
+
+div.slide.bigbullet h3 {
+    font-size: 250%;
+}
+
+div.slide.bigbullet ul li {
+    font-size: 240%;
+}
+div.slide.bigbullet ul li li {
+    font-size: 90%;
+}
+div.slide.bigbullet ul li small {
+    font-size: 50%;
+}
+
+div.slide.centerquote section {
+    min-height: 590px;
+}
+
+div.slide.centerquote blockquote {
+    display: table-cell;
+    width: 800px;
+    height: 500px;
+    vertical-align: middle;
+    text-align: center;
+}
+
+div.slide.centerquote blockquote p {
+    font-size: 280%;
+    padding: 0 20px;
+}
+
+div.slide.larger section * {
+    font-size: 200%;
+}
+
+div.slide.larger section pre {
+    font-size: 70%;
+}
+
+div.slide.larger section p code,
+div.slide.larger section h3 code,
+div.slide.larger section li code {
+    font-size: 90%;
+}
+
+p.cop {
+    position: fixed;
+    width: 100%;
+    bottom: 0;
+    margin: 0;
+    padding: .2em 0;
+    color: #fff;
+    text-align: center;
+    color: #fff;
+    background: #092d1f;
+}
+
+p.cop strong {
+    color: ##092d1f;
+}
+
+p.cop a {
+    color: #ffe971;
+}

File 2012.it.s.over.9000/it.s.over.9000.rst

View file
+
+===============
+It's over 9000!
+===============
+
+Ma page fait 9000 requêtes SQL, pourquoi, et comment je m’en sors ?
+-------------------------------------------------------------------
+
+Rencontres Django a.k.a #djangocong
+
+14 avril 2012
+
+
+----
+
+
+==========================
+Le yin et le yang de l'ORM
+==========================
+
+.. image:: what9000.png
+    :width: 90 %
+    :class: solo
+
+
+----
+
+
+=============
+Qui suis-je ?
+=============
+
+- Marc Hertzog @_kemar
+- Développeur Web freelance http://marcarea.com/
+- Pythoniste et Djangonaute
+- Intervenant sur le projet Autolib’
+
+.. image:: autolib.strike.team.png
+    :width: 500 px
+
+
+----
+
+
+====================================
+Voir les requêtes générées par l'ORM
+====================================
+
+
+1) Dans le navigateur web : ``django-debug-toolbar``
+----------------------------------------------------
+
+2) Dans le shell Django ``./manage.py shell``
+---------------------------------------------
+
+::
+
+    !python
+    >>> from django.db import connection  # DEBUG = True
+    >>> connection.queries
+    >>> connection.queries = []  # reset
+
+3) Dans la sortie de runserver >= 1.3
+-------------------------------------
+
+::
+
+    !python
+    import logging
+    l = logging.getLogger('django.db.backends')
+    l.setLevel(logging.DEBUG)
+    l.addHandler(logging.StreamHandler())
+
+4) Directement dans les fichiers de log du SGBD
+-----------------------------------------------
+
+::
+
+    log_statement all >> /etc/postgresql/postgresql.conf
+
+    [mysqld] log=/tmp/mysql.log >> /etc/mysql/my.cnf
+
+
+----
+
+
+=================
+Modèles d'exemple
+=================
+
+::
+
+    !python
+    class Car(models.Model):
+
+        is_locked = models.BooleanField(default=False)
+
+        paired_with = models.ForeignKey(RfidCard, related_name='paired_cars')
+
+        ...
+
+    class CarTelemetry(models.Model):
+
+        car = models.ForeignKey(Car, related_name='telemetry_set')  # many-to-one
+
+        time = LocalDateTimeField(default=datetime.datetime.now)
+
+        ...
+
+
+----
+
+
+=======================
+Cas des clés étrangères
+=======================
+
+Pour chaque ``Car``, récupèrer **la** carte RFID associée
+
+::
+
+    !django
+    <ul>
+    {% for car in cars %}
+        <li>{{ car.paired_with.get_kind_display }} : IT'S OVER 9000!!!!!!</li>
+    {% endfor %}
+    </ul>
+
+
+----
+
+
+===============================
+Solution : ``select_related()``
+===============================
+
+- ``MyModel.objects.select_related().all()``
+- limité aux ``foreign keys`` et aux ``one-to-one``
+- ne suit pas les relations avec ``null=True``
+- ``MyModel.objects.select_related('model1__model2').all()``
+- ``select_related(depth=2)`` contrôle le nombre de niveaux
+
+Shortcut : ::
+
+    !python
+    get_object_or_404(MyModel.objects.select_related(), field=value)
+
+Exemples : ::
+
+    !python
+    cars = Car.objects.select_related('paired_with')
+
+    telemetries = CarTelemetry.objects.select_related('car__paired_with')
+
+
+----
+
+
+==========================
+Cas des relations inverses
+==========================
+
+Pour chaque ``Car``, récupèrer les **n** télémétries associées
+
+::
+
+    !django
+    <div>
+    {% for car in cars %}
+        <ul>
+        {% for telemetry in car.telemetry_set.all %}
+            <li>IT'S OVER 9000!!!!!!</li>
+        {% endfor %}
+        </ul>
+    {% endfor %}
+    </div>
+
+Rappel du modèle : ::
+
+    !python
+    class CarTelemetry(models.Model):
+
+        car = models.ForeignKey(Car, related_name='telemetry_set')
+
+        ...
+
+
+----
+
+
+===========================================================
+Solution : simuler les joints SQL complexes à la main < 1.4
+===========================================================
+
+::
+
+    !python
+    cars = Car.objects.filter(is_locked=False)
+
+    telemetries = CarTelemetry.objects.filter(car__is_locked=False)
+
+    telemetries_by_car = {}
+    for t in telemetries:
+        telemetries_by_car.setdefault(t.car.pk, []).append(t)
+
+    # {18: [<CarTelemetry: 2012-02-29 10:44:36>,
+    #       <CarTelemetry: 2012-02-29 10:50:36>,
+    #       <CarTelemetry: 2012-02-29 10:54:38>]}
+
+    for car in cars:
+        car.telemetries = telemetries_by_car.get(car.id)
+
+
+----
+
+
+========================================
+Solution : ``prefetch_related()`` >= 1.4
+========================================
+
+::
+
+    !python
+    cars = Car.objects.filter(
+            is_locked=False,
+        ).prefetch_related(
+            'telemetry_set',
+        )
+
+- Exécute plusieurs requêtes SQL et fait la jointure en Python
+- Fonctionne avec des ``many-to-many`` et des ``many-to-one``
+- Fonctionne avec des ``GenericForeignKey``
+- Attention à la consommation mémoire !
+
+
+----
+
+
+================================
+Tester avec ``assertNumQueries``
+================================
+
+::
+
+    !python
+    class CarTestCase(TestCase):
+
+        def test_its_under_9000(self):
+
+            with self.assertNumQueries(3):
+                response = self.client.get(reverse('cars'))
+                self.assertEqual(response.status_code, 200)
+
+
+----
+
+
+===============
+Aller plus loin
+===============
+
+- Tester avec un jeu de données de production
+- ``db_index=True`` ajouter des Index SQL qui réduisent le nombre de candidats
+- Passer au ``raw SQL``
+- Dénormaliser
+- Envisager d'autres solutions : Haystack (Solr, Elasticsearch, Whoosh, Xapian)
+- NoSQL
+
+
+----
+
+
+==========
+Références
+==========
+
+- django-debug-toolbar https://github.com/django-debug-toolbar/django-debug-toolbar
+- Django prefetch_related https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related
+- Django Database access optimization https://docs.djangoproject.com/en/dev/topics/db/optimization/
+- Unbreaking Your Django Application http://lanyrd.com/2011/oscon/sgbkg/
+- Some quick Django optimisation lessons http://lukeplant.me.uk/blog/posts/some-quick-django-optimisation-lessons/
+- Django patterns, part 2: efficient reverse lookups http://blog.roseman.org.uk/2010/01/11/django-patterns-part-2-efficient-reverse-lookups/
+

File 2012.it.s.over.9000/what9000.png

Added
New image