Django персистентное соединение с базой данных

Извините, это - Python вместо C#, но по крайней мере результаты корректны:

def ColIdxToXlName(idx):
    if idx < 1:
        raise ValueError("Index is too small")
    result = ""
    while True:
        if idx > 26:
            idx, r = divmod(idx - 1, 26)
            result = chr(r + ord('A')) + result
        else:
            return chr(idx + ord('A') - 1) + result


for i in xrange(1, 1024):
    print "%4d : %s" % (i, ColIdxToXlName(i))
54
задан HardQuestions 14 July 2009 в 02:47
поделиться

4 ответа

Заявление об ограничении ответственности: я не пробовал этого.

Я считаю, что вам необходимо реализовать собственный сервер базы данных. В Интернете есть несколько примеров, которые показывают, как реализовать серверную часть базы данных с пулом соединений.

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

  • В этом сообщении это достигается путем исправления Django (в одном из комментариев указывается, что лучше реализовать собственный сервер вне основного кода django).
  • Этот пост представляет собой реализацию пользовательский сервер базы данных

Оба сообщения используют MySQL - возможно, вы сможете использовать аналогичные методы с Postgresql.

Изменить:

  • В книге Django упоминается объединение соединений Postgresql с использованием pgpool ( tutorial ).
  • Кто-то опубликовал патч для бэкэнда psycopg2, который реализует пул соединений. Я предлагаю создать копию существующей серверной части в вашем собственном проекте и исправить ее.
3
ответ дан 7 November 2019 в 08:02
поделиться

В транке Django отредактируйте django / db / __ init__. py и закомментируйте строку:

signals.request_finished.connect(close_connection)

Этот обработчик сигнала заставляет его отключаться от базы данных после каждого запроса. Я не знаю, каковы будут все побочные эффекты от этого, но нет никакого смысла начинать новое соединение после каждого запроса; это снижает производительность, как вы заметили.

Я использую это сейчас, но я не проводил полного набора тестов, чтобы увидеть, не сломается ли что-нибудь.

Я не знаю, почему все думают, что это необходимо новый бэкэнд, специальный пул подключений или другие сложные решения. Это кажется очень простым, хотя я не сомневаюсь, что есть некоторые неясные подводные камни, которые заставили их сделать это в первую очередь - с которыми следует разбираться более разумно; Как вы заметили, накладные расходы в 5 мс на каждый запрос - это довольно много для высокопроизводительного сервиса. (У меня уходит 150 мсек - я еще не понял почему.)

Редактировать: еще одно необходимое изменение находится в django / middleware / transaction.py; удалите два теста transaction.is_dirty () и всегда вызывайте commit () или rollback (). В противном случае транзакция не будет зафиксирована, если она будет только читать из базы данных, в результате чего блокировки останутся открытыми, которые следует закрыть.

20
ответ дан 7 November 2019 в 08:02
поделиться

Я сделал небольшой пользовательский бэкэнд psycopg2, который реализует постоянное соединение с использованием глобальной переменной. Благодаря этому я смог улучшить количество запросов в секунду с 350 до 1600 (на очень простой странице с несколькими вариантами выбора). Просто сохраните его в файле с именем base.py в любом каталоге (например, postgresql_psycopg2_persistent) и установите в настройках

DATABASE_ENGINE имя проекта.postgresql_psycopg2_persistent

ПРИМЕЧАНИЕ !!! код не является потокобезопасным - вы не можете использовать его с потоками python из-за неожиданных результатов, в случае mod_wsgi используйте режим демона prefork с thread = 1


# Custom DB backend postgresql_psycopg2 based
# implements persistent database connection using global variable

from django.db.backends.postgresql_psycopg2.base import DatabaseError, DatabaseWrapper as BaseDatabaseWrapper, \
    IntegrityError
from psycopg2 import OperationalError

connection = None

class DatabaseWrapper(BaseDatabaseWrapper):
    def _cursor(self, *args, **kwargs):
        global connection
        if connection is not None and self.connection is None:
            try: # Check if connection is alive
                connection.cursor().execute('SELECT 1')
            except OperationalError: # The connection is not working, need reconnect
                connection = None
            else:
                self.connection = connection
        cursor = super(DatabaseWrapper, self)._cursor(*args, **kwargs)
        if connection is None and self.connection is not None:
            connection = self.connection
        return cursor

    def close(self):
        if self.connection is not None:
            self.connection.commit()
            self.connection = None

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

# Custom DB backend postgresql_psycopg2 based
# implements persistent database connection using thread local storage
from threading import local

from django.db.backends.postgresql_psycopg2.base import DatabaseError, \
    DatabaseWrapper as BaseDatabaseWrapper, IntegrityError
from psycopg2 import OperationalError

threadlocal = local()

class DatabaseWrapper(BaseDatabaseWrapper):
    def _cursor(self, *args, **kwargs):
        if hasattr(threadlocal, 'connection') and threadlocal.connection is \
            not None and self.connection is None:
            try: # Check if connection is alive
                threadlocal.connection.cursor().execute('SELECT 1')
            except OperationalError: # The connection is not working, need reconnect
                threadlocal.connection = None
            else:
                self.connection = threadlocal.connection
        cursor = super(DatabaseWrapper, self)._cursor(*args, **kwargs)
        if (not hasattr(threadlocal, 'connection') or threadlocal.connection \
             is None) and self.connection is not None:
            threadlocal.connection = self.connection
        return cursor

    def close(self):
        if self.connection is not None:
            self.connection.commit()
            self.connection = None
0
ответ дан 7 November 2019 в 08:02
поделиться

Попробуйте PgBouncer - облегченный пул соединений для PostgreSQL. Особенности:

  • Несколько уровней жестокости при вращении соединений:
    • Пул сеансов
    • Пул транзакций
    • Пул операторов
  • Низкие требования к памяти (2 КБ на соединение по умолчанию).
22
ответ дан 7 November 2019 в 08:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: