У меня есть вопрос, связанный с производительностью. Допустим, у меня есть пользователь с именем Майкл. Возьмите следующий запрос:
UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
Будет ли запрос фактически выполнять обновление, даже если оно обновляется до того же значения? Если так, как я могу предотвратить это?
postgresql
performance
update
postgresql-performance
OneSneakyMofo
источник
источник
Ответы:
Из-за MVCC-модели Postgres и в соответствии с правилами SQL,
UPDATE
записывает новую версию строки для каждой строки, которая не исключена вWHERE
предложении.Это делает имеют более или менее существенное влияние на производительность, прямо и косвенно. «Пустые обновления» имеют ту же цену за строку, что и любое другое обновление. Они запускают триггеры (если они есть), как и любое другое обновление, они должны быть зарегистрированы в WAL, и они генерируют мертвые строки, раздувающие таблицу и вызывающие дополнительную работу на
VACUUM
потом, как и любое другое обновление.Записи индексов и столбцы TOASTed, в которых не изменен ни один из задействованных столбцов, могут остаться прежними, но это верно для любой обновленной строки. Связанный:
Это почти всегда хорошая идея, чтобы исключить такие пустые обновления (когда есть реальный шанс, что это может произойти). Вы не предоставили определение таблицы в своем вопросе (что всегда является хорошей идеей). Мы должны предположить, что
first_name
может иметь значение NULL (что не удивительно для «имени»), поэтому в запросе необходимо использовать NULL-безопасное сравнение :Если
first_name IS NULL
до обновления тест с just простоfirst_name <> 'Michael'
оценивается как NULL и как таковая исключает строку из обновления. Подлая ошибка. Если столбец определенNOT NULL
, используйте простую проверку на равенство, потому что это немного дешевле.Связанный:
источник
Indexes entries and TOASTed columns where none of the involved columns are changed can stay the same
Но не нужно ли их обновлять, чтобы они указывали на новое местоположение строки?rollback
обработки снимков, управление блокировками, WAL, а что нет ...ORM похож на предложение Ruby on Rail с отложенным исполнением, которое помечает запись как измененную (или нет), а затем, когда это необходимо или вызывается, затем передает изменение в базу данных.
PostgreSQL - это база данных, а не ORM. Это снизило бы производительность, если бы потребовалось время, чтобы проверить, совпадает ли новое значение с обновленным значением в вашем запросе.
Поэтому он будет обновлять значение независимо от того, совпадает ли оно с новым значением или нет.
Если вы хотите предотвратить это, вы можете использовать код, предложенный Максом Верноном в своем ответе.
источник
Вы можете просто добавить к
where
предложению:Если
first_name
определяется какNOT NULL
,OR first_name IS NULL
часть может быть удалена.Условие:
также может быть написано более элегантно, как (в ответе Эрвина):
источник
NULL
@erwinС точки зрения базы данных
Ответ на ваш вопрос - ДА. Обновление состоится. База данных не проверяет предыдущее значение, она только устанавливает новое значение.
Поскольку это происходит в памяти (и будет записано в файлы данных только после выдачи коммита), производительность не будет проблемой.
С точки зрения ORM
Обычно у вас будет объект, представляющий одну строку базы данных (это может быть намного сложнее, но давайте будем проще). Этот объект управляется в памяти (на уровне сервера приложений), и только последняя зафиксированная версия этого объекта в определенный момент попадет в базу данных.
Это может объяснить другое поведение.
Теперь давайте не будем сравнивать грузовой корабль с 3D-принтером. Тот факт, что вы можете отправлять 3D-принтеры с использованием грузовых кораблей, не означает, что между ними может быть какое-либо сравнение.
Наслаждайтесь!
Я надеюсь, что это прояснило некоторые понятия.
источник