Какое лучшее решение для пула соединений с базой данных в python?

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

Решение отлично работает, за исключением того, что каждый раз, когда делается новый запрос, я открываю новое соединение через MySQLdb.connect.

Какое лучшее решение для «вставки», чтобы переключить это на использование пула соединений в python? Я представляю что-то вроде общего решения DBCP для Java.

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

Отредактировано для добавления: После еще нескольких поисков я нашел anitpool.py, который выглядит прилично, но поскольку я относительно новичок к python Я думаю, я просто хочу убедиться, что не упустил более очевидное/более идиоматичное/лучшее решение.


person John    schedule 19.09.2008    source источник


Ответы (8)


ИМО, более очевидное/более идиоматичное/лучшее решение - использовать существующую ORM, а не изобретать классы, подобные DAO.

Мне кажется, что ORM более популярны, чем необработанные соединения SQL. Почему? Потому что Python является объектно-ориентированным, и сопоставление строки SQL с объектом является абсолютно необходимым. Существует не так много случаев использования, когда вы имеете дело со строками SQL, которые не сопоставляются с объектами Python.

Я думаю, что SQLAlchemy или SQLObject (и связанный с ним пул соединений) являются более идиоматичными решениями Pythonic.

Объединение в пул как отдельная функция не очень распространено, потому что чистый SQL (без сопоставления объектов) не очень популярен для сложных, длительных процессов, которые выигрывают от объединения соединений. Да, чистый SQL используется, но он всегда используется в более простых или более контролируемых приложениях, где объединение в пул бесполезно.

Я думаю, у вас может быть два варианта:

  1. Пересмотрите свои классы, чтобы использовать SQLAlchemy или SQLObject. Хотя поначалу это кажется болезненным (вся эта работа потрачена впустую), вы должны быть в состоянии использовать весь дизайн и мысли. Это просто упражнение по внедрению широко используемого решения ORM и пула.
  2. Разверните свой собственный простой пул соединений, используя описанный вами алгоритм — простой набор или список соединений, которые вы циклически перебираете.
person S.Lott    schedule 19.09.2008

В MySQL?

Я бы сказал, не беспокойтесь о пуле соединений. Они часто являются источником проблем, и с MySQL они не принесут вам преимущества в производительности, на которое вы надеетесь. Этот путь может потребовать больших усилий — политически — потому что в этом пространстве так много передовых практик и пустословия в учебниках о преимуществах пула соединений.

Пулы соединений — это просто мост между пост-веб-эрой приложений без сохранения состояния (например, протокола HTTP) и до-веб-эрой долгоживущих приложений пакетной обработки с отслеживанием состояния. Поскольку соединения в базах данных до Интернета были очень дорогими (поскольку никто не слишком заботился о том, сколько времени требуется для установления соединения), пост-веб-приложения разработали эту схему пула соединений, чтобы каждое попадание не вызывало таких огромных накладных расходов на обработку. на РСУБД.

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

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

person mbac32768    schedule 19.09.2008
comment
Спустя 8 лет после публикации этого ответа объединение по-прежнему остается актуальным. Если вы запускаете веб-приложение с интенсивным трафиком, вы можете легко столкнуться с ограничением «Слишком много подключений», независимо от его отсутствия состояния. Пул поможет смягчить это, ожидая бесплатного подключения вместо жесткого сбоя. Кроме того, если вы хотите масштабировать свой сервер приложений горизонтально, ваша база данных, вероятно, не будет жить на той же машине. В этом случае вы, скорее всего, захотите подключиться к нему по протоколу HTTPS, который имеет значительные накладные расходы. Здесь тоже поможет бассейн. - person Joe; 13.09.2016

Оберните свой класс подключения.

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

Обновление: я поместил что-то вроде этого в dbpool.py:

import sqlalchemy.pool as pool
import MySQLdb as mysql
mysql = pool.manage(mysql)
person Chris    schedule 19.09.2008
comment
Крис, наверняка кто-то уже построил это? В худшем случае я могу написать это сам, но, очевидно, это должно быть довольно распространенным требованием для людей, не использующих существующие ORM/фреймворки, и я уверен, что кто-то уже создал решение, проверенное временем? - person John; 19.09.2008
comment
Я делал это раньше с Oracle, и я думаю, что в общей сложности это заняло менее 50 строк кода. По сути, используйте идентификатор, словарь, сохраните соединение, сохраните статус использования и т. д. Очень просто? - person Chris; 19.09.2008
comment
@Chris, согласно этой логической цепочке, я тоже должен начать реализовывать свои хэш-карты и списки самостоятельно. - person Martin Konecny; 08.10.2013

Старый поток, но для пула общего назначения (соединений или любого дорогого объекта) я использую что-то вроде:

def pool(ctor, limit=None):
    local_pool = multiprocessing.Queue()
    n = multiprocesing.Value('i', 0)
    @contextlib.contextmanager
    def pooled(ctor=ctor, lpool=local_pool, n=n):
        # block iff at limit
        try: i = lpool.get(limit and n.value >= limit)
        except multiprocessing.queues.Empty:
            n.value += 1
            i = ctor()
        yield i
        lpool.put(i)
    return pooled

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

# in main:
my_pool = pool(lambda: do_something())
# in thread:
with my_pool() as my_obj:
    my_obj.do_something()

Это предполагает, что любой объект, который создает ctor, имеет соответствующий деструктор, если это необходимо (некоторые серверы не убивают объекты подключения, если они не закрыты явно).

person metaperture    schedule 14.07.2014
comment
Вы забыли две вещи: 1. yield i может вызвать исключение, поэтому вы должны обернуть его с помощью try...except. 2. lpool.put(i) может возвращать объект в неправильном состоянии (например, соединение с БД с открытой транзакцией) - person socketpair; 05.07.2016
comment
Выдача исключения должна фактически обрабатываться менеджером контекста. Независимо от того, как происходит выход из контекста (исключение или иное), остальная часть функции будет работать. Но да, если вы выполняете манипуляции с состоянием в базе данных, хорошей идеей будет обработка этого в бите функции после выхода. - person metaperture; 05.07.2016
comment
На практике использование объекта пула в отредактированном посте Криса, вероятно, лучше, но для тех, кто хочет узнать, как реализовать пулы в целом, я думаю, что это хороший пример. - person metaperture; 05.07.2016

Я как раз искал нечто подобное.

Я нашел pysqlpool и модуль пула sqlalchemy

person Community    schedule 14.05.2009

Создание собственного пула соединений — ПЛОХАЯ идея, если ваше приложение когда-нибудь решит начать использовать многопоточность. Создание пула соединений для многопоточного приложения намного сложнее, чем для однопоточного приложения. В этом случае вы можете использовать что-то вроде PySQLPool.

Также ПЛОХАЯ идея использовать ORM, если вам нужна производительность.

Если вы будете иметь дело с огромными/тяжелыми базами данных, которые должны обрабатывать множество выборок, вставок, обновлений и удалений одновременно, вам понадобится производительность, а это означает, что вам понадобится собственный SQL, написанный для оптимизации поиска. и время блокировки. С ORM у вас обычно нет такой гибкости.

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

person flexo    schedule 22.08.2011

Отвечая на старый поток, но в последний раз, когда я проверял, MySQL предлагает пул соединений как часть своих драйверов.

Вы можете ознакомиться с ними по адресу:

https://dev.mysql.com/doc/connector-python/en/connector-python-connection-pooling.html

Из TFA, если вы хотите явно открыть пул соединений (как заявил OP):

dbconfig = {  "database": "test", "user":"joe" }
cnxpool = mysql.connector.pooling.MySQLConnectionPool(pool_name = "mypool",pool_size = 3, **dbconfig)

Затем доступ к этому пулу осуществляется путем запроса из пула через функцию get_connection().

cnx1 = cnxpool.get_connection()
cnx2 = cnxpool.get_connection()
person kilokahn    schedule 10.06.2017

Используйте DBUtils, просто и надежно.

pip install DBUtils
person ospider    schedule 11.11.2018