У меня есть таблица Postgres с ~ 2,1 миллиона строк. Я запустил обновление ниже:
WITH stops AS (
SELECT id,
rank() OVER (ORDER BY offense_timestamp,
defendant_dl,
offense_street_number,
offense_street_name) AS stop
FROM consistent.master
WHERE citing_jurisdiction=1
)
UPDATE consistent.master
SET arrest_id=stops.stop
FROM stops
WHERE master.id = stops.id;
Этот запрос занял 39 часов. Я использую это на 4-х (физическом) процессоре для ноутбука i7 Q720, много оперативной памяти, больше ничего не работает в большинстве случаев. Нет места на жестком диске. Стол был недавно очищен, проанализирован и переиндексирован.
Все время выполнения запроса, по крайней мере, после первоначального WITH
завершения, загрузка ЦП обычно была низкой, а жесткий диск использовался на 100%. Жесткий диск использовался так сильно, что любое другое приложение работало значительно медленнее, чем обычно.
Настройки питания ноутбука были на высокой производительности (Windows 7 x64).
Вот ОБЪЯСНЕНИЕ:
Update on master (cost=822243.22..1021456.89 rows=2060910 width=312)
CTE stops
-> WindowAgg (cost=529826.95..581349.70 rows=2060910 width=33)
-> Sort (cost=529826.95..534979.23 rows=2060910 width=33)
Sort Key: consistent.master.offense_timestamp, consistent.master.defendant_dl, consistent.master.offense_street_number, consistent.master.offense_street_name
-> Seq Scan on master (cost=0.00..144630.06 rows=2060910 width=33)
Filter: (citing_jurisdiction = 1)
-> Hash Join (cost=240893.51..440107.19 rows=2060910 width=312)
Hash Cond: (stops.id = consistent.master.id)
-> CTE Scan on stops (cost=0.00..41218.20 rows=2060910 width=48)
-> Hash (cost=139413.45..139413.45 rows=2086645 width=268)
-> Seq Scan on master (cost=0.00..139413.45 rows=2086645 width=268)
citing_jurisdiction=1
исключает только несколько десятков тысяч строк. Даже с этим WHERE
условием я все еще работаю над более чем 2 миллионами строк.
Жесткий диск полностью зашифрован с помощью TrueCrypt 7.1a. То , что замедляет немного, но не достаточно , чтобы вызвать запрос , чтобы принять , что много часов.
WITH
Часть занимает около 3 минут для запуска.
arrest_id
Поле не было никакого индекса внешнего ключа. В этой таблице 8 индексов и 2 внешних ключа. Все остальные поля в запросе индексируются.
arrest_id
Поле не было никаких ограничений , кроме NOT NULL
.
Всего в таблице 32 столбца.
arrest_id
имеет тип символов, меняющихся (20) . Я понимаю, что rank()
производит числовое значение, но я должен использовать переменный символ (20), потому что у меня есть другие строки, где citing_jurisdiction<>1
используются не числовые данные для этого поля.
arrest_id
Поле было пустым для всех строк с citing_jurisdiction=1
.
Это персональный, высококлассный (по состоянию на 1 год назад) ноутбук. Я единственный пользователь. Другие запросы или операции не выполнялись. Блокировка кажется маловероятной.
В этой таблице или в другом месте базы данных нет триггеров.
Другие операции с этой базой данных никогда не занимают много времени. При правильной индексации SELECT
запросы обычно выполняются довольно быстро.
источник
Seq Scan
немного страшно ...Ответы:
Недавно у меня произошло нечто подобное с таблицей из 3,5 миллионов строк. Мое обновление никогда не закончится. После долгих экспериментов и разочарований я наконец нашел виновника. Оказалось, что это индексы на обновляемой таблице.
Решение состояло в том, чтобы отбросить все индексы в обновляемой таблице перед выполнением оператора update. Как только я это сделал, обновление закончилось через несколько минут. После завершения обновления я заново создал индексы и вернулся к работе. Это, вероятно, не поможет вам на данный момент, но это может кто-то другой ищет ответы.
Я бы держал индексы в таблице, из которой вы извлекаете данные. Это не нужно будет постоянно обновлять индексы и должно помочь в поиске данных, которые вы хотите обновить. Он работал нормально на медленном ноутбуке.
источник
Ваша самая большая проблема заключается в выполнении огромного количества трудоемких операций записи на жестком диске ноутбука. Это никогда не будет быстрым, независимо от того, что вы делаете, особенно если это тип более медленного 5400 оборотов в минуту, поставляемый во многих ноутбуках.
TrueCrypt замедляет процесс записи больше, чем «немного». Чтение будет достаточно быстрым, но при записи RAID 5 будет выглядеть быстро. Запуск БД на томе TrueCrypt будет пыткой для записи, особенно случайной записи.
В этом случае, я думаю, вы бы потратили время на оптимизацию запроса. В любом случае вы переписываете большинство строк, и ваша ужасная ситуация записи будет медленной . Я бы порекомендовал:
Я подозреваю, что это будет быстрее, чем просто удаление и повторное создание только ограничений, потому что ОБНОВЛЕНИЕ будет иметь довольно случайные шаблоны записи, которые убьют ваше хранилище. Две массовые вставки, одна в незафиксированную таблицу, а другая в таблицу с протоколом WAL без ограничений, вероятно, будут быстрее.
Если у вас есть абсолютно обновленные резервные копии и вы не возражаете против восстановления базы данных из резервных копий, вы также можете перезапустить PostgreSQL с
fsync=off
параметром иfull_page_writes=off
временно для этой массовой операции. Любая непредвиденная проблема, такая как потеря питания или сбой ОС, оставит вашу базу данных без возможности восстановленияfsync=off
.POSTGreSQL, эквивалентный «no logging», - это использование незарегистрированных таблиц. Эти незагруженные таблицы усекаются, если БД нечисто выключается, пока они грязные. Использование незарегистрированных таблиц, по крайней мере, вдвое уменьшит нагрузку на запись и сократит количество запросов, поэтому они могут быть намного быстрее.
Как и в Oracle, может быть хорошей идеей удалить индекс, а затем заново создать его после большого пакетного обновления. Планировщик PostgreSQL не может понять, что происходит большое обновление, приостановить обновления индекса, а затем перестроить индекс в конце; даже если бы это было возможно, ему было бы очень трудно понять, в какой момент это стоит делать, особенно заранее.
источник
HOT
, лучше оставить индексы на месте. Если нет, то вы, вероятно, захотите удалить и заново создать. Столбец не индексируется, но для того, чтобы можно было выполнить ГОРЯЧЕЕ обновление, на той же странице также должно быть свободное место, так что это немного зависит от того, сколько мертвого пространства есть в таблице. Если это в основном для записи, я бы сказал, отказаться от всех индексов. Если он обновлен, у него могут быть дыры, и вы можете быть в порядке. Инструменты какpageinspect
иpg_freespacemap
могут помочь определить это.Кто-то даст лучший ответ для Postgres, но вот несколько замечаний с точки зрения Oracle, которые могут применяться (и комментарии слишком длинны для поля комментариев).
Моя первая задача - попытаться обновить 2 миллиона строк за одну транзакцию. В Oracle вы будете записывать предшествующий образ каждого обновляемого блока, чтобы другие сеансы все еще имели согласованное чтение, не читая измененные блоки, и у вас была возможность отката. Это долгий откат. Обычно лучше делать транзакции небольшими порциями. Скажи 1000 записей одновременно.
Если у вас есть индексы в таблице, и эта таблица будет считаться неработающей во время обслуживания, вам лучше удалить индексы перед большой операцией, а затем заново создать ее после нее. Дешевле тогда постоянно пытаться поддерживать индексы с каждой обновленной записью.
Oracle позволяет «не регистрировать» подсказки для операторов, чтобы остановить ведение журнала. Это значительно ускоряет утверждения, но оставляет вашу базу данных в «неустранимой» ситуации. Таким образом, вы хотели бы сделать резервную копию до, и резервное копирование сразу же после этого. Я не знаю, есть ли у Postgres похожие варианты.
источник
VACUUM
является только половиной ответа; PostgreSQL также использует так называемый «журнал записи вперед» (фактически журнал) для обеспечения атомарных фиксаций и защиты от частичной записи и т. Д. См. Postgresql.org/docs/current/static/wal-intro.html