Как я могу ускорить этот запрос PostgreSQL UPDATE FROM sql? В настоящее время для завершения sh работы требуется несколько дней - PullRequest
1 голос
/ 21 июня 2020

Как я могу ускорить выполнение запроса PostgreSQL UPDATE FROM sql ниже? В настоящее время требуется несколько дней для завершения sh выполнения.

UPDATE import_parts ip
SET part_part_id = pp.id
FROM parts.part_parts pp
WHERE pp.upc = ip.upc
AND (ip.status is null or ip.status != '6'); 

И почему для запуска требуются дни?

В большинстве случаев я вручную завершаю запрос, потому что бегать нужно слишком долго, как более 24 часов. Последний раз, когда он успешно завершил работу, это заняло почти 38 часов.

import_parts таблица имеет 971971 строк

parts.part_parts таблица имеет 2196357 строк

* Таблица 1016 * имеет индекс на upc, а id является первичным ключом таблицы.

Я уже пробовал запустить VACUUM ANALYZE на import_parts таблице и parts.part_parts таблице перед запросом обновления выше выполняется, но запрос по-прежнему выполняется слишком долго, поэтому я вручную отключил его через 30 минут. Я надеюсь, что смогу выполнить запрос менее чем за 30 минут.

Вот результат EXPLAIN, когда я запускаю запрос после выполнения VACUUM ANALYZE в import_parts таблице и parts.part_parts таблице:

result of EXPLAIN

UPDATE 1:

I also tried setting enable_nestloop to off: SET enable_nestloop TO off

But the query still takes too long to run so I manually killed it. Here's the result of EXPLAIN when enable_nestloop is turned off:

result of EXPLAIN when nestloop is turned off

UPDATE 2:

Here's the result of EXPLAIN when using the query suggested by Abelisto on his answer to this post:

результат Explain с использованием предложенного запроса Abelisto

Но когда я действительно запускаю запрос, я сталкиваюсь с этой ошибкой:

ERROR: more than one row returned by a subquery used as an expression

Я все еще пытаюсь исправить ошибку .

Ответы [ 3 ]

2 голосов
/ 21 июня 2020

Прежде всего, попробуйте переписать свой запрос, например,

UPDATE import_parts ip
SET part_part_id = (
  SELECT pp.id
  FROM parts.part_parts pp
  WHERE pp.upc = ip.upc)
WHERE status is null or status != '6'; 

Очевидно, что он вызывает что-то вроде

ERROR:  more than one row returned by a subquery used as an expression

Исправьте его, используя дополнительные условия (подзапрос должен возвращать ровно один или нулевая строка для каждой строки в целевой таблице)

1 голос
/ 21 июня 2020

Из того, что вы говорите, кажется, что upc не уникален в parts_parts. Попробуйте запустить это:

select upc, count(*)
from parts.parts_parts pp
group by upc
having count(*) > 1;

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

UPDATE import_parts ip
  SET part_part_id = pp.id
  FROM (SELECT pp.upc, MIN(pp.id) as id
        FROM parts.part_parts pp
        GROUP BY pp.upc
       ) pp
  WHERE pp.upc = ip.upc AND (ip.status is null or ip.status <> '6'); 
0 голосов
/ 21 июня 2020
  1. Создайте индекс с in import_parts со столбцами: up c, status.

  2. Я рекомендую вам разделить на два предложения:

Я не знаю вашего статуса, но полагаю, у вас есть статус: null, 1, 2, 3, 4, 5, 6, 7

UPDATE import_parts ip
SET part_part_id = pp.id
FROM parts.part_parts pp
WHERE pp.upc = ip.upc
AND ip.status is null
;

UPDATE import_parts ip
SET part_part_id = pp.id
FROM parts.part_parts pp
WHERE pp.upc = ip.upc
AND ip.status IN(1, 2, 3, 4, 5, 7)
;

Конечно, вам нужно изменить 1, 2, 3, 4, 5, 7 для ваших значений (отличных от 6)

Мне также нравится ответ @ Гордон Линофф, но это зависит от того, сколько у вас строк на c

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