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

Всем привет, вопрос по view-ам. Есть запрос который с помощью

CROSSTAB переворачивает данные из длинного в широкий формат.
Таблица к которой обращается запрос имеет более чем 500кк записей.
Пример запроса:
SELECT * FROM CROSSTAB(
'SELECT dt, name, value
FROM some_huge_table
WHERE dt >= ''2023-05-19 00:00:00'' AND dt < ''2023-05-20 00:00:00''
ORDER BY 1,2'
)
AS summary(
dt TIMESTAMP,
"1" FLOAT,
"2" FLOAT,
"3" FLOAT,
...
"1000" FLOAT

При выполнении этого запроса с фильтром по времени все работает хорошо и быстро.
В случае помещения этого запроса во view, но уже без фильтра, а фильтрацию осуществлять на view-хе, запрос зависает.
SELECT *
FROM some_view
WHERE dt >= '2023-05-19 00:00:00' AND dt <= '2023-05-20 00:00:00'

Я почему-то всегда думал, что postgres при фильтрации по вьюхе будет выгружать только диапозон строк, а не всю вьюху.
А в итоге получается что он сначала все выгружает, а уже потом фильтрует?
Работает как HAVING?

43 ответов

22 просмотра

так у вас там crosstab - в него нельзя услловие прокинуть, это ж функция со строкой на входе

Vander-Svanlin Автор вопроса
Konstantin Zaitsev
так у вас там crosstab - в него нельзя услловие пр...

Хм, а я даже не подумал об этом. Понял, спасибо

Для начала разговора про скорость запросов представьте информацыю из закрепа: https://t.me/pgsql/303899 Без этого такие разговоры будет совершэнно беспредметными. PS А, и да, откажытесь от crosstab. В нём нет никакого смысла в RDBMS.

Vander-Svanlin Автор вопроса
Ilya Anfimov
Для начала разговора про скорость запросов предста...

С CROSSTAB просто переворачивать таблицу из узкого формата в широкий. Почему вы не советуете его использовать?

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

Ilya Anfimov
Потому, что это противоречит типизацыи в RDBMS. М...

ну от PIVOT в субд, которые его поддерживают, еще нико не умер:))))

Vander-Svanlin Автор вопроса
Ilya Anfimov
Потому, что это противоречит типизацыи в RDBMS. М...

Ну если так рассуждать то и функции нельзя использовать в СУБД. Мы пробовали переворачивать через pandas, но postgres отрабатывает на порядок быстрее

Konstantin Zaitsev
ну от PIVOT в субд, которые его поддерживают, еще ...

В большынстве случаев можно и вообще СУБД выкинуть -- и никто не умрёт. А так, людей, которые встряли на 1600 или страдали из-за нюансов типизацыи строки с названиями -- я встречал.

Vander Svanlin
Ну если так рассуждать то и функции нельзя использ...

Выпрямите руки, да. pandas переворачивает на скорости копирования в памяти примерно. Кроме того, если у вас столько данных, чтобы это было заметно -- то crosstab у вас не сработает...

Vander-Svanlin Автор вопроса
Ilya Anfimov
Выпрямите руки, да. pandas переворачивает на скор...

Думаю вам сначала надо попробовать подобное сделать на реальном проекте с помощью pandas, а потом токсичностью тут изливаться. Видно, что вы не юзали такое глубоко

Vander Svanlin
Думаю вам сначала надо попробовать подобное сделат...

Вот лично я транспонировал матрицы последний раз на алгебре и первом курсе программирования. Про кросстаб услышал тут впервые пару месяцев назад и ума не приложу зачем они нужны в базах данных.

Роман Жарков
Вот лично я транспонировал матрицы последний раз ...

в SQL оно нормально - PIVOT, UNPIVOT (не сильно нужно, но вполне нормально и полезно) 1 берем оттчеты мменеджеров не думая грузим copy 2 unpivot 3 agragate 4 pivot 5 copy все конечно можно написать в приложении не вопрос

Vander-Svanlin Автор вопроса
Роман Жарков
Вот лично я транспонировал матрицы последний раз ...

У нас в базе храниться огромное количество показателей снимаемых с сотен датчиков в узком формате (dt, name, value). По этим показателям саентисты строят свои модели, но их модели принимают данные только в широком виде (dt, name1, name2, ... name1000). Поэтому есть задача переворота данных из узкого формата в широкий. Выгрузку необходимо делать например за 90 дней, за это время в таблице накопиться порядка 200кк строк, пандас справляется, но делает это гораздо дольше, условно 5 минут, когда постгрес за 1 минуту. Для того и используем crosstab.

Роман Жарков
Вот лично я транспонировал матрицы последний раз ...

это гораздо быстрее чем загружать этим клиентское приложение, и позволяет заметно уменьшить объем данных, передаваемых клиенту. А еще в какой-то степени позволяет эмулировать запросы в колоночное хранилище (для клиента)

Nikita Malakhov
речь о crosstab

так это убогий PIVOT )

