SQLAlchemy «по умолчанию» против производительности «server_default»

1

Есть ли преимущество в производительности (или недостаток) при использовании default вместо server_default для отображения значений по умолчанию для столбцов таблицы при использовании SQLAlchemy с PostgreSQL?

server_default я понимаю, что по default визуализирует выражение в INSERT (обычно), и что server_default помещает выражение в оператор CREATE TABLE. Похоже, server_default является аналогом типичной обработки значений по умолчанию непосредственно в БД, таких как:

CREATE TABLE example (
    id serial PRIMARY KEY,
    updated timestamptz DEFAULT now()
);

... но мне неясно, будет ли эффективнее обрабатывать значения по умолчанию при INSERT или при создании таблицы.

Будет ли какое-либо улучшение или ухудшение производительности при вставке строк, если каждый из параметров по default в приведенном ниже примере был изменен на server_default?

from uuid import uuid4
from sqlalchemy import Column, Boolean, DateTime, Integer
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql import func

Base = declarative_base()

class Item(Base):
    __tablename__ = 'item'

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
    count = Column(Integer, nullable=False, default=0)
    flag = Column(Boolean, nullable=False, default=False)
    updated = Column(DateTime(timezone=True), nullable=False, default=func.now())

ПРИМЕЧАНИЕ. Лучшее объяснение, которое я нашел на тот момент, когда использовать default вместо server_default не относится к производительности (см. Ответ Mike Bayer SO на эту тему). Мое упрощенное резюме этого объяснения server_default что по default предпочтительнее, чем server_default когда...

  • БД не может обработать выражение, которое вам нужно или вы хотите использовать для значения по умолчанию.
  • Вы не можете или не хотите изменять схему напрямую.

... так что остается вопрос о том, следует ли учитывать производительность при выборе между default и server_default?

Теги:
performance
sqlalchemy

1 ответ

0

Невозможно дать вам ответ "это быстрее", потому что производительность в расчете на значение по умолчанию может сильно различаться как на сервере, так и в Python. Функция для получения текущего времени ведет себя не так, как скалярное значение по умолчанию.

Затем вы должны понимать, что значения по умолчанию могут быть предоставлены пятью различными способами:

Обратите внимание, что когда речь идет о выражении SQL, определяющем значение по умолчанию, будь то выражение SQL на стороне клиента, выражение DLL на стороне сервера или триггер, это очень мало влияет на базу данных, откуда исходит выражение значения по умолчанию, Исполнителю запроса необходимо знать, как создать значения для данного столбца, после того, как он был проанализирован в операторе DML или определении схемы, сервер все равно должен выполнить выражение для каждой строки.

Выбор между этими вариантами редко основывается на одной только производительности, производительность должна быть не более, чем одним из множества аспектов, которые вы рассматриваете. Здесь много факторов:

  • default со скалярной или Python-функцией напрямую создает значение по умолчанию Python, а затем отправляет новое значение на сервер при вставке. Код Python может получить доступ к значению по умолчанию, прежде чем данные будут вставлены в базу данных.
  • У выражения SQL на стороне клиента, значения server_default и неявных значений по умолчанию и триггеров на стороне сервера все серверы генерируют значение по умолчанию, которое затем должен быть получен клиентом, если вы хотите иметь доступ к нему в том же сеансе SQLAlchemy. Вы не можете получить доступ к значению, пока объект не будет вставлен в базу данных.

    В зависимости от точного запроса и поддержки базы данных, SQLAlchemy может потребоваться выполнить дополнительные запросы SQL, чтобы либо сгенерировать значение по умолчанию перед оператором INSERT либо запустить отдельный SELECT впоследствии, чтобы получить значения по умолчанию, которые были вставлены. Вы можете контролировать, когда это происходит (непосредственно при вставке или при первом доступе после eager_defaults, с помощью eager_defaults mapper eager_defaults).

  • Если у вас есть несколько клиентов на разных платформах, обращающихся к одной и той же базе данных, server_default или другое значение по умолчанию, присоединенное к схеме (например, триггер), гарантирует, что все клиенты будут использовать одни и те же значения по умолчанию, несмотря на то, что к значениям по умолчанию, реализованным в Python, невозможно получить доступ другими платформами.

