172 похожих чатов

Подскажите такой вопрос: есть таблица, в которой поле "время" (не

важно, datetime или bigint) участвует в индексе и постоянно обновляется у каждой записи. из-за этого пухнет индекс, причем, fillfactor не помогает, так как через какое-то время индекс начинает пухнуть снова. что можно сделать с таким индексом ? в таблице примерно 300М записей. Варианты с секционированием не очень подходят, так как это уже часть секции еще большей таблицы и при более мелком разбитии на секции получается ну прям очень дофига таблиц, чего не хотелось бы. Есть ли какое-то решение данной проблемы или оно так исторически сложилось в постгресе и сделать ничего нельзя ?

27 ответов

7 просмотров

Периодически делать рядом новый индекс и удалять старый. Только analyse не забыть перед удалением :) Или reindex concurrently.

Pavel-Nikiforov Автор вопроса
Роман Жарков
Периодически делать рядом новый индекс и удалять с...

этот вариант хорош, когда данных не очень много и он реально прокатывал до какого-то момента, но данных стало много и такой псевдо vacuum не очень быстро работает в результате.

Pavel Nikiforov
этот вариант хорош, когда данных не очень много и ...

А действительно обязательно включение этого поля в составной индекс? Вариант с отдельным индексом только по этому полю не решит проблемы?

Pavel-Nikiforov Автор вопроса
Алексей Фирсов
А действительно обязательно включение этого поля в...

ну как бы да, это как раз дата-время, по нему делается выборка, без индекса по этому полю будет просмотр всех записей этой группы данных (индекс по "группе" есть). Было бы их в "группе" мало - конечно индекс не нужен, пусть бегает по таблице. Но тут запрос получается на несколько минут, если без индекса, что не приемлемо.

Лучше всего обновиться на 14-ю версию когда она выйдет. Описание в блоке "Удаление индексных строк «снизу вверх»"

Pavel-Nikiforov Автор вопроса
Евгений Смирнов
Лучше всего обновиться на 14-ю версию когда она вы...

ну это еще когда оно выйдет, а работать должно "сейчас". там много чего вкусного есть.

Если fillfactor помогает ненадолго -- то, возможно, чаще запускать вакуум и постараться, чтобы не было сверхдолгих транзакцый. То есть вообще говоря — оно и так должно работать, страничка заполнилась старьём, отвакуумилась, индэкс тожэ поочистился. Почему этот шаблон у вас работает подозрительно неэффективно — надо бы разбираться. С другой стороны — докиньте лишний SSD под индэкс, делайте регулярный reindex concurrently — и это будет решэние задачи малой кровью, честно говоря. Тем более, что табличка небольшая, все части должны бы в первые сотни гигабайт умещатьсяю

Pavel-Nikiforov Автор вопроса
Ilya Anfimov
Если fillfactor помогает ненадолго -- то, возможно...

сверхдолгих транзакций нет, там 5-6к обновлений в сек (update ... set dt=nnn,...), запросы на получение данных тоже не длинные, так как упираются в скорость доступа индекса, но все равно это 10-15сек сейчас. Но физическая таблица сама большая, примерно 90Гб, при том это это уже секция еще большей таблицы. индексы я раскидывал на разные диски - ssd (nvme) выпиливает быстро, а механика не такая быстрая на рандомном доступе. операции по reindex идут по 20-30мин, это долго, так как при этом диск сильно грузится и это так же тормозит другие операции. для меня подходящее решение разбивка на вообще мелкие секции, но я хз, как система прожует 15к файлов в одном каталоге. кто-нибудь релал базы где 5-6к таблиц (в секциях или просто, не важно) ?

IMNSHO: ну пухнет и пухнет, проблема-то в чём? Добавите дисков / RAM, в крайнем случае. Вы далее пишете, что используете UUID-ы — в общем-то, их использование практически гарантирует (разнообразные) проблемы с производительностью. Так что, если они Вам действительно нужны — придётся терпеть. А так — лучше бы увидеть \d таблицы, и те запросы, которые приводят индекс в такое состояние. Но, если действительно: > индексы - (group_id, bucket) и (group_id, dt) > Вставка идет по ключу (group_id, bucket) - обновляется dt и другие данные И, к тому же, dt обновляется на "далёкие" значения — это нормальное поведение, т.е. то, что этот индекс больше, чем свежесозданный, раза в 2-3, вполне ожидаемо (вот если больше, нужно уже смотреть подробнее).

Pavel-Nikiforov Автор вопроса
Yaroslav Schekin
IMNSHO: ну пухнет и пухнет, проблема-то в чём? Доб...

> И, к тому же, dt обновляется на "далёкие" значения это на какие ? там dt время в мс с начала эпохи, т.е. обновляется чаще всего не на следующее значение (+1) и не на очень близкое. По поводу - "пусть пухнет" - я согласен, что поставить дисков и пусть работает, вопрос в том, что бы это распухло до какого-то объема не равного бесконечности и работало без особого присмотра дальше, так как у заказчика компетентного админа для постгреса нет и не будет. Делать vacuum или reindex можно, но это долгий процесс, который при работе сильно напрягает диск. Понятно, что там nvme, raid и т.д. вопрос закроют на какое-то время, но хочется прям вот решение "включил и забыл", только диски менять в рейде и все.

Pavel-Nikiforov Автор вопроса
Yaroslav Schekin
IMNSHO: ну пухнет и пухнет, проблема-то в чём? Доб...

Column | Type | Collation | Nullable | Default | Storage | Stats target | Description ---------+--------------------+-----------+----------+------------------------+----------+--------------+------------- grp_id | uuid | | not null | | plain | | dt | bigint | | not null | | plain | | bucket | integer | | not null | '-1'::integer | plain | | val | double precision | | | | plain | | val1 | double precision | | | | plain | | val2 | double precision | | | | plain | | индексы по (grp_id, dt) , (grp_id, bucket) а чем uuid плох, что с ним такого плохого ? Ну для индекса да, не удобно, не u64.

Pavel Nikiforov
> И, к тому же, dt обновляется на "далёкие" значен...

> вопрос в том, что бы это распухло до какого-то объема не равного бесконечности Ну да, посыл был именно в этом. Т.е. стоит выяснить, останавливается ли "распухание" на приемлемых объёмах (допустим, в 3 раза от свежесозданного индекса) или нет. Если да, то "плясать" вокруг него с VACUUM и REINDEX малополезно — это "нормальное" состояние b-tree для таких данных и нагрузки, оно к нему сильно "стремится" и, соответственно, будет быстро приходить в это состояние (в любой СУБД, кстати).

Pavel Nikiforov
Column | Type | Collation | Nullab...

> а чем uuid плох, что с ним такого плохого ? Ну для индекса да, не удобно, не u64. Тем, что это они случайны — это наихудший случай для b-tree (и корень проблем — погуглите, в benchmarks можно увидеть очень существенные провалы в производительности).

Pavel-Nikiforov Автор вопроса
Yaroslav Schekin
> а чем uuid плох, что с ним такого плохого ? Ну д...

> Тем, что это они случайны — это наихудший случай для b-tree может быть не случайны, а у них "большой разборс" ? Ну будет не uuid, а int4, от 0 до 0x7FFFFFFF, это же не сильно улучшит работу b-tree ? Или для наиболее эффективной работы надо прям вообще делать последовательные числа в качестве id ?

Pavel Nikiforov
Column | Type | Collation | Nullab...

Например, https://habr.com/ru/company/ozontech/blog/564520/

Pavel Nikiforov
> Тем, что это они случайны — это наихудший случай...

Нет, именно случайны, при чём тут "разброс"? Для b-tree последовательности вставок [1, 2, 3, 4, ...] и [1, 213, 5454, 6456] примерно одинаково "прекрасны", а вот случайные последовательности — примерно одинаково ужасны. И с последующее извлечение (которое чаще всего бывает примерно в том же порядке — потому что чаще всего используются "новые" данные) — не лучше.

Pavel-Nikiforov Автор вопроса
Yaroslav Schekin
Нет, именно случайны, при чём тут "разброс"? Для b...

хорошо, а как тогда b-tree поступает в случае с "композитным" индексом ? когда (uuid, dt), причем dt всегда набегает вперед, но не равномерно ?

Yaroslav Schekin
Нет, именно случайны, при чём тут "разброс"? Для b...

Подскажите а какие недостатки вместо B-Tree для UUID4 использовать Hash индекс?

Pavel-Nikiforov Автор вопроса
Pavel Nikiforov
hash не умеет 2 поля индексировать

Но можно проиндексировать uuid || dt::text )

Pavel-Nikiforov Автор вопроса
Евгений Смирнов
Но можно проиндексировать uuid || dt::text )

ну кстати да, вариант. минус в том, что в хеше будет храниться не бинарное представление uuid (16 байт), а строка. Как вариант сделать на сях функцию, которая будет делать то же самое, но результатом будет bytea .

Pavel Nikiforov
ну кстати да, вариант. минус в том, что в хеше буд...

Так выхлоп всё равно int32, хотя без тестов не скажешь, что будет быстрее.

Pavel-Nikiforov Автор вопроса
Евгений Смирнов
Так выхлоп всё равно int32, хотя без тестов не ска...

я не знаю, как там реализовано в постгресе, но если там классический хеш в 2 уровня, то где-то надо хранить уже сами ключи (2й уровень), без хеширования, для уже перехода на кнкретную запись в таблице с данными. а если там будут hex строки - это не эффективно. Но надо попробовать, идея хорошая.

Pavel Nikiforov
я не знаю, как там реализовано в постгресе, но есл...

> Полученное число можно использовать как индекс обычного массива, куда и складывать ссылки на строки таблицы (TID) > ... > Страницы корзин (bucket page) — основные страницы индекса, хранят данные в виде пар «хеш-код — TID»; Читал наискосок, но вроде бы исходное значение не хранится вообще.

Pavel-Nikiforov Автор вопроса
Евгений Смирнов
> Полученное число можно использовать как индекс о...

да, это действительно так - в индексе самих ключей нет, лишь массивы страниц относящихся к кешу. это хорошо. Спасибо за совет.

Pavel Nikiforov
хорошо, а как тогда b-tree поступает в случае с "к...

Смотря как именно используется такой индекс. Если речь о вставках, где для последних использованных UUID вставляются последовательно dt — это [существенно] лучше, чем просто вставка UUID-ов (вставки менее случайны). Если используемые UUID-ы произвольны — то примерно так же.

Alex
Подскажите а какие недостатки вместо B-Tree для UU...

Обычные недостатки hash indexes (см. в документации). Опять-таки, проблема индексации UUID именно в том, что зачастую они образуют случайную последовательность (если используются как суррогатный ключ, например).

Похожие вопросы

Обсуждают сегодня

А чем вам питонисты не угодили?😂
.
79
Привет, запускаю werf в dind в k8s, получаю ошибку на этапе build/beforeSetup: /.werf/stapel/embedded/bin/bash: /.werf/scripts/5898bdfe5214357d3706b879cc8d3d78460fb379607cbd...
florius0
4
Dim Dim, [02.07.2024 11:07] DB 0x62 Dim Dim, [02.07.2024 11:07] DB 0x66 Dim Dim, [02.07.2024 11:07] кто пояснит что это?
Dim Dim
14
Всем привет, написал код ниже, но он выдает сегфолт, в чем причина? #include <stdio.h> #include <stdlib.h> #include <string.h> struct product { char *name; float price; };...
buzz базз
75
Язык Си можно выучить за день? По книжке ANSI C на 230 страниц
Vincent Vegan
29
Кстати, я тут еще с одной темой столкнулся, вот учу я C++, на таком то ресурсе, а остальные постоянно советуют практиковаться, что то писать, проекты, но как писать если вот т...
aaswq1
7
Ребят, а за скок можно впарить анон чат с апишкой и веб админкой ?
Eugene Неелов
15
Подскажите, можно ведь комбинировать запись данных в один и тот же Stream через TFileStream и через TCompressionStream поочерёдно? Ну т.е. часть данных мне нужно сжать, часть ...
notme
4
Ещё такой вопрос. Мне необходимо хранить пароль пользователя локально. Для этого планирую использовать ini файл. Это для автозаполнения полей логин и пароль при авторизации. Е...
Евгений
19
Ребят, кто сталкивался с тем, что Electron.js не разворачивает билд React.js-приложения? Голый body в чёрном цвете, как и должно быть, но остального - нет. Билд работает исп...
..
6
Карта сайта