Может быть, лучше примерно так агрегировать в массивы/json с помощью обычных SQL-запросов, чтобы условия пробрасывались внутрь VIEW ? (Не уверен, что правильно понял смысл этой тысячи столбцов в crosstab) create table test_pivot as select id, data from generate_series(1, 10000) id, enerate_series(1, 1000) data; create view test_pivot_view as select id, array_agg(data) data from ( select id, data, row_number() over (partition by id order by data) n from test_pivot ) foo group by id, (n - 1) / 100; select * from test_pivot_view; 11233.465 ms select * from test_pivot_view where id > 1234 and id < 1237; 235 ms 1234 | {1,2,3,...98,99,100} 1234 | {101,102,103,...198,199,200} ...

Vander Svanlin
У нас в базе храниться огромное количество показат...

Постгрес в принцыпе неспособен сделать crosstab на 200 милионов строк...

Konstantin Zaitsev
почемму?)))))

Потому, что в нём лимит 1600 столбцов, а crosstab делает строки — стобцами.

Ilya Anfimov
Потому, что в нём лимит 1600 столбцов, а crosstab ...

да нет же ) ттам хреновая документация на расширениее

Ilya Anfimov
Потому, что в нём лимит 1600 столбцов, а crosstab ...

этот не транспониирование всео запроса

Vander Svanlin
У нас в базе храниться огромное количество показат...

А что б и модели-то сразу в PostgreSQL не строить, зачем данные куда-то таскать? ;) В общем, посыл подобных советов, во-первых, в том, что подобные преобразования — это "оформительство" (так можно дойти и до того, чтобы в отчётах считать итоги по группам на сервере... а потом возвращать какие-то поля, которые будут указывать клиенту, в какой цвет красить данные ячейки в отчёте... а затем уже вообще генерировать отчёт целиком (в html или т.п.)... ну и почему бы сразу уж не отсылать его на e-mail / не выкладывать куда-то, зачем вообще клиенту что-то возвращать?!). Т.е. неплохо было бы остановиться сразу, не скатываясь в вышеописанное безумие нецелевое использование СУБД. Во-вторых, большинство RDBMS работают как статически типизированные системы, причём это относится не только к типам полей, но и к типам обрабатываемых и возвращаемых отношений (точнее, таблиц, если речь об SQL). Поэтому нормального пути вернуть из запроса или функции отношение динамического типа (к примеру, либо (a int, b int, c int), либо (d numeric, e text) ) исключительно в зависимости от того, какие данные "попались" этому запросу, просто нет ("ненормальные", вроде композитных типов и т.д. и т.п., конечно, существуют). Т.е. это "религия" не в большей степени, чем невозможность (например, в C ) вернуть double из функции, которая объявлена, как возвращающая int.

Vander-Svanlin Автор вопроса
Nikita Glukhov
Может быть, лучше примерно так агрегировать в масс...

Мы что-то на подобие в начале проектирования думали создать, только использовали jsonb, но потом при раскладке в датафреймы пандаса сильно страдала скорость из-за того что надо было сливать между собой эти json-ы. Хотя пандас вроде как специальный инструментарий имеет под эту задачу. В итоге был выбор либо хранить уже в широком виде в самих таблицах, но тогда мы бы померли от апдейтов и блокировок, либо переворачивать через crosstab.

Yaroslav Schekin
А что б и модели-то сразу в PostgreSQL не строить,...

считать итоги по группам плохо на сервере?)))))

и pivot не возвращщаеет динамичесие типы)

Nikita Malakhov
это гораздо быстрее чем загружать этим клиентское ...

просто как правило это недальновидно с т. з. нагрузки на сервер БД: изменения представления данных средствами сервера тем менее оправданы, чем более эти изменения его нагружают. просто есть менее затратные изменения представления, такие как кол-во точек после запятой в дробных числах, формат таймштампа... и есть более затратные, и crosstab — это один из эталонов затратности. в конкретно вашем случае это, может быть, и не представляет особых проблем, однако как правило транспонирование — достаточно простая в реализации вещь для того, чтобы делать это на фронте (т. е. не в СУБД), и вместе с этим достаточно ресурсоёмкая, чтобы не грузить этим базу (если у неё действительно есть чем ещё заняться). crosstab не экономит ни объём, ни делает ещё какой-то особой магии по подсчёту... а так люди порой и от сортировки избавляются, как от явной, так и от вынужденной...

Konstantin Zaitsev
считать итоги по группам плохо на сервере?)))))

Нет, не плохо — это иллюстрация "благими намерениями вымощена дорога в ад". Т.е. начинается-то это всё невинно, а вот далее... см. выше.

Konstantin Zaitsev
и pivot не возвращщаеет динамичесие типы)

Естественно, не возвращает. Я же не просто так написал, что "нормального пути вернуть ... отношение динамического типа ... просто нет".

Vander-Svanlin Автор вопроса
Ilya Anfimov
Постгрес в принцыпе неспособен сделать crosstab на...

