|
|
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
Один пользователь. Есть анонимная функция на plpgsql (читай, дело происходит внутри одной транзакции). Задача - перелить данные из одной базы (другого сервера) в другую. Внутри цикл по строкам выборки на 10000 строк (т.е. за один раз зальется 10000 строк). В процессе выполнения скорость уменьшается. При повторе этого кода всё повторяется - сначала быстро(! старые данные остались !), потом всё медленнее и медленнее. Как так? Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.01.2014, 18:36:55 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
acetonВ процессе выполнения скорость уменьшается. Перепишите цикл на pgScript и делайте commit после каждой вставки на 10К. У вас цена изоляции одной транзакции растет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.01.2014, 19:28:03 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
tadmin, можно для общего развития вводную про "цену изоляции" для этого конкретного примера? Так сказать, физику процесса (с постгресом относительно недавно занимаюсь). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.01.2014, 23:31:49 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
aceton, Не видно, что вы делаете. Покажите таблицы и как вы сохраняете ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 02:56:05 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
aceton, Или покажите код perform platbox.transaction_insert(_r.id, _r.ext_id, _r.deal_id, _r.create_moment, _r.amount); или для интереса замените эти хранимки на тестовые версии которые делают ТОЛЬКО 1 insert в какую то таблицу (без индексов и FK триггеров и прочего)... и перетестируйте... а далее сами думайте что в ваших хранимках вызывает такое поведение... лично я бы предположил что у вас там ловля исключений в хранимках (begin/exception/end)... а это не то что в цикле стоит делать... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 03:50:57 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
Misha Tyurin, transaction_insert() вызывает срабатывание триггера, который ведет сводные таблицы (код не слишком маленький), но(!) transaction_confirm() всего лишь прописывает значения пары полей в уже существующей записи без каких-либо доп. действий. При этом картина при выполнении обеих функций абсолютно идентична. Я сначала пытался решить проблему на irc://irc.freenode.net/postgresql. Анализ знатоками скрипта со всеми задействованными таблицами (с индексами и триггерами) и функциями криминала не выявил. Абстрактный взгляд на вещи (с учетом единственного подключения и не упрощающихся стартовых условий для каждого повторения) указывает на какой-то ньюанс с долгой транзакцией, но мои знания работы версионника не дают ответа. PS ловли исключений нет ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 09:57:39 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
acetonТак сказать, физику процесса (с постгресом относительно недавно занимаюсь). Каждая незавершенная вставка приводит появлению записей с ID транзакции, которые не должны быть видны прочим. Для обновления (см. ваши агрегаты) появляется минимум две записи. Если цикл повторяется N раз, то весьма вероятно появление N версий агрегатов. Соотвественно, пухнут таблицы и индексы. Пока транзакция не завершится, не произойдет очистка от мертвых записей и обновление статистики. Чем дальше, тем больше начинает ошибаться планировщик. Если есть параллельная нагрузка на чтение, то там будут сопутствующие проблемы. Когда транзакция завершается, весь этот массив из N версий схлопыватся: мертвые записи оперативно выпиливаются, статистика исправляется и т.д. Наличие у вас триггеров усугубляет проблемы. Они срабатывают на каждую из 10 0000 записей по отдельности. Не зная вашего приложения трудно давать советы, но отказ от триггеров и пересчет в ХП должны дать хорошее ускорение. Еще, мне кажется, что редкий цикл for loop in select func..... from table нельзя заменить на perforn func .... from table. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 10:59:06 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
aceton, какая у Вас версия сервера и операционной системы? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 10:59:23 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
tadmin, откуда же "появление N версий", если транзакция одна, и подключение одно? Казалось бы, сводные данные должны обновляться в рамках одной версии и не плодить новых. Или я не понял, о каких агрегатах речь. Статистика не должна влиять при повторе эксперимента, в результате которого изменения таблиц уже относительно малы (на существующих 500000 очередные 10000 роли не сыграют). По поводу perform func .... from table: delete from main.transaction where id in (select id from main.transaction limit <NNN>) <NNN>: 10 строк изменено за 42 мс. 100 строк изменено за 91 мс. 200 строк изменено за 212 мс. 500 строк изменено за 596 мс. 1000 строк изменено за 1615 мс. 2000 строк изменено за 5225 мс. 3000 строк изменено за 9854 мс. Та же картина. Гость_0, pgsql 9.3, SMP Debian 3.2.51-1 x86_64 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 11:46:17 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
aceton, я бы попробовал включить set track_functions to 'all'; далее begin; запуск вашей функции... и далее изучение содержимого select * from pg_stat_xact_user_functions ; чтобы понять где тормозит... возможно сделав батч на 1000 и батч на 10000 а далее сравнив pg_stat_xact_user_functions и вполне возможно найдется блок который начинает тормозить и тогда с ним можно будет работать системно... PS: у вас там нигде нет constraints в режиме deferrable intially deferred ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 13:50:52 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
acetonГость_0, pgsql 9.3Третья цифра какая? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 14:28:36 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
aceton, авторtransaction_insert() вызывает срабатывание триггера, который ведет сводные таблицы (код не слишком маленький) так как более ничего не известно, думаю, что дело тут. что-то растет и фк/пк деградируют. или еще что-то подобное. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 14:32:57 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
сводные таблицы хорошо вести асинхронно ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 14:34:47 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
aceton, и да Maxim Boguk PS: у вас там нигде нет constraints в режиме deferrable intially deferred ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 14:41:17 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
Misha Tyurin, deferrable есть, intially deferred - нет Ёш, 9.3.2 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 14:59:34 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
Maxim Boguk, спасибо, воспользовался Вашим рецептом. Тормозные участки выделил, но суть пока не ясна. Не знаю, странный ли это вопрос.. для поиска только что вставленных записей в незавершенной транзакции используется индекс? Или такие записи индексируются по факту завершения транзакции? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 16:03:31 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
acetonMaxim Boguk, спасибо, воспользовался Вашим рецептом. Тормозные участки выделил, но суть пока не ясна. Не знаю, странный ли это вопрос.. для поиска только что вставленных записей в незавершенной транзакции используется индекс? Или такие записи индексируются по факту завершения транзакции? тут есть много тонкостей... вставьте analyze вашей таблицы в вашу функцию который бы вызывался после каждой 1000 записей добавленных... (если поможет я обьясню в чем беда была) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 16:40:32 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
Maxim Boguk, нет, не помогает. В процессе используется нежурналируемая таблица для доступа statement-level триггера к задействованным в операции записям, но там проскакивает по 3 записи, и они сразу удаляются. Может быть в нежурналируемых таблицах есть какая-то магия? :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 17:26:50 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
acetontadmin, откуда же "появление N версий", если транзакция одна, и подключение одно? Казалось бы, сводные данные должны обновляться в рамках одной версии и не плодить новых. Или я не понял, о каких агрегатах речь. Статистика не должна влиять при повторе эксперимента, в результате которого изменения таблиц уже относительно малы (на существующих 500000 очередные 10000 роли не сыграют). Я предположил, что ваш триггер вычисляет агрегаты. Это так? Вставляем 10 000 записей - 10 000 срабатываний триггера - если триггер агрегирует значения, скажем, по 100 записям, то значение агрегата за время этой вставки будет изменено 100 раз. Получаем 99 мертвых версий записи агрегата + 1 живая. Если бы агрегат вычислялся один раз после вставки всех 10 000, получилось бы две версии - одна живая, одна мертвая. acetonПо поводу perform func .... from table: delete from main.transaction where id in (select id from main.transaction limit <NNN>) А тут надо планы смотреть. Возможно, что limit <много> дороже, чем вообще без лимит. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 18:25:45 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
tadmin, в триггере происходит агрегирование, и одни и те же немногочисленные записи в таблице с остатками обновляются большое количество раз. Но откуда 99 мертвых версий? Разве не одна версия, соответствующая текущей транзакции, будет менять свое значение? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 18:53:04 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
acetontadmin, в триггере происходит агрегирование, и одни и те же немногочисленные записи в таблице с остатками обновляются большое количество раз. Но откуда 99 мертвых версий? Разве не одна версия, соответствующая текущей транзакции, будет менять свое значение? Может быть вы и правы, что одна версия на всю транзакцию. Но мне кажется, что будут выделяться новые, если не сработает HOT (heap only tuples). В противном случае индекс, как минимум, будет пухнуть. Однажды это обсуждали, но найти не могу. Даже если мое предположение ошибочное, 100х обновление стоит много дороже однократного. Не забудьте, что оно вызывается 10К раз, а локализация для агрегата может быть хуже чем х100. Мое предположение не трудно проверить, если выключить триггеры и обновлять агрегаты plain запросом без всяких циклов, один раз на вставку 10К. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 19:56:16 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
tadmin, спору нет - одно обновление гораздо лучше тысячи. Здесь transaction_insert() вставляет документ, делает проводки, триггеры на которые обновляют остатки по задействованным счетам (помимо разных проверок), поэтому завернуть цикл вставки таких документов в простой запрос, приводящий к одному изменению вместо множественных, не получится (разные счета, даты, условия). А проводок по каждому документу несколько. Избыточная работа по агрегированию итогов - печальное следствие недоступности в statement-триггере задействованных в операции записей. В эквивалентном функционале на ms sql server любое изменение таблицы проводок приводит к однократному выполнению триггера, и одним быстрым запросом обновляются остатки и обороты по всем счетам в любом дне из задействованных. Мера вынужденная - выбор средств для реализации такого поведения мал. HOT сработать должен, т.к. в таблице со сводной информацией по счетам (несколько десятков записей) эти самые многократные обновления затрагивают только неиндексированные поля. Строго говоря, при штатной работе проблема никак себя не проявляет. Выкрутиться можно (по Вашей рекомендации открыл для себя pgScript), однако разобраться в причинах было бы интересно и полезно. Завтра попробую поэкспериментировать с временными таблицами. Unlogged-таблицы были реализованы заметно позже, и, быть может, описываемый эффект пропадет. Просто unlogged-таблица идеально вписалась в задачу: заполнить данными внутри транзакции, использовать их в расчетах и в итоге удалить (минус оверхед на создание временной таблицы). А с временной таблицей придется городить еще один триггер before all для ее создания. Пока думается, что выигрыша такой вариант не даст, а в штатном режиме окажется медленнее. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.01.2014, 22:57:17 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
acetontadmin, спору нет - одно обновление гораздо лучше тысячи. Здесь transaction_insert() вставляет документ, делает проводки, триггеры на которые обновляют остатки по задействованным счетам (помимо разных проверок), поэтому завернуть цикл вставки таких документов в простой запрос, приводящий к одному изменению вместо множественных, не получится (разные счета, даты, условия). А проводок по каждому документу несколько. Избыточная работа по агрегированию итогов - печальное следствие недоступности в statement-триггере задействованных в операции записей. В эквивалентном функционале на ms sql server любое изменение таблицы проводок приводит к однократному выполнению триггера, и одним быстрым запросом обновляются остатки и обороты по всем счетам в любом дне из задействованных. Мера вынужденная - выбор средств для реализации такого поведения мал. HOT сработать должен, т.к. в таблице со сводной информацией по счетам (несколько десятков записей) эти самые многократные обновления затрагивают только неиндексированные поля. Строго говоря, при штатной работе проблема никак себя не проявляет. Выкрутиться можно (по Вашей рекомендации открыл для себя pgScript), однако разобраться в причинах было бы интересно и полезно. Завтра попробую поэкспериментировать с временными таблицами. Unlogged-таблицы были реализованы заметно позже, и, быть может, описываемый эффект пропадет. Просто unlogged-таблица идеально вписалась в задачу: заполнить данными внутри транзакции, использовать их в расчетах и в итоге удалить (минус оверхед на создание временной таблицы). А с временной таблицей придется городить еще один триггер before all для ее создания. Пока думается, что выигрыша такой вариант не даст, а в штатном режиме окажется медленнее. Даже если сработает HOT у вас всеравно при каждом обновлени в цепочке HOT будет фиксироваться новая версия строки... т.е. 100 обновлений одной и той же записи в транзакции создадут всеравно вам 100 версий записи (только плюс что индексы не будут затронуты). Поэтому циклическое/многократное обновление одной и той же записи внутри хранимки - будет замедлятся по мере работы (и с этим вы ничего не сделаете). HOT помогает избежать изменения индексов на каждой операции но совершенно не спасает от появления новой версии строки на каждом update. Так что совет переливать батчами по 100-1000 записей и коммитится после каждого батча... (а заодно возможно принудительно вызывать vacuum analyze нужных таблиц в промежутках). Скорее всего так будет быстрее... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.01.2014, 03:16:53 |
|
||
|
количество повторений влияет на скорость выполнения?!
|
|||
|---|---|---|---|
|
#18+
Maxim Boguk, похоже, всё так и есть. Простой эксперимент: Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. Буду учитывать эту особенность. Всем спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.01.2014, 10:21:40 |
|
||
|
|

start [/forum/topic.php?fid=53&msg=38532627&tid=1998885]: |
0ms |
get settings: |
12ms |
get forum list: |
18ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
204ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
61ms |
get tp. blocked users: |
1ms |
| others: | 229ms |
| total: | 545ms |

| 0 / 0 |
