|
|
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Добрый день. У меня есть таблица djangobb форума. В полях body и body_html хранится текст постов (он может быть очень большой). Сайт написан на Django с использованием батареек типа haystack (для полнотекстового поиска используется Elasticsearch) Elasticsearch делит с postgersql 2 Гб оперативной памяти. В таблице постов где-то 1,5 млн. записей суммарно. Весит она 1,7 Гб (из-за текстовых полей, без текстовых полей где-то 130 МБ) и соответственно в память полностью не помещается. Django-haystack синхронизирует с Elasticsearch данные по кусочкам, каждый раз делая запрос вида: Код: plsql 1. 2. 3. 4. Такой запрос из-за того, что данные каждый раз читаются с диска выполняется долго (где-то 11-23 секунд), не считая запросов с небольшим OFFSET Кроме того, тупят темы с большим числом постов (несколько десятков тысяч), но гораздо меньше (одна-две секунды). Django для пагинации каждый раз делает запрос Код: plsql 1. Делал VACUUM FULL ANALYZE; Делал переиндексацию. Пробовал создать копию таблицы, но без текстовых полей (body и body_html) - и те же выборки оттуда выполняются за 200-300 мс. Что гораздо лучше. Пробовал колонкам выставлять Column storage в EXTERNAL Я с БД мало работал, и плохо понимаю как хранятся данные, но у меня ощущение что даже при запросах COUNT - postgresql пытается считываться все данные (в т. ч. и эти текстовые поля). Нельзя ли как-то настроить чтобы они как бы были в этой же таблице (но физически лежали в другом месте) и их не трогали при просчёте OFFSET и COUNT? Спасибо. CREATE таблицы: Код: 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. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.09.2015, 15:01 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-a, `OFFSET` тяжелая вещь, от нее нужно избавляться — особенно со столь большими значениями. `COUNT()` же в Postgres'е делает SeqScan из-за особенностей версионного движка. Чтобы лучше понять что у вас происходит, нужно показать вывод `EXPLAIN (analyze, buffers) ... SELECT ...` для ваших проблемных запросов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.09.2015, 15:33 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-aПробовал колонкам выставлять Column storage в EXTERNAL RTFMNote that SET STORAGE doesn't itself change anything in the table, it just sets the strategy to be pursued during future table updates. ну и ведите актуальное матвью канутов. если вы их не по каждому фильтру отдельно лудите. чтобы фуллсканом не читать. а джанго засуньте, откуда нашли. если он не исправится. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.09.2015, 16:09 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-a... Код: plsql 1. 2. 3. 4. ... Код: plsql 1. поаккуратней с синтаксисом. Где ордер бы? Где скобки? Может ли created быть больше now? В совокупности с OFFSET 1000000 напрашивается вывод о некорректной настройке поисковика для получения очередной пачки изменений. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.09.2015, 16:24 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-a, тут либо добавлять память (shared_buffers надеюсь выставлен нормально) либо извращаться с запросами. первый запрос можно немного ускорить для широких таблиц если например предварительно выбрать только id по заданному условию, используя index only scan (потребуется индекс на (created, id)), а потом уже выбрать 1000 записей по полученным id. увеличение размеров пачек тоже должно помочь. если created уникальное поле, то можно и сразу по нему выбирать. второй запрос можно ускорить если не считать точное число, а оценку (я так полагаю что там условие какое-то есть). например, можно парсить вывод explain или самому из pg_stats вычислять (если простое условие). тут конечно надо autovacuum_analyze_threshold еще подкрутить и возможно stats_target. ну или кэшировать результат. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.09.2015, 21:30 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Это на самом деле тестовый форум - просто провожу так сказать нагрузочное тестирование. qwwq, Django - это фреймворк на питоне и форуму писал не я. Мне просто надо как-то что-то оптимизировать. Я там менять ничего не могу. Тем более принцип работы пагинации. Сначала выбирается общее количество, потом разбивается на количество страниц, потом уже оффсетом выбирается нужные посты для нужной страницы. В любой момент некоторые посты могут быть удалены. И соответственно посты сдвинутся. Ну это так себе проблема, лишь несколько тем большие. Оригинальную таблицу пришлось урезать. Вот план из таблицы на 100 000 строк p2., фреймворк выполняет следующие запросы (из дебага): Код: plsql 1. 2. 3. Код: 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. Код: 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. Старую таблицу я скопировать отдельно, но план такой же каким я его видел и раньше: Код: plsql 1. Код: plsql 1. 2. 3. 4. 5. 6. 7. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.09.2015, 23:06 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-aЭто на самом деле тестовый форум - просто провожу так сказать нагрузочное тестирование. qwwq, Django - это фреймворк на питонеКО не заметил, что оно тут не первое развесистой джангой помахивает Zim-aи форуму писал не я. Мне просто надо как-то что-то оптимизировать. -- выкинуть джангу, или научиться таки ей пользоваться, перепиливая во все дыры, если оно не собирается без этого нормально работать Zim-aЯ там менять ничего не могу. Тем более принцип работы пагинации. Сначала выбирается общее количество, потом разбивается на количество страниц, потом уже оффсетом выбирается нужные посты для нужной страницы. В любой момент некоторые посты могут быть удалены. И соответственно посты сдвинутся. Ну это так себе проблема, лишь несколько тем большие. ещё раз -- пагинация у вас одна сквозь всё, или по всяким фильтрам -- своя ? а то ж если одна -- то это даже не задача, а гулькин чих. вот только джангу похерить -- и решать. а вот если по любым фильтрам - своя -- то тут уже никуда не денесся -- придется фуллсканить на миллионных оффсетах. или другую модельку "постраниции" строить. печалька. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 00:36 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
qwwqещё раз -- пагинация у вас одна сквозь всё, или по всяким фильтрам -- своя ?Для индексации - практически сквозь всё. WHERE created < [здесь NOW timestamp] Для страниц форума - дополнительная фильтрация по topic_id В Django есть стандартный компонент paginator. Ну я немного посмотрел исходники тоже же phpbb - там тоже такая же беда. Поэтому на рутрекере например темы закрываются при достижении 100 страниц. Кстати, а какой другой способ сделать пагинацию вы можете предложить? Кроме LIMIT OFFSET? Хранить дополнительные данные в других таблицах? Почему вот этот трюк, который работает в MySQL не работает в Postgresl? Почему всё равно просматривается вся таблица, а не только индекс по id? http://stackoverflow.com/a/4502426/4007475 Код: plsql 1. 2. 3. 4. 5. Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 08:06 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-aКстати, а какой другой способ сделать пагинацию вы можете предложить? Кроме LIMIT OFFSET? Хранить дополнительные данные в других таблицах? а что в этом плохого ? у вас закрытое множество под--пагинируемого. храните массивы айдишников начала страниц. при удалении -- производите перевычисление (инкрементальное) правых от точки удаления узлов. -- там будет limit 1 без offset, столько лупов -- сколько страниц. на худой конец открытого множества возможных фильтров -- например откройте курсор (или FOR LOOP) и сразу всё нарежьте. в пределах сессии отдавайте из этой нарезки. можете опять таки подумать, как сдвиги вычислять по событиям удаления. Zim-aПочему вот этот трюк, который работает в MySQL не работает в Postgresl? Почему всё равно просматривается вся таблица, а не только индекс по id?патамушта индекс в пг не хранит видимости. много раз перетёрто. чтобы не сортило на диске -- можете work_mem добавить, но это мало повлияет на время. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 08:43 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-a, А индекс `ON djangobb_forum_post_backup(id)` есть? И статистики актуальные? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 08:44 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
vyegorovZim-a, А индекс `ON djangobb_forum_post_backup(id)` есть? И статистики актуальные?вы ещё версию пж узнайте. IOS не сразу появился. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 08:47 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Код: plsql 1. 2. 3. 4. 5. 6. 7. Статистики актуальные. Делал VACUUM ANALYZE FULL; И через pgAdmin REINDEX таблицы. Строка версии PostgreSQL 9.3.9 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4, 64-bit ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 09:44 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-a, Приведите план для Код: sql 1. 2. 3. -- где-то там начнётся выгода от IOS , с т.з. планировщика. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 10:58 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Выборки: Віборка по ID, OFFSET 100 000 Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. Выборка * OFFSET 100 000 Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. Выборка по ID, OFFSET 10 000 Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. Выборка *, OFFSET 10 000 Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 11:16 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-a, кажется, Код: sql 1. -- как бы говорит нам, что visibility map не актуальна. олл, поправьте меня, если я не прав. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 12:26 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
может создать табличку из 1 поля id 1:1 к исходной. И её мучать оффсетами раз авторбез текстовых полей (body и body_html) - и те же выборки оттуда выполняются за 200-300 мс. А потом уже выбранные несколько id - лукапить по индексу из основной таблицы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 14:49 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Ivan Durakможет создать табличку из 1 поля id 1:1 к исходной. И её мучать оффсетами раз авторбез текстовых полей (body и body_html) - и те же выборки оттуда выполняются за 200-300 мс. А потом уже выбранные несколько id - лукапить по индексу из основной таблицы. А просто попросить postgres чтобы он большие текстовые поля отдельно ложил и подтягивал их только по мере необходимости нельзя? Column storage EXTERNAL не для этого разве? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 16:19 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-a, А он так и делает, из коробки. Размер страницы 8Кб и запись не может превышать этот размер. Так что любое значение больше примерно 2Кб будет автоматом тостироваться. А вот меньшие значения вполне себе могут и в основной таблице лежать. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 16:27 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-a А просто попросить postgres чтобы он большие текстовые поля отдельно ложил и подтягивал их только по мере необходимости нельзя? Column storage EXTERNAL не для этого разве? так он это начнет делать только *после* того , как вы это скажете, и зальёте данные ПОСЛЕ этого слова. До того у вас ширина записи так и останется "несколько шире" тех считанных байт + системный префикс, и это шире будет примерно до 2К/на поле, как нам тут подбрасывают. т.е. ПОСЛЕ того, как вы вот это сказали, вам надо обновить все записи, чтобы в новых версиях оно в external|extended легло, после чего отвакуумится, отреиндекситься и попробовать ещё раз. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 16:55 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Я понял.Создал новую таблицу. Код: 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. Вставил туда все данные Код: plsql 1. Сделал VACUUM ANALYZE FREEZE Код: plsql 1. 2. 3. 4. 5. 6. 7. И REINDEX. Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.09.2015, 20:41 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-a, страничек осталось стока же. сканить -- стока де. вот и времена не поменялись. покажите план select count(1) из узкой таблички, которую руками обрезали. и vacuum verbose её же -- будем на странички посмотреть ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 30.09.2015, 00:42 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Узкая таблица: Код: plsql 1. 2. 3. 4. 5. 6. 7. Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. [SRC PLSQL][/SRC] ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 30.09.2015, 09:21 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
Zim-a, 173809 pages <=> 9661 pages 14928.792 ms <=> 436.867 ms во втором случае видимо затраты на агрегирование уже вкладываются ощутимо почему external не заужает таблику -- хз. Может быть заполнение считается из расчетной ширины записи без учета STORAGE ... EXTERNAL. Попробуйте ещё FILLFACTOR на табличку погонять туда -- сюда. (тоже затратно для тестера). Хотя лучше у знающих людей спросить. Максим наверное должен знать. и вот это: "Sort Method: external merge Disk: 17984kB" говорит о том, что оффсету на миллион без IOS надо добавить work_mem до 18--20 MB даже в узком случае. Для сорта. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 30.09.2015, 12:20 |
|
||
|
Медленный COUNT, OFFSET. Таблица не помещается в RAM
|
|||
|---|---|---|---|
|
#18+
В конфиге postgresql.conf стояло work_mem = 32MB ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 30.09.2015, 13:12 |
|
||
|
|

start [/forum/topic.php?fid=53&msg=39063656&tid=1997743]: |
0ms |
get settings: |
9ms |
get forum list: |
19ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
182ms |
get topic data: |
14ms |
get forum data: |
3ms |
get page messages: |
86ms |
get tp. blocked users: |
2ms |
| others: | 236ms |
| total: | 559ms |

| 0 / 0 |
