Postgres: как запустить несколько запросов одновременно? - PullRequest
2 голосов
/ 19 августа 2010

У меня есть одна процедура, которая обновляет значения записей, и я хочу запустить ее для всех записей в таблице (более 30 тыс. Записей), время выполнения процедуры составляет от 2 до 10 секунд, потому что это зависит от сетевой нагрузки.

Теперь я делаю ОБНОВЛЕНИЕ таблицы SET. Field = имя_процедуры (paramns); но при таком количестве записей обработка всей таблицы занимает до 40 минут.

Теперь я использую 4 разных соединения с фоном и запускает запрос с предложением WHERE, перебирающим по модулю идентификаторов строк, чтобы ускорить это (WHERE id_field% 4 =), и это работает хорошо и сокращает заполнение таблицы до ~ 10 мин.

Но я хочу избежать использования cron, shell-заданий и нескольких соединений для этого, я знаю, что это можно сделать с помощью libpq, но есть ли способ запустить запрос (4 разных неблокирующих запроса) и не подождать, пока не закончится выполнение, в пределах одного соединения?

Или, если кто-нибудь может указать мне на некоторые подсказки о том, как написать эту функцию, используя внутренние компоненты postgres или просто в C, и связать ее как хранимую процедуру?

Приветствия Дария

Ответы [ 4 ]

1 голос
/ 20 августа 2010

У меня есть верный ответ на этот вопрос - ЕСЛИ вы поделитесь с нами вашими тренировками !!!Я сгущаюсь с каждой минутой, и мне самим нужны ответы ...

ОК, я все равно отвечу.

Если вы обновляете одну таблицу на одном сервере базы данных через 40 минут«однопоточное» и за 10 минут с 4 потоками узкое место не является сервером базы данных;в противном случае это может быть связано с вводом / выводом.Если вы выполняете кучу ОБНОВЛЕНИЙ, по одному вызову на запись, то обходной путь в сети убивает вас.

Я почти уверен, что это так, а не то, что это узкое место ввода-выводаБД или вероятность того, что имя_процедуры (paramns);занимает много времени.(Если бы это была процедура, занимающая 2-10 секунд, это заняло бы около 2500 минут, чтобы сделать 30K записей).Я уверен, что причина в том, что запуск 4 одновременно обработанных сокращает время на 1/4.Поэтому особенно это не проблема ввода-вывода на сервере БД.

Это может быть единственным оправданием для помещения бизнес-логики в SP на сервере.Оптимизация, к сожалению, означает нарушение правил.Следствием является сложное техническое обслуживание.но!

Однако, лучшее решение - настроить этот параметр на использование запросов «массового обновления».Это может означать, что вы должны предпринять несколько странных и не интуитивно понятных шагов, таких как:

  • Это потребует значительных модификаций, если несколько пользователей могут запускать его одновременно.
  • рефакторинг системы так,имя_процедуры (paramns) может получить все данные, необходимые для обработки всех записей, с помощью оператора select.Возможно, потребуется использовать творческие объединения.Если это, конечно, SP, теперь вы переносите логику на клиент.
  • Используйте, чтобы программа создала XML или другой импортируемый формат плоского файла с PK записи для обновления и новым значением поляили значения.Запишите все обновления в этот файл вместо выполнения их в БД.
  • имеет временную таблицу в базе данных, которая соответствует макету этого плоского файла
  • , запустите импорт в базу данных - очиститьвременную таблицу и импортируйте файл
  • обновите объединение временной таблицы и обновляемой таблицы, например, UPDATE mytbl, mytemp WHERE myPK = mytempPK SET myval = mytempnewval (используйте правильный синтаксис объединенияконечно).
  • Вы можете сначала попробовать некоторые из этих вещей "вручную", прежде чем потрудиться кодировать, чтобы увидеть, стоит ли увеличение скорости.
  • Если возможно, вы можете поставить этовсе в SP!

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

1 голос
/ 10 января 2014

Возможно обновить несколько строк одновременно. Ниже приведен пример в postgres:

UPDATE
    table_name
SET
    column_name = temp.column_name 
FROM
    (VALUES
        (<id1>, <value1>),
        (<id2>, <value2>),
        (<id3>, <value3>)
    ) AS temp("id", "column_name")
WHERE
    table_name.id = temp.id
0 голосов
/ 10 января 2014

Я думаю, что вы не можете. Одно соединение может обрабатывать один запрос одновременно. Это описано в главе документации libpq «Асинхронная обработка команд»:

"После успешного вызова PQsendQuery вызовите PQgetResult один или несколько раз, чтобы получить результаты. PQsendQuery нельзя вызвать повторно (для того же соединения), пока PQgetResult не вернет нулевой указатель, указывающий, что команда выполнена."

0 голосов
/ 20 августа 2010

PHP имеет некоторые функции для асинхронных запросов :

  • pg_ send_ execute ()
  • pg_ send_ prepare ()
  • pg_send_query ()
  • pg_ send_ query_ params ()

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

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