При использовании PostgreSQL SQLAlchemy может использовать предложение RETURNING для операторов DML, которое предоставляет клиенту доступ к сгенерированным по умолчанию настройкам на стороне сервера за один шаг.

Таким образом, при использовании server_default умолчанию для столбца server_default котором вычисляется новое значение для каждой строки (не скалярное значение), вы экономите небольшое количество времени на стороне Python и сохраняете небольшую пропускную способность сети, поскольку вы не отправляете данные для этого столбца. к базе данных. База данных может быстрее создавать то же значение или медленнее; это во многом зависит от типа операции. Если вам нужно иметь доступ к сгенерированному значению по умолчанию из Python, в той же транзакции вам придется ждать обратного потока данных, проанализированных SQLAlchemy. Однако все эти детали могут стать незначительными по сравнению со всем остальным, что происходит при вставке или обновлении строк.

Поймите, что ORM не подходит для высокопроизводительных массовых вставок или обновлений строк; цитата из записи FAQ по производительности SQAlchemy:

SQLAlchemy ORM использует шаблон единицы работы при синхронизации изменений в базе данных. Эта модель выходит далеко за рамки простых "вставок" данных. Он включает в себя то, что атрибуты, которые назначаются объектам, принимаются с использованием системы инструментария атрибутов, которая отслеживает изменения в объектах по мере их внесения, включает в себя то, что все вставленные строки отслеживаются в карте идентификаторов, что приводит к тому, что для каждой строки SQLAlchemy должна получать свои " последний вставленный идентификатор ", если он еще не задан, и также включает в себя то, что вставляемые строки сканируются и сортируются по зависимостям по мере необходимости. Объекты также подлежат значительной степени бухгалтерского учета, чтобы поддерживать все это в рабочем состоянии, что для очень большого количества строк может одновременно создавать чрезмерное количество времени, затрачиваемого на большие структуры данных, поэтому лучше всего их разбивать на части.

По сути, единица работы - это большая степень автоматизации, позволяющая автоматизировать задачу сохранения графа сложного объекта в реляционной базе данных без явного кода постоянства, и эта автоматизация имеет свою цену.

ORM в основном не предназначены для высокопроизводительных массовых вставок - вот почему SQLAlchemy предлагает Core в дополнение к ORM в качестве первоклассного компонента.

Поскольку ORM, такой как SQLAlchemy, стоит огромных накладных расходов, любые различия в производительности между серверной или Python-стороной по умолчанию быстро исчезают из-за шума операций ORM.

Поэтому, если вы беспокоитесь о производительности для операций вставки или обновления большого количества, вы можете использовать массовые операции для них и разрешить помощникам выполнения пакета psycopg2 действительно увеличить скорость. При использовании этих массовых операций я бы ожидал, что настройки по умолчанию на стороне сервера улучшат производительность, просто сохранив пропускную способность, перемещая данные строк из Python на сервер, но насколько это зависит от точного характера значений по умолчанию.

Если производительность вставки и обновления ORM вне массовых операций является для вас большой проблемой, вам необходимо проверить свои конкретные параметры. Я бы начал с пакета SQLAlchemy examples.performance и добавил бы свой собственный набор тестов, используя две модели, которые отличаются только одной server_default и конфигурацией по default.

  • 1
    Суть в том, что ORM, такой как SQLAlchemy, стоит огромных накладных расходов, и любые различия в производительности между серверной или Python-стороной по умолчанию быстро исчезают , и все эти полезные сведения здесь суммированы. В частности, вероятность того, что любая значительная производительность при выборе default или server_default часто низкая, и что, учитывая природу по умолчанию, потребности, связанные с доступом к значениям по умолчанию, и требования к приложениям, которые лучше всего подходят для SQLAlchemy ORM или Core, или сочетание обоих может наилучшим образом проинформировать это решение.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню