Избыточные данные в операторах обновления - PullRequest
6 голосов
/ 18 октября 2011

Hibernate генерирует UPDATE операторов, которые включают все столбцы, независимо от того, изменяю ли я значение в этих столбцах, например:

tx.begin();
Item i = em.find(Item.class, 12345);
i.setA("a-value");
tx.commit();

выдает этот оператор UPDATE:

update Item set A = $1, B = $2, C = $3, D = $4 where id = $5

поэтому столбцы B, C, D обновляются, а я их не менял.

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

tx.begin();
em.createQuery("update Item i set i.a = :a where i.id = :id")
    .setParameter("a", "a-value")
    .setParameter("id", 12345)
    .executeUpdate();
tx.commit();

Что меня больше всего смущает, так это то, что планы EXPLAIN по «неоптимизированным» и «оптимизированным»Версия запроса идентична!

Ответы [ 2 ]

11 голосов
/ 18 октября 2011

Из-за PostgreSQL MVCC , UPDATE фактически почти похож на DELETE плюс INSERT - с заметным исключением из тостовых значений.См .:

Если быть точным, «удаленная» строка просто невидима для любой транзакции, начинающейсяпосле того, как удаление было совершено, и пылесосить позже.Следовательно, на стороне базы данных, включая манипулирование индексами, в действительности нет никакой разницы между двумя операторами.(Применяются исключения, продолжайте чтение.) Он немного увеличивает сетевой трафик (в зависимости от ваших данных) и требует небольшого разбора.

Я изучил обновления HOT еще несколько раз после ввода @ araqnid и провел несколько тестов.Обновления в столбцах, которые на самом деле не изменяют значение, не имеют значения в отношении HOT HOT.Мой ответ верен.Подробности см. Ниже.

Это также относится к всплывающим атрибутам, поскольку они также не затрагиваются, если только значения фактически не изменяются .

Однако , есливы используете триггеры для каждого столбца (введено в pg 9.0), это может иметь нежелательные побочные эффекты!

Я цитирую руководство по триггерам :

... такая команда, как UPDATE ... SET x = x ..., запустит триггер для столбца x, , даже если значение столбца не изменилось .

выделение жирным шрифтоммой.

Слои абстракции для удобства.Они полезны для неграмотных разработчиков SQL или если приложение должно быть переносимым между различными RDBMS.С другой стороны, они могут снизить производительность и ввести дополнительные точки отказа.Я избегаю их везде, где это возможно.

Относительно обновлений HOT (только для кучи)

Кортежи только для кучи были представлены с Postgres 8.3 , с важными улучшениями в 8.3.4 и 8.4.9 .
Замечания к выпуску Postgres 8.3:

UPDATE s и DELETEs оставляют мертвые кортежи, как и неудачные INSERT s.Ранее только VACUUM мог вернуть пространство, занятое мертвыми кортежами.С HOT мертвое пространство кортежей может быть автоматически восстановлено во время INSERT или UPDATE , если не внесены изменения в индексированные столбцы .Это учитывает более последовательную работу.Кроме того, HOT избегает добавления повторяющихся записей индекса.

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

Поджаренные столбцы также не мешают горячим обновлениям.Обновлённый HOT кортеж просто ссылается на один и тот же неизменный кортеж (ы) в тост-форке отношения.Обновления HOT даже работают с всплывающими значениями в списке целей (фактически изменены или нет).Если тостовые значения изменены, это, очевидно, влечет за собой запись в форк отношения тоста.Я тоже все это проверял.

Тебе не нужно верить моим словам.Убедитесь сами, Postgres предоставляет несколько функций для проверки статистики .Запустите ваш UPDATE со всеми столбцами и без них и проверьте, имеет ли это значение.

-- Number of rows HOT-updated in table:
SELECT pg_stat_get_tuples_hot_updated('table_name'::regclass::oid)

-- Number of rows HOT-updated in table, in the current transaction:
SELECT pg_stat_get_xact_tuples_hot_updated('table_name'::regclass::oid)

Или используйте pgAdmin .Выберите свою таблицу и проверьте вкладку «Статистика» в главном окне.

Имейте в виду, что обновления HOT возможны только в том случае, если на той же странице ветки основного отношения есть место для новой версии кортежа.Один простой способ форсировать это условие - протестировать с небольшой таблицей, которая содержит всего несколько строк.Размер страницы обычно составляет 8 КБ, поэтому на странице должно быть свободное место.

3 голосов
/ 18 октября 2011

Вы можете использовать аннотацию в спящем режиме @Entity:

@org.hibernate.annotations.Entity(dynamicUpdate = true)
public class Item

Это обновит только измененные поля.

...