
Mikhail
30.04.2017
22:47:28
минус семь дней от текущей даты
в принципе уже сразу можно для этой выберки по последней недели применить btree_gist по времени
но дальше все равно нужно или представление или materialized view

Denis
30.04.2017
22:52:27
Тут нужно поиграться с индексом по нескольким колонкам. У вас сколько записей в неделю (порядок?)

Google

Mikhail
30.04.2017
22:56:24
есть только расчетные значения. 100000 вставок в день. Строки не апдейтится, а только добавляется новая инфа

Denis
30.04.2017
22:57:16
Ага, порядка миллиона. Я поэкспериментирую и отпишусь)

Mikhail
30.04.2017
23:00:12
Да, спасибо, будет интересно увидеть твое решение.

Denis
01.05.2017
01:34:13
Важный уточняющий вопрос. Пользователи, которые не получали никаких новых баллов в amount в отборе ближайших участвуют?

Just
01.05.2017
02:08:51


Denis
01.05.2017
02:19:12
Да, спасибо, будет интересно увидеть твое решение.
Я понимаю, что статистику ближайших надо будет строить часто и быстро. Поэтому нужен кеш и я предлагаю создать таблицу weekly_deals и использовать ее как регистр оборотов. План примерно такой:
Таблица deals:
1. Покрывающий btree индекс date_trunc('day', date), user_id, amount. Опционально партицирование через pg_pathman
Таблица weekly_deals (userid, amount):
2. Аудит в таблицу weekly_deals_audit через триггер на строку
3. Транзакция старт
4. Блокировка на запись deals
5. Вставить в weekly_deals агрегацию из deals за 6 дней (без сегодня)
6. Построить gist индекс по amount (create extension)
7. На deals добавить построчный триггер обновления amount для каждой новой вставки
8. Транзакция коммит
9. Регламентное ежедневное задание, удаляющее из deals_weekly данные за самый старый день
Ну и ищите ближайших в weekly_deals через gist
Из недостатков - я не доверяю всяким конструкциям типа регистров оборотов, в них всегда может пойти несогласованность данных. Плюс, в момент создания у вас будет простой, наверное секунд на 15. И главное, когда будете первоначально заполнять таблицу weekly_deals, убедитесь, что используете покрывающий индекс - у меня на 2 млн в таблице за две недели агрегация за неделю строилась на покрывающем индексе 4 секунды.
А почему trans_date не участвует в поиске по индексу, а только в sequence scan? Может, ее стоит добавить в покрывающий индекс?


Just
01.05.2017
02:40:23

Denis
01.05.2017
02:42:30
Вам нужен (trans_date, payer_edrpou) по двум колонкам

Just
01.05.2017
02:43:21

Denis
01.05.2017
02:44:32
Никакой разницы вроде

Google

Denis
01.05.2017
02:45:32

Just
01.05.2017
02:46:24
неа, этот индекс не используется, запрос строится так же само

Denis
01.05.2017
02:52:51

Just
01.05.2017
02:55:00
на самом деле сфинкс очень быстро делает такие запросы и если использовать базу толька для запросов по списку id'шек (и разбить pathman'ом таблицу по id'кам, а не датам) то будет сносно. правда мне это кажется не совсем полноценным, хотя если бы база была на SSD или хотя бы индексы, то было бы тоже нормально

Denis
01.05.2017
02:57:21
Кстати, у меня мысль! Можно разбить ваш запрос на два и склеить их union. В первом будет покрывающий индекс trans_date + payer_edrpou, а во втором - trans_date + recipt_edrpou

Just
01.05.2017
02:58:22
это как раз лучшее, что удалось сделать с mysql и что в итоге работает за 5-7 секунд))
но при первых тестах с постресом он такое же время давал на одинарных индексах, а юнион работал даже хуже. может я неудачный выбрал тогда запрос (период, организацию). но было так, можно еще проверить

Denis
01.05.2017
03:00:38

Just
01.05.2017
03:02:22
сейчас первую базу я партицировал, развернул аналогичную, но там тяжелые апдейты идут и они кажется, что существенно грузят ее, т.ч. не уверен, что это будет честный экперимент. хотя чисто на план запрос это наверное и не влияет особо? создам индексы пока

Denis
01.05.2017
03:03:32
Нет, интересен план и оценки.

Just
01.05.2017
03:06:53
создание около часа займет примерно, может усну до того времени, но отпишусь сегодня в результатами в любом случае

Denis
01.05.2017
03:09:23
Так создайте тестовую базу с только родительской таблицей и партицией за 16 год. В ней 2.8 млн...По ней индекс пулей построится, а нам ничего другого для тестов и не надо
На худой конец просто нагенерируйте туда рандомных данных
Можно вообще просто одну дочернюю таблицу, нужно же понять, даёт ли два покрывающих индекса преимущество

Just
01.05.2017
03:12:14
да, логично, так и сделаю

Denis
01.05.2017
03:16:08
И в индексах важен порядок колонок. Мне кажется, будет адекватно работать только порядок (payer_edrpou, trans_date) и (recipt_edrpou, trans_date)

Just
01.05.2017
03:21:20
хм, а я создал как раз наоборот, что же, тоже сравним. сам запрос
explain analyze select * from
((select id from transactions_16 where trans_date>='2016-12-15' and trans_date<='2017-01-14' and payer_edrpou='00013480' limit 300)
union
(select id from transactions_16 where trans_date>='2016-12-15' and trans_date<='2017-01-14' and recipt_edrpou='00013480' limit 300)) t
join transactions_16 on t.id=transactions_16.id limit 300;
норм или перемудрил?

Google

Denis
01.05.2017
03:25:11
Запрос ок, а результат печальный. Давайте наоборот колонки в индексе проверим?
Хотя погодите, запрос не норм. Я не понял, зачем бы подзапросом выбираете id и присоединяете по нему таблицу

Just
01.05.2017
03:26:53
explain analyze
(select * from transactions_16 where trans_date>='2016-12-15' and trans_date<='2017-01-14' and payer_edrpou='00013480' limit 300)
union
select * from transactions_16 where trans_date>='2016-12-15' and trans_date<='2017-01-14' and recipt_edrpou='00013480' limit 300;
вот прямая версия
правда тут с лимитом не совсем то, но тоже пусть будет, для сравнения

Denis
01.05.2017
03:28:48
Ладно, а можно только первую часть? Я не понимаю, почему не использует планировщик индекс по обоим колоннам

Just
01.05.2017
03:28:48

Denis
01.05.2017
03:31:07
А можно посмотреть созданный индекс? Я в замешательстве)
Вообще, с таблицы убрать все индексы, кроме двойного?

Just
01.05.2017
03:32:21
а как его посмотреть?) хотя что-то тут и правда неладное явно

Just
01.05.2017
03:33:17
сейчас порядок поменяю

Denis
01.05.2017
03:33:59
Давайте убьём всех, кроме нашего. Я подозреваю, что планировщик использует вначале кластеризрванный

Just
01.05.2017
03:35:24
пересоздал, кстати создались они вообще влет
в другом порядке это занимало минуту +-
новые все равно не использует, кстати
а, это я на родительской пустой таблице создал, сори

Google

Denis
01.05.2017
03:38:16

Just
01.05.2017
03:43:19
создал нормально, но итог тот же) CLUSTER index trans_date дропнул, дропну сейчас другие и еще раз запущу

Denis
01.05.2017
03:46:04
Сделайте vacuum freeze на партицию

Just
01.05.2017
03:48:04
запустил. это 5 сек заняло считать 300 строк с диска, выходит или вот это Recheck Condition просто seq scan делает, не пойму

Denis
01.05.2017
03:50:12
Он продолжает делать перепроверку в таблице после обновления карты видимости? Странно. Точно vacuum freeze на патрицию отработал?

Just
01.05.2017
03:50:45

Denis
01.05.2017
03:51:09
Ну это норма, он карту видимости вам делал)

Admin
ERROR: S client not available

Just
01.05.2017
03:51:37
так он норм сработал же?

Denis
01.05.2017
03:53:01
А, я понял. Уберите в запросе * и замените на truns_date
Чтобы он только в индекс лез. Если сработает, добавим в индекс ещё id

Just
01.05.2017
03:53:50
а хотя не лучше, после вакуум то же время

Denis
01.05.2017
03:55:57
Ненене, там в таблицу лезли, так как мы запрашивали все поля из таблицы, а их не было в индексе. Нужно создать индекс по трём колонкам - времени, recip и id. И в селекте выбирать id

Just
01.05.2017
03:58:52
не совсем понимаю, в чем разница между лезть в таблицу по индексу и по id, там же физические адреса хранятся, как я понимаю. надо будет принцип работы постгрес поизучать)

Google

Denis
01.05.2017
04:02:07
Индекс - это отдельный файл. Если постгрес может все данные вытащить из него, он берет только оттуда и не лезет за каждой строкой в файл таблицы. Потом, так как в индексе нет версий строк, он просматривает карту видимости. И те строки из индекса , которые видят не все транзакции перепроверяются в таблице

Just
01.05.2017
04:04:11
а с доступов по id разве не то же самое, я так понимаю, это такой же индекс?

Denis
01.05.2017
04:04:46

Just
01.05.2017
04:05:50
ну т.е. запрос c where id=N использует такой же индекс, как и обычные индексированные колонки?

Denis
01.05.2017
04:07:44
Да, абсолютно. Лежит себе отдельный файл с индексом id и оттуда вытаскивать можно только значения id

Just
01.05.2017
04:09:25

Denis
01.05.2017
04:13:59
Ну хорошая новость, мы не вылезти из индекса) Плохая, что ищем медленно)) Давайте поменяем колонки местами
Первые две

Just
01.05.2017
04:14:41
давайте, почему бы, собственно, и нет
Первые две
создал еще два таких индекса, но планировщик их не использует, думаете, стоит удалить те, что использует?

Denis
01.05.2017
04:21:46
Да, определенно

Just
01.05.2017
04:24:49

Denis
01.05.2017
04:25:43
Грустно... покрывающие индексы нас не спасли.

Just
01.05.2017
04:26:29

Denis
01.05.2017
04:27:50
Ну тут для чистоты эксперимента нужен ещё просто индекс по id для join, наверное
Но в целом все ясно с результатами

Just
01.05.2017
04:28:15
не понимаю, почему это не работает быстро, дается около 300 готовых id'шек, но планировщик циклы в цыкле делает. проверю просто по списку id как будет
Ну тут для чистоты эксперимента нужен ещё просто индекс по id для join, наверное
explain analyze select * from
((select id from transactions_16 where trans_date>='2016-12-15' and trans_date<='2017-01-14' and payer_edrpou='00013480' limit 300)
union
(select id from transactions_16 where trans_date>='2016-12-15' and trans_date<='2017-01-14' and recipt_edrpou='00013480' limit 300)) t
join transactions_16 on t.id=transactions_16.id limit 300;
такой запрос? тоже тестил, ~9 сек на payer,date,id

Denis
01.05.2017
04:31:18

Just
01.05.2017
04:31:42

Denis
01.05.2017
04:32:03
Нет, ещё отдельный один
Просто id

Just
01.05.2017
04:32:15
а, понял