Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
рефакторинг большой таблицы. 2 вопроса.
|
|||
|---|---|---|---|
|
#18+
Всем привет. Есть следующая проблема: существует одна таблица, для простоты картины ее можно представить в таком виде: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. В этой таблице ~ 50 млн. записей. Решено было сделать следующую оптимизацию - значения из val_data вынести в отдельную таблицу и заменить это поле внешним ключем. Для этого была создана таблица: Код: plaintext 1. 2. 3. 4. 5. 6. 7. а в исходную добавлена колонка uv_id. после этого во вторую таблицу были вставлены все неповторяющиеся значения из поля val_data первой таблицы. Получилось в итоге примерно 10 млн. записей. Вопрос первый: Каким самым быстрым образом можно связать между собой эти две таблицы? То есть обновить в первой таблице поле uv_id? Поясню в чем проблема: запрос Код: plaintext выполняется безобразно долго и мучительно. если делать update частями, то запрос вида Код: plaintext выполняется ~1000 секунд. То есть 10 тысяч строк апдейтятся 16 минут. а строк, которые надо проапдейтить - 50 миллионов. с такими скоростями на это уйдет 55 суток (( ps: индексы (btree, clustered) созданы на каждые поля таблицы Вопрос второй: для уменьшения времени поиска вторую таблицу я разбил на множество более мелких, используя партиционирование (примерно как тут: http://postgrestips.blogspot.com/2007/06/partitial-table.html), обвесив таблицу правилами наподобие Код: plaintext 1. 2. 3. 4. и так для всех букв алфавита, то есть создано множество таблиц, делящих текст по букве, с которой начинается текстовое поле. Соответственно идентификаторы uv_id так же оказались разнесены по разным таблицам. Проблема заключается в том, что uv_id является внешним ключем для таблицы values. а так как значения этого ключа оказались разнесенными по разным таблицам у меня не получается повесить constraint на таблицу values: Код: plaintext 1. 2. 3. 4. этот код генерирует ошибку говорящую о том, что необходимые ключи не найдены в таблице unique_values. Можно каким-либо образом повесить constraint на таблицу values или придется оставить все как есть? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.08.2007, 23:32 |
|
||
|
рефакторинг большой таблицы. 2 вопроса.
|
|||
|---|---|---|---|
|
#18+
untitledКаким самым быстрым образом можно связать между собой эти две таблицы? То есть обновить в первой таблице поле uv_id?Попробуйте update values set uv_id = unique_values.uv_id from unique_values where values.uv_value=unique_values.val_data. Покажите получившийся EXPLAIN, наверное надо добиться Merge Join. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. untitledПоясню в чем проблема: запрос Код: plaintext 1. Код: plaintext 1. 2. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.08.2007, 10:54 |
|
||
|
рефакторинг большой таблицы. 2 вопроса.
|
|||
|---|---|---|---|
|
#18+
Да, вариант с join быстрее на два порядка: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. против Код: plaintext 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. Однако общая стоимость запроса по прежнему не радует. Сейчас пока обновляю таблицу кусками при помощи такого запроса и думаю что можно сделать еще... Код: plaintext 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. реальное время выполнения каждого такого апдейта ~4500000 ms ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.08.2007, 12:38 |
|
||
|
рефакторинг большой таблицы. 2 вопроса.
|
|||
|---|---|---|---|
|
#18+
untitledОднако общая стоимость запроса по прежнему не радует.Merge Join не получился. Попробуйте запросами по частичным таблицам типа "update values set uv_id = a.uv_id from unique_values_a a where val_data=uv_value". untitled... limit 200000. реальное время выполнения каждого такого апдейта ~4500000 msПри этом, как видно из плана, limit накладывается на values, а таблицы unique_values_* прочитываются целиком. Получается неэффективно. Для сравнения попробуйте "limit 400000", думаю что время выполнения возрастет меньше, чем в два раза. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.08.2007, 13:02 |
|
||
|
рефакторинг большой таблицы. 2 вопроса.
|
|||
|---|---|---|---|
|
#18+
untitledВсем привет. Есть следующая проблема: существует одна таблица, для простоты картины ее можно представить в таком виде: В этой таблице ~ 50 млн. записей. Решено было сделать следующую оптимизацию - значения из val_data вынести в отдельную таблицу и заменить это поле внешним ключем. Для этого была создана таблица: Получилось в итоге примерно 10 млн. записей. а ради чего это делалось? применительно к оптимизации postgresql встречал рекомендацию наоборот делать всё одной таблицей с кучей полей, пусть даже и с некоторым дублированием информации. логика: для доступа к данным придётся делать два сика вместо одного, накладные расходы на организацию второнй таблицы "съедят" экономию от удаления избыточных данных. конечно не стоит доходить до крайностей - в данном конкретном случае (10 миллионов уникальных значений на 50 миллионов данных) вполне возможно, что нормализация была лишней. выполняется ~1000 секунд. То есть 10 тысяч строк апдейтятся 16 минут. а строк, которые надо проапдейтить - 50 миллионов. с такими скоростями на это уйдет 55 суток (( ps: индексы (btree, clustered) созданы на каждые поля таблицы к слову - чем меньше индексов - тем быстрее идёт обновление. afaik postgesql до недавнего времени перестраивал все индесы на каждый update (независимо от того, поменял ли update поля, участвующие в индексе или нет). хотя в данном конкретном случае дело явно не в индексах. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2008, 14:14 |
|
||
|
рефакторинг большой таблицы. 2 вопроса.
|
|||
|---|---|---|---|
|
#18+
eddie, это было полтора года назад) применительно к оптимизации postgresql встречал рекомендацию наоборот делать всё одной таблицей с кучей полей, пусть даже и с некоторым дублированием информации. логика: для доступа к данным придётся делать два сика вместо одного, накладные расходы на организацию второнй таблицы "съедят" экономию от удаления избыточных данных. это денормализация, оно не только конкретно к постгре применимо, а везде, где нужен быстрый доступ к данным можно делать нечто подобное. в итоге так и сделали. если уж на то пошло прокомментирую второй свой вопрос: делать партиционирование в постгре в виде Код: plaintext 1. 2. 3. - это крайне неудачное решение. все дело в том, что если потом сделать запрос вида Код: plaintext вообще после различных экспериментов целесообразность партиционирования таблиц размером меньше 10 гигов (без учета размера индексов) и 100М записей под большим вопросом. если таблица общего назначения, то есть в нее и заносятся данные, и делаются выборки по различным критериям, то, наверное, самое лучшее - это разбить по первичному ключу, положив каждую из полученных таблиц в таблспейс на отдельный диск. и еще - делать кластеризацию индекса на постоянно обновляемой таблице такого размера - нереально. так как CLUSTER делает полную блокировку таблицы, в том числе и для чтения, и занимает дофига времени. правда, как вариант, если позволяет логика программы, можно поочереди отключать таблицы,меняя правила, кластеризовывать их, а потом подключать обратно. но это далеко не везде применимо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2008, 14:58 |
|
||
|
рефакторинг большой таблицы. 2 вопроса.
|
|||
|---|---|---|---|
|
#18+
untitlededdie, это было полтора года назад) упс, это меня или форум переглючило? ;) если уж на то пошло прокомментирую второй свой вопрос: делать партиционирование в постгре в виде Код: plaintext 1. 2. 3. - это крайне неудачное решение. все дело в том, что если потом сделать запрос вида Код: plaintext ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2008, 15:42 |
|
||
|
рефакторинг большой таблицы. 2 вопроса.
|
|||
|---|---|---|---|
|
#18+
случаем не забыли включить constraint_exclusion и на дочерних таблицах сделать "CHECK (uv_value >= 'a'::text AND uv_value < 'b'::text)"? нет конечно, не забыл. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2008, 15:49 |
|
||
|
рефакторинг большой таблицы. 2 вопроса.
|
|||
|---|---|---|---|
|
#18+
имхо это уже повод написать багрепорт ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2008, 20:50 |
|
||
|
рефакторинг большой таблицы. 2 вопроса.
|
|||
|---|---|---|---|
|
#18+
untitled вообще после различных экспериментов целесообразность партиционирования таблиц размером меньше 10 гигов (без учета размера индексов) и 100М записей под большим вопросом. если таблица общего назначения, то есть в нее и заносятся данные, и делаются выборки по различным критериям, то, наверное, самое лучшее - это разбить по первичному ключу, положив каждую из полученных таблиц в таблспейс на отдельный диск. Постгрес в продакшене использовался задолго до того, как стали доступны гигабайты памяти и быстрые диски. Например, на машинке с 256 мб ОЗУ и аташным винтом гиг на 40 указанные вами объемы данных без партиционирования обрабатывать нереально. P.S. Первый свой сервак с постгресом я делал на пентиум I, разогнанном до 166 МГц, с 32Мб ОЗУ. А теперь на машинках с 32Гб ОЗУ часто слышим о проблемах с базами размером в проценты от доступной памяти :-) Это я к тому, что эффективность любой техники оптимизации зависит от вида и стат. распределения хранимых данных, интенсивности и типа нагрузки и нельзя для произвольной базы на неизвестном железе однозначно сказать, что такое хорошо и что такое плохо. Пробовать надо - именно с этими данными и на этом железе. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2008, 21:16 |
|
||
|
|

start [/forum/topic.php?fid=53&msg=34753779&tid=2003864]: |
0ms |
get settings: |
6ms |
get forum list: |
10ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
38ms |
get topic data: |
8ms |
get forum data: |
2ms |
get page messages: |
34ms |
get tp. blocked users: |
1ms |
| others: | 219ms |
| total: | 322ms |

| 0 / 0 |
