From 9012e34c6de9fccd4cd470b82e93ee6cbd214a7c Mon Sep 17 00:00:00 2001
From: Benjamin Bertrand <benjamin.bertrand@esss.se>
Date: Tue, 9 Oct 2018 09:49:26 +0200
Subject: [PATCH] Improve relationship loading

Decrease the number of SELECT calls by loading relationships that are
almost always used.

See https://docs.sqlalchemy.org/en/latest/orm/loading_relationships.html

JIRA INFRA-595
---
 app/models.py | 54 ++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 38 insertions(+), 16 deletions(-)

diff --git a/app/models.py b/app/models.py
index 875410d..7c03b28 100644
--- a/app/models.py
+++ b/app/models.py
@@ -523,13 +523,15 @@ class Item(CreatedMixin, SearchableMixin, db.Model):
     host_id = db.Column(db.Integer, db.ForeignKey("host.id"))
     stack_member = db.Column(db.SmallInteger)
 
-    manufacturer = db.relationship("Manufacturer", back_populates="items")
-    model = db.relationship("Model", back_populates="items")
-    location = db.relationship("Location", back_populates="items")
-    status = db.relationship("Status", back_populates="items")
+    manufacturer = db.relationship(
+        "Manufacturer", back_populates="items", lazy="joined"
+    )
+    model = db.relationship("Model", back_populates="items", lazy="joined")
+    location = db.relationship("Location", back_populates="items", lazy="joined")
+    status = db.relationship("Status", back_populates="items", lazy="joined")
     children = db.relationship("Item", backref=db.backref("parent", remote_side=[id]))
-    macs = db.relationship("Mac", backref="item")
-    comments = db.relationship("ItemComment", backref="item")
+    macs = db.relationship("Mac", backref="item", lazy="joined")
+    comments = db.relationship("ItemComment", backref="item", lazy="joined")
 
     __table_args__ = (
         sa.CheckConstraint(
@@ -643,7 +645,9 @@ class Network(CreatedMixin, db.Model):
     scope_id = db.Column(db.Integer, db.ForeignKey("network_scope.id"), nullable=False)
     domain_id = db.Column(db.Integer, db.ForeignKey("domain.id"), nullable=False)
 
-    interfaces = db.relationship("Interface", backref="network")
+    interfaces = db.relationship(
+        "Interface", backref=db.backref("network", lazy="joined"), lazy=True
+    )
 
     __table_args__ = (
         sa.CheckConstraint("first_ip < last_ip", name="first_ip_less_than_last_ip"),
@@ -811,7 +815,9 @@ class DeviceType(db.Model):
     id = db.Column(db.Integer, primary_key=True)
     name = db.Column(CIText, nullable=False, unique=True)
 
-    hosts = db.relationship("Host", backref="device_type")
+    hosts = db.relationship(
+        "Host", backref=db.backref("device_type", lazy="joined"), lazy=True
+    )
 
     @validates("name")
     def validate_name(self, key, string):
@@ -974,13 +980,18 @@ class Host(CreatedMixin, db.Model):
     # Set cascade to all (to add delete) and delete-orphan to delete all interfaces
     # when deleting a host
     interfaces = db.relationship(
-        "Interface", backref="host", cascade="all, delete-orphan"
+        "Interface",
+        backref=db.backref("host", lazy="joined"),
+        cascade="all, delete-orphan",
+        lazy="joined",
+    )
+    items = db.relationship(
+        "Item", backref=db.backref("host", lazy="joined"), lazy="joined"
     )
-    items = db.relationship("Item", backref="host")
     ansible_groups = db.relationship(
         "AnsibleGroup",
         secondary=ansible_groups_hosts_table,
-        lazy=True,
+        lazy="joined",
         backref=db.backref("_hosts"),
     )
 
@@ -1102,7 +1113,10 @@ class Interface(CreatedMixin, db.Model):
     # - deleting an interface
     # - de-associating a cname (removing it from the interface.cnames list)
     cnames = db.relationship(
-        "Cname", backref="interface", cascade="all, delete, delete-orphan"
+        "Cname",
+        backref=db.backref("interface", lazy="joined"),
+        cascade="all, delete, delete-orphan",
+        lazy="joined",
     )
     tags = db.relationship(
         "Tag",
@@ -1188,7 +1202,9 @@ class Mac(db.Model):
     address = db.Column(postgresql.MACADDR, nullable=False, unique=True)
     item_id = db.Column(db.Integer, db.ForeignKey("item.id"))
 
-    interfaces = db.relationship("Interface", backref="mac")
+    interfaces = db.relationship(
+        "Interface", backref=db.backref("mac", lazy="joined"), lazy=True
+    )
 
     def __str__(self):
         return str(self.address)
@@ -1227,8 +1243,12 @@ class Cname(CreatedMixin, db.Model):
 class Domain(CreatedMixin, db.Model):
     name = db.Column(db.Text, nullable=False, unique=True)
 
-    scopes = db.relationship("NetworkScope", backref="domain")
-    networks = db.relationship("Network", backref="domain")
+    scopes = db.relationship(
+        "NetworkScope", backref=db.backref("domain", lazy="joined"), lazy=True
+    )
+    networks = db.relationship(
+        "Network", backref=db.backref("domain", lazy="joined"), lazy=True
+    )
 
     def __str__(self):
         return str(self.name)
@@ -1254,7 +1274,9 @@ class NetworkScope(CreatedMixin, db.Model):
     domain_id = db.Column(db.Integer, db.ForeignKey("domain.id"), nullable=False)
     description = db.Column(db.Text)
 
-    networks = db.relationship("Network", backref="scope")
+    networks = db.relationship(
+        "Network", backref=db.backref("scope", lazy="joined"), lazy=True
+    )
 
     __table_args__ = (
         sa.CheckConstraint(
-- 
GitLab