Как построить отношения SQLAlchemy для повышения производительности? - PullRequest
0 голосов
/ 01 мая 2019

Я построил две модели Message и EmailAddress, которые связаны в соотношении «многие ко многим» с помощью таблицы MessageEmailAddress.(Я использовал Model класс для MessageEmailAddress, потому что есть метаданные action, связанные с отношением.) Эти relationships все lazy=dynamic.

Запуск метода экземпляра Message.add_email_address()невероятно медленно, ок.1,5 секунды на объект !!Метод, который необходимо проверить, существует ли ранее существующее отношение (т. Е. Строка в MessageEmailAddress), а если нет, то создать новое.

Как построить более производительные отношения между таблицами?Какой элемент моего кода вызывает такую ​​медленную работу?

Я пробовал много других способов создания отношения «многие ко многим» со связанными метаданными - это единственный способ, который не вызывал ошибок.

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()


class Message(db.Model):
    """A single message."""
    id = db.Column(db.Integer, primary_key=True)

    # Is there a way to dynamically create these?
    _email_addresses = relationship(
        "EmailAddress",
        secondary="message_email_address", lazy='dynamic', backref=backref("_messages", lazy='dynamic'))
    _email_addresses_from = relationship(
        "EmailAddress",
        primaryjoin="and_(Message.id==MessageEmailAddress.message_id, MessageEmailAddress.action=='from')",
        secondary="message_email_address",
        lazy='dynamic',
        backref=backref('_messages_from', lazy='dynamic')
    )
    _email_addresses_to = relationship(
        "EmailAddress",
        primaryjoin="and_(Message.id==MessageEmailAddress.message_id, MessageEmailAddress.action=='to')",
        secondary="message_email_address",
        lazy='dynamic',
        backref=backref('_messages_to', lazy='dynamic')
    )

    def add_email_address(self, email_str, action, name=None):
        """Setter method for all related EmailAddress objects.

        Args:
            email_str: A string, ex. "david@gmail.com"
            action: A string describing header action, ex. "from"
            name: Optional string for name of EmailAddress

        """
        # Ensure connection between Message, EmailAddress, and action is unique
        action_prop = '_email_addresses_' + action
        pre_existing = getattr(self, action_prop).filter_by(email_address=email_str).all()

        if pre_existing and len(pre_existing):
            return

        # Add new connection
        email_address = EmailAddress.get_or_create(
            email_address=email_str, create_kwargs=dict(name=name))
        a = MessageEmailAddress(message_id=self.id, email_id=email_address.id, action=action)
        db.session.add(a)
        db.session.commit()

        return email_address


class EmailAddress(db.Model, ModelMixin):
    """A single email address.

    Relationships to Message: _messages, _messages_from, _messages_to, etc.
    """
    id = db.Column(db.Integer, primary_key=True)
    ...


class MessageEmailAddress(db.Model):
    # Join Message and EmailAddress tables
    id = db.Column(db.Integer, primary_key=True)
    message_id = db.Column(
        db.Integer, db.ForeignKey('message.id'), nullable=False)
    email_id = db.Column(
        db.Integer, db.ForeignKey('email_address.id'), nullable=False)
    action = db.Column(db.String(), nullable=False)  # Ex. From, To, Bcc

    message = db.relationship("Message", backref=backref("message_email_address", lazy='dynamic'))
    email_address = db.relationship("EmailAddress", backref=backref("message_email_address", lazy='dynamic'))
...