
Yaroslav
24.10.2017
05:05:39
Кстати, Вы могли бы попробовать оптимизировать этот запрос (хотя бы проверить, есть ли подходящие индексы и т.д.)
Да, держит, а что ему делать-то? Он запрос-то ещё, может, и не выполнил целиком... и, возможно, не выполнит до выдачи всех данных.

??Suffer
24.10.2017
05:09:24

Yaroslav
24.10.2017
05:10:53
Естественно, если Вы читаете ~3M rows 20 минут, много он не потребит.

Google

Anton [Mgn, az09@osm]
24.10.2017
05:11:15
ходить по курсору питоном имхо моветон. в хранимке норм

??Suffer
24.10.2017
05:11:45

Anton [Mgn, az09@osm]
24.10.2017
05:12:43
А какая разница?
еще один слой, не?
на самом деле я даже не представляю как это делается из питона ))

??Suffer
24.10.2017
05:12:52
что именно?
cur.execute("declare foo cursor for select * from generate_series(1,1000000)")
cur.execute("fetch forward 100 from foo")
rows = cur.fetchall()
# ...
cur.execute("fetch forward 100 from foo")
rows = cur.fetchall()
# and so on
Все равно же в хранимке тожуе будет занято много памяти.

Yaroslav
24.10.2017
05:14:48
В общем, раз Вам нужно 20 минут на обработку данных, нужна или же память для активного запроса (а сколько её будет —- зависит от work_mem); либо память только для результатов —- на клиенте (если Вы считываете всё сразу, с курсором или без, и завершаете транзакцию), или же на сервере —- если использовать WITH HOLD в курсоре.

??Suffer
24.10.2017
05:16:42
WITH HOLD specifies that the cursor can continue to be used after the transaction that created it successfully commits. WITHOUT HOLD specifies that the cursor cannot be used outside of the transaction that created it. If neither WITHOUT HOLD nor WITH HOLD is specified, WITHOUT HOLD is the default.
Yaroslav больше спасибо за разъяснение!


Yaroslav
24.10.2017
05:20:26
In the current implementation, the rows represented by a held cursor are copied into a temporary file or memory area so that they remain available for subsequent transactions.
А так, или уменьшайте work_mem, или попробуйте оптимизировать сам запрос.

Google

Yury
24.10.2017
05:23:58
на самом деле интересный кейс
@ihor_ukraine вам бы условие какое-нибудь ввеcти и отрезать кусками, и кушать в Django.

Yaroslav
24.10.2017
05:27:15
seq scan ничего и не держит. А вот hash-и, materialize-ы и т.п. останутся с нами до победного конца. ;)

Yury
24.10.2017
05:28:20
но это уже другая тема
@ihor_ukraine и не волнуйтесь на счёт ООМ киллера, постгрес умеет все действия делать на диске.


??Suffer
24.10.2017
05:30:47
@ihor_ukraine вам бы условие какое-нибудь ввеcти и отрезать кусками, и кушать в Django.
Сейчас оно работает вот так
def queryset_iterator(queryset, chunk_size=250000):
"""
Iterate over a Django Queryset ordered by the primary key
This method loads a maximum of chunk_size (default: 1000) rows in it's
memory at the same time while django normally would load all rows in it's
memory. Using the iterator() method only causes it to not preload all the
classes.
Note that the implementation of the iterator does not support ordered query sets.
"""
try:
last_pk = queryset.order_by('-pk')[:1].get().pk
except ObjectDoesNotExist:
return
pk = 0
queryset = queryset.order_by('pk')
while pk < last_pk:
for row in queryset.filter(pk__gt=pk)[:chunk_size].iterator():
pk = row.pk
yield row
gc.collect()
Оно медленно и прожорливо
Я пойду посплю, перепишу на новый код и потом попробую на проде

Yury
24.10.2017
05:33:28
ну вас и так не быстро идёт обработка

??Suffer
24.10.2017
05:33:41
Основная проблема с этим решениям
Note that the implementation of the iterator does not support ordered query sets.

Yury
24.10.2017
05:33:46
почему индексов нету к слову?

??Suffer
24.10.2017
05:34:35

Yury
24.10.2017
05:35:34
для join они могут огого как взлететь

??Suffer
24.10.2017
05:37:40
"forensics_forensic"."is_archived" = False AND "forensics_forensic"."is_valid" = True
вот эти значения будут постоянны, а остальные where разные могут быть
Для такого случая подойдет Partial Index?
@stalkerg спасибо за советы. Я уже завтра попробую индексы

Google

Yury
24.10.2017
05:48:16
приятных снов

??Suffer
24.10.2017
05:50:22

Michael
24.10.2017
06:07:19
Всем привет
МОжете подскзать, почему БД себя ведет так.
Есть у нас БД1. Через createdb -T создаю копию БД2. 1 к 1.
Затем делаю реиндекс основных таблиц на БД2.
После реиндекса - гоняю на БД2 те же запросы, что и на БД1.
На БД2 - запросы висят жестко. Фуллскан идет, некоторых запросов.
В субботу я оставил в покое БД2.
Вчера ночью полез проверить БД2, и вуаля, запросы летают так же как и на БД1.
Можете подсказать, что это может быть?

Yury
24.10.2017
06:08:23
статистику собрать нужно?

Michael
24.10.2017
06:08:38
собирал

Yury
24.10.2017
06:09:55
надо смотреть запроссы, и explain analyze что бы понять, почему он ошибается на одной БД и не ошибается на другой
я ведь верно понял, что проблемма в том что на БД1, у вас сексканы пошли вместо индекс сканов?
но обычно тут дело в статистике и... а вы на какой БД делали реиндекс?

Michael
24.10.2017
06:12:04
на БД2
БД1 вообще не трогал
на БД1 я не делаю ничего
тк просто с нее создал клон БД2

Yury
24.10.2017
06:13:01
ну вот explain analyze вам скажет почему
если реально индекс есть и эстиматор правильно всё предсказал то ответ должен быть достаточно очевидным
/me всё же надо добавить в SQL стандарт индексы... хотя бы как запись в лог если индекс который хотел использовать, не сработали.
нужно как то уменьшать неочевидности в исполнении SQL...
хотя бы как:
select * from my_table where my_table.field1{my_index2} = 10;
надо глянуть BISON, кажется эту граматику будет не трудно добавить. Ладно, это на правах бреда.

Michael
24.10.2017
06:28:49
спасибо
буду копать

Yaroslav
24.10.2017
06:39:02

Google

Yaroslav
24.10.2017
06:39:33
спасибо
буду копать
У Вас, скорее всего, дело в том, что на копии за ночь отработал autoanalyze.

Yury
24.10.2017
06:40:10

Yaroslav
24.10.2017
06:40:41

Yury
24.10.2017
06:40:45
хинты это плохо
может SQL2

Michael
24.10.2017
06:42:00

Yaroslav
24.10.2017
06:42:47
А я совсем не хочу. Зачем это надо? Я хочу, чтобы результаты были верные, по возможности, быстро.

Yury
24.10.2017
06:43:08

Yaroslav
24.10.2017
06:47:00
Ну уж индексные hint в таких случаях довольно плохо подходят (и мало в каких подходят вообще, IMHO).
Вот cardinality hints, возможно, были бы интересны.

Yury
24.10.2017
06:48:14

Yaroslav
24.10.2017
06:49:11
Хмм... в смысле?

Yury
24.10.2017
06:49:20
т.е. если твоё приложение закладывается на использование индексов, хочется как то узнать, что кто то напортачил и они не используются.
ну т.е. не будешь же ты вручную эксплейны отсматривать (а на пустой БД вообще мало смысла), или логи?
т.е. по сути юнит тест для БД

Yaroslav
24.10.2017
06:51:01
Почему закладывается-то? По каким причинам?

Yury
24.10.2017
06:51:46
ну когда ты 100% знаешь что тут должна быть индексная выборка и она 100% быстрее секскана

Yaroslav
24.10.2017
06:51:49
И зачем EXPLAIN-ы отсматривать?

Google

Yury
24.10.2017
06:52:22
потому что лезешь с эксплейном уже тогда когда что то тормозит....

Yaroslav
24.10.2017
06:52:51
Никто этого почти никогда не знает. На то и оптимизаторы. Т.е. это вообще не аргумент. :(

Николай
24.10.2017
06:54:27
доброе утро) вопрос про оптимальный алгоритм) задача - есть таблица model, там поля id, date_modified (Python, Django, date_modified = models.DateTimeField(_('date modified'), auto_now=True), там дата изменения документа с микросекундами, которые стоит игнорить), есть некий список словарей на питоне [{‘id’: 1, ‘date_modified’: 1508817032}, …], тут unixtimestamp в секундах, задача - написать, какие id из этого списка имеют отличные date_modified от СУБД, то есть сделать список id изменённых документов
допустим, в списке 100 000 пар объектов, как лучше сделать - выгрузить все данные одним запросом и на питоне сравнивать или делать кучу запросов к базе? или какой-нибудь третий вариант (один неведомый запрос к базе)?
Подготовить эти данные фоновым процессом никак не связанным с работой веб сервера.

Anton [Mgn, az09@osm]
24.10.2017
06:54:40

Yaroslav
24.10.2017
06:55:42
Так если оптимизатор их не использует, в 99% случаев дело-то в том... что разработчику казалось неправильно. ;)

Anton [Mgn, az09@osm]
24.10.2017
06:56:40
на схему данных смотрел, грибы кушал, потребности фронта осознал, создал охватывающий индекс, а он бац и не юзается. потому что оптимизатор умнее тебя оказался. ну, такое себе

Yaroslav
24.10.2017
07:10:06
на схему данных смотрел, грибы кушал, потребности фронта осознал, создал охватывающий индекс, а он бац и не юзается. потому что оптимизатор умнее тебя оказался. ну, такое себе
Бывает, что поделаешь... Вообще, мне кажется, индексы, которые должны подходить для "критичных" запросов, нужно создавать. Но в том, что они не используются в каких-то ситуациях, страшного (самого по себе) ничего нет.

Аггей
24.10.2017
07:21:42

Yaroslav
24.10.2017
07:29:54

Аггей
24.10.2017
07:33:52

Yaroslav
24.10.2017
07:39:48

Anton [Mgn, az09@osm]
24.10.2017
07:40:34
@pasha_golub @Komzpa вы в доле?))

Аггей
24.10.2017
07:43:41
А это, по идее, довольно редкая ситуация, разве нет?
Частая. Особенно для новых систем. На этапе разработки невозможно учесть специфики данных. Допустим мы храним историю изменений в той же таблице и предполагаем, что изменений будет достаточно много - строим индекс с доп полем is_actual - и на начальном этапе - все тыркаются вносят/правят данные... Достаточно много как актуальных так и исторических данных... Индекс сразу фильтрует большую часть записей по признаку актуальности. Потом пользователи "освоились" и практически всегда вносят данные без ошибок... У нас доля актуальных растёт и индекс становится не привлекательным... мертвым
А так да... Я сам делаю так - строю индексы под все тяжёлые запросы в системе... Потом выделяю общие из них... Убираю неиспользуемые... Часть переделываю в частичные (как раз для is_actual)...

Anton [Mgn, az09@osm]
24.10.2017
07:51:59