Postgres. Есть ли более быстрый способ обновить таблицу информацией из другой БД?

Я обновляю таблицу с именем Recipes и устанавливаю столбец ImageUrl в соответствующую строку в VIEW. Мой оператор UPDATE:

UPDATE Recipes R
  SET ImageUrl=L.ImageUrl
  FROM Link.Recipes L
  WHERE L.RecipeId=R.RecipeId AND L.ImageUrl is not null;

Link.Recipes — это VIEW, которое возвращает все Recipes строк из другой базы данных на другом сервере, так что это уже довольно медленно:

Запрос успешно возвращен: затронута 8541 строка, время выполнения 173236 мс.

Я хотел бы посмотреть, есть ли способ сделать это немного быстрее. Операторы INSERT, включающие одно и то же представление с одинаковым количеством строк, намного быстрее, поэтому здесь происходит что-то другое.

Конечно, в RecipeId есть индекс, однако ImageUrl не имеет индексов ни в одной из таблиц. Есть ли лучший способ написать этот оператор UPDATE, который не займет почти 3 минуты?

Объясните:

'Update  (cost=0.00..4136.54 rows=995 width=1531)'
'  ->  Nested Loop  (cost=0.00..4136.54 rows=995 width=1531)'
'        ->  Function Scan on dblink t1  (cost=0.00..10.00 rows=995 width=266)'
'              Filter: (imageurl IS NOT NULL)'
'        ->  Index Scan using recipes_pkey on recipes r  (cost=0.00..4.13 rows=1 width=1281)'
'              Index Cond: (r.recipeid = t1.recipeid)'

Объяснить Анализ:

'Update  (cost=0.00..4233.18 rows=995 width=1532) (actual time=168887.016..168887.016 rows=0 loops=1)'
'  ->  Nested Loop  (cost=0.00..4233.18 rows=995 width=1532) (actual time=23689.440..24500.006 rows=8549 loops=1)'
'        ->  Function Scan on dblink t1  (cost=0.00..10.00 rows=995 width=266) (actual time=23689.250..23749.288 rows=8550 loops=1)'
'              Filter: (imageurl IS NOT NULL)'
'        ->  Index Scan using recipes_pkey on recipes r  (cost=0.00..4.23 rows=1 width=1282) (actual time=0.083..0.085 rows=1 loops=8550)'
'              Index Cond: (r.recipeid = t1.recipeid)'
'Trigger trg_recipes_searchupdate: time=3808.617 calls=8549'
'Total runtime: 168889.272 ms'

person Mike Christensen    schedule 01.06.2012    source источник
comment
Представление использует dblink, который намного медленнее из-за дополнительного подключения к базе данных. Не могли бы вы также показать нам результат EXPLAIN ANALYZE? Это показывает вам, где время тратится.   -  person Frank Heikens    schedule 01.06.2012
comment
@FrankHeikens - Согласен. Однако мне интересно, почему это значительно медленнее, чем просто INSERT INTO Recipes SELECT * FROM Link.Recipes;   -  person Mike Christensen    schedule 01.06.2012
comment
@FrankHeikens — добавлен анализ объяснения   -  person Mike Christensen    schedule 02.06.2012
comment
Что делает триггер? Он использовался 8549 раз и работает медленно. dblink - другое узкое место, оно вам действительно нужно?   -  person Frank Heikens    schedule 02.06.2012
comment
@FrankHeikens — триггер обновляет столбец tsvector, используемый в полнотекстовом поиске. Мне определенно не нужно запускать его для каждой строки, я могу просто обновить все строки в конце. Хороший улов!   -  person Mike Christensen    schedule 01.07.2012


Ответы (1)


Вероятно, стоило бы создать частичный индекс для imageurl, а не null. Подробнее об этом читайте здесь: http://www.postgresql.org/docs/current/static/indexes-partial.html

person Mark Roberts    schedule 01.06.2012
comment
Кроме того, сколько строк в рецепте? Как выглядит план объяснения? - person Mark Roberts; 01.06.2012
comment
Я могу попробовать еще раз с частичным индексом на удаленном столе. Я также добавил объяснение. Обе таблицы Recipes содержат около 10 000 строк. - person Mike Christensen; 01.06.2012
comment
Мне любопытно, поможет ли индекс. ВИД просто вызывает функцию DBLink, которая выполняет SELECT * из удаленной таблицы. Поскольку VIEW не индексируется, индекс в удаленной таблице, вероятно, даже не будет использоваться, верно? - person Mike Christensen; 01.06.2012
comment
Нет, я бы не ожидал, что он будет использоваться в этом случае. Возможно, стоит создать другое представление, которое удаленно фильтрует URL-адрес изображения? - person Mark Roberts; 01.06.2012
comment
Да, это, вероятно, сработает, однако я хотел сделать этот запрос достаточно гибким, чтобы обновлять любой столбец или столбцы. На самом деле я только что удалил предложение WHERE, и это лишь немного быстрее. Я думаю, что большую часть времени тратится на отправку данных по сети. - person Mike Christensen; 01.06.2012
comment
Я обычно обнаруживал, что лучше перенести весь набор результатов в локальную базу данных, прежде чем пытаться выполнить подобное обновление. Это верно даже для Oracle и подсказки Driving_site. Я бы не ожидал, что CTAS займет много времени для таблицы из 10 тыс. строк. - person Mark Roberts; 01.06.2012