200кк строк это не значит что в широком виде будет 200кк показателей, показателей как раз таки до 1600. 139088688 перевернул изи за 2.5мин

Vander Svanlin
200кк строк это не значит что в широком виде будет...

А, действительно, есть тут такой вариант.

Vander Svanlin
Мы что-то на подобие в начале проектирования думал...

Вместо использования jsonb-объектов можно попробовать jsonb-массивы (или обычные), с которыми должно быть дешевле работать из Питона. Для эффективного создания массивов нужна специальная агрегатная функция, умеющая писать нужный элемент по индексу, чтобы каждое свойство всегда лежало на одном и том же месте (для свойств нужны будут их числовые id). Такую функцию можно даже на SQL написать, но она, конечно, очень медленно будет работать (еще в нее приходится передавать максимальное кол-во элементов, потому что jsonb_set не умееет произвольно расширять массив): CREATE FUNCTION jsonb_agg_idx_trans( arr jsonb, elem anyelement, idx int, max_elems int ) RETURNS jsonb AS $$ SELECT jsonb_set(COALESCE(arr, to_jsonb(array_fill(NULL::int, ARRAY[max_elems]))), ARRAY[idx::text], to_jsonb(elem)) $$ LANGUAGE SQL STABLE; CREATE AGGREGATE jsonb_agg_idx( elem anyelement, idx int, max_elems int ) ( SFUNC = jsonb_agg_idx_trans, STYPE = jsonb ); CREATE TABLE test AS SELECT id, 'prop' || i AS name, id * 1000 + i - 1 AS val FROM generate_series(1, 1000) id, generate_series(1, 100) i WHERE (id + i) % 3 = 0; CREATE TABLE properties AS SELECT i - 1 AS id, 'prop' || i AS name FROM generate_series(1, 100) i; SELECT t.id, jsonb_agg_idx(t.val, p.id, 100) FROM test t JOIN properties p USING (name) GROUP BY 1; 1 | [null, 1001, null, null, 1004, ... 1097, null, null] 2 | [2000, null, null, 2003, null, ... null, null, 2099] ...

Nikita Glukhov
Вместо использования jsonb-объектов можно попробов...

Вот кстати типичный пример когда pivot jsonb проще ))))

Vander-Svanlin Автор вопроса
Vander Svanlin
Потестю Ваш способ в пн, спасибо)

Надо на C написать эту функцию и от джойна по имени свойства избавиться, без этого все очень медленно работает -- порядка 100 000 строк в секунду.

Vander Svanlin
Ну да, медленно

Реальная скорость на C должна получиться такой же, как и у остальных агрегатных функций. На предыдущем примере с 10М строк у меня такие числа получились: array_agg() -- 2.9 Mrow/s json_agg() -- 2.3 Mrow/s jsonb_agg() -- 1.2 Mrow/s jsonb_agg() очень неэффективно написана, надо бы ее переделать.

А jsonb_object_agg тоже?

Konstantin Zaitsev
А jsonb_object_agg тоже?

jsonb_object_agg(), конечно, намного удобнее на стороне сервера, но на стороне клиента парсинг объектов и извлечение значений из них, возможно, будет заметно медленнее, чем у массивов. json[b]_object_agg() раза в полтора медленнее, чем json[b]_agg(). И использовать jsonb в данном случае, когда результат передается клиенту в виде текста, смысла нет, так как мы получим лишний оверхед промежуточного кодирования в jsonb. В примере выше я использовал jsonb, потому что, во-первых, у нас нет array_set() и запись элемента массива по индексу возможна только в UPDATE tab SET arr[idx] = val (что очень плохо), и, во-вторых, у нас нет json_set().

Nikita Glukhov
jsonb_object_agg(), конечно, намного удобнее на ст...

А про парсинг кстати не факт, но питон не знаю. А так то осталось jsonb_populate_record with sub query и pivot в кармане 🤦‍♀️

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

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

30500 за редактор? )
Владимир
47
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
вы делали что-то подобное и как? может есть либы готовые? увидел картинку нокода, где всё линиями соединено и стало интересно попробовать то же в ddl на lua сделать. решил с ч...
Victor
8
Подскажите пожалуйста, как в CustomDrawCell(Sender: TcxCustomGridTableView; ACanvas: TcxCanvas; AViewInfo: TcxGridTableDataCellViewInfo; var ADone: Boolean); получить наз...
A Z
7
Ребят в СИ можно реализовать ООП?
Николай
33
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
1
Он в одиночку это дело запилил или была какая-то команда?
Aquinary
12
~ 2m21s  nix shell github:nixos/nixpkgs#stack ~  stack ghc -- --version error: … while calling the 'derivationStrict' builtin at /builtin/derivation.nix:...
Rebuild your mind.
6
Всем привет, нужна как никогда, нужна помощь с IO в загрузчике. Пишу в code16 после установки сегментных регистров, пишу вывод символа. Пробовал 2 варианта: # 1 mov $0x0E, %a...
Shadow Akira
14
Карта сайта