
Denis
30.04.2017
13:29:46
посмотрите, вот эта штука вам не поможет?

Mikhail
30.04.2017
13:30:36
Сейчас почитаю, спасибо!
Тут явно видна проблема, что ищутся 10 ближайших. А мне строго нужно 10 выше значения и 10 ниже

Denis
30.04.2017
13:38:03
я боюсь, что для реализации именно 10 сверху и 10 снизу, вам придется немного погрузиться в си и поправить функцию distance в коде btree_gist

Google

Denis
30.04.2017
13:38:04
https://postgrespro.ru/docs/postgrespro/9.5/gist-extensibility.html

Mikhail
30.04.2017
13:42:37
Думаю тогда проще в коде получить всю таблицу и самому искать ближайшие значения

Denis
30.04.2017
13:44:22
вряд ли, если таблица реально большая, то получать ее через sequence scan - боль и деградация системы. ну и вертеть в памяти приложения - тоже боль

Mikhail
30.04.2017
13:44:44
так да, но можно же не всю таблицу загрузить в память
а как раз по 20 значений

Denis
30.04.2017
13:45:46
ну так у вас же в таблице строки лежат как бог на душу положит
вам придется сканировать почти все

Mikhail
30.04.2017
13:46:25
Так я сделаю запрос с упорядочиванием и его буду частями вытаскивать в приложении

Denis
30.04.2017
13:46:42
проще тогда уж выбрать из гист индекса ближайшую 1000 строк и их уже сравнивать

Mikhail
30.04.2017
13:47:47
Почему проще?
Я буду просто последовательно вытаскивать строки и анализировать их

Anton [Mgn, az09@osm]
30.04.2017
13:48:53
Можно ламерское предложение? Разбить задачу на две - поиск 10 сверху, и поиск 10 снизу.

Mikhail
30.04.2017
13:48:55
что мне даст GiST индекс по 1000 строк?

Google

Denis
30.04.2017
13:50:35
что мне даст GiST индекс по 1000 строк?
вы из хипа вытащите только 1000 кортежей, четко заня, откуда их брать. в вашем же варианте вы будете последовательно сканировать таблицу, пока не найдете 20 вариантов. и при плохом везении, вы вытащите гораздо больше кортежей
а просто последовательно вытаскивая строки и анализируя - это варианто еще хуже, чем подзапрос с оконной функцией, нумерующей строки. так как вы его еще по сети на сервер приложения будете гонять

sne18
30.04.2017
14:03:23
Ребят, всем привет. Где можно найти стажера со знанием SQL в Московский офис?
Посоветуйте плиз
Нужно два чела - один опытный воторой стажёр

Fike
30.04.2017
14:17:14

Denis
30.04.2017
14:17:45

Fike
30.04.2017
14:17:52
Тупо два запроса и отсутствие лишнего геморроя

Denis
30.04.2017
14:18:36

Mikhail
30.04.2017
14:21:55
Тупо два запроса и отсутствие лишнего геморроя
Да нет, я еще раз перечитал btree_gist, он все равно дает данные по определенному столбцу. У меня же ситуация, нужно найти строку по userid, а потом уже ближайшие к ней 10 выше и 10 ниже строк

Denis
30.04.2017
14:23:34

Mikhail
30.04.2017
14:24:04
так это с подзапросами
к тому же я знаю userId, и не знаю amount
ааа

Denis
30.04.2017
14:25:11
Вам нужно ближайшие amount?

Mikhail
30.04.2017
14:25:18
кажется я начинаю догонять

Denis
30.04.2017
14:25:33
Ну тогда все наоборот)

Mikhail
30.04.2017
14:28:02
select userid, amount from test_table where amount <= (select amount from test_table where userId = myId) and userId = myId limit 10;
но это все равно с подзапросом

Google

Mikhail
30.04.2017
14:28:31
мне кажется с номерами строк и подзапросом даже быстрее будет
там вообще никаких индексов не нужно

Denis
30.04.2017
14:29:39
Вы все не правильно понимаете, правда((

Mikhail
30.04.2017
14:31:44

Fike
30.04.2017
14:32:38
я не очень подробно читал исходную задачу, но:
- делаете запрос, который получает то, что вам нужно
- отрезаете все "выше" нужной строки с помощью where
- сортируете по нужному значению
и получаете таким образом половину необходимой выборки, вторую получаете перевернув запрос и осртируя уже в обратную сторону

Mikhail
30.04.2017
14:35:44
Но тут будут проблемы, если несколько юзеров имеют одинаковый amount, т.к. amount не уникален

Denis
30.04.2017
14:40:55

Mikhail
30.04.2017
14:43:09
я так понимаю нету никаких правил, какую именно строку он вернет при каждом запросе с одинаковым amount

Denis
30.04.2017
14:44:14
Я запутался)) вам нужно 10 меньше включая тако же количество, или без них?

Mikhail
30.04.2017
14:45:20
И чем все таки решения с индексом лучше вот этого
create table test(a integer, b text);
insert into test (a,b) select generate_series(1,30), '';
update test set b='mark' where a=13;
with numbered_test as (
select row_number() over(order by a), a, b from test
)
select a,b from numbered_test where row_number between
(select row_number from numbered_test where b='mark') - 10
and
(select row_number from numbered_test where b='mark') + 10;
Если в обоих случаях будут вложенные селекты


Denis
30.04.2017
14:51:13
Смотрите, вложенные селекты - это не страшно. Страшно, когда мы много данных вытаскиваем из большой таблицы. Разница в следующем - в случае с оконной функцией мы поднимаем все строки с диска в общие буферы из таблицы, каждую из них нумеруем и из кучи данных в памяти выбираем лишь 10 штук. В случае с индексом мы находим в файле индекса 10 строк (на самом деле чуть больше, так как индекс не версионирует данные и их нужно перепроверять) и только 10 поднимаем с диска. Это обычно в сотни или тысячи раз быстрее

Mikhail
30.04.2017
14:51:53
А, понял, да
Т.е. получается оконные функции в любом случае зло
Если они нумерются в запросе

Google

Mikhail
30.04.2017
14:53:01
и выборка большая
Ну тогда получается остается решить, как точно относительно строки с помощью индексов отсчитать 10 строк сверху и снизу

Denis
30.04.2017
14:54:03
Ну, они зло в исполнении постгреса. Сколь я знаю, он не умеет для них все ещё конвейерную обработку - то есть вначале он все должен построить, а потом уже фильтровать. Вроде оракл и микрософт в этом плане круче, но я не готов поручиться)


Mikhail
30.04.2017
15:09:42
Я кажется понял. Можно в union добавить еще когда дистанция равна нулю. В этом случае можем получить чуть больше чем 10 записей сверху и/или снизу
select userid from test_table where amount <-> (select amount from test_table where userId = myId) and amount <= (select amount from test_table where userId = myId) limit 11
union
select userid from test_table where amount <-> (select amount from test_table where userId = myId) and amount >= (select amount from test_table where userId = myId) limit 11
union
select userid from test_table where amount <-> (select amount from test_table where userId = myId) = 0 limit 21
А лишние строки можно обрезать в приложении уже

Denis
30.04.2017
15:13:43
А зачем последнее условие, я все никак не пойму? Эти точки же и так должны попасть в первые два

Admin
ERROR: S client not available

Mikhail
30.04.2017
15:15:03
Может не войти. Предположим у нас 10 одинаковых значений amount. Пусть первый запрос возвратит все которые выше первой строки, второй все которые ниже 10-ой. Тогда последний добавит все одинаковые строки

Denis
30.04.2017
15:15:38

Mikhail
30.04.2017
15:16:14
Потому на уровне приложения уже находим строку с заданным userId и относительно неё отсчитываем 10 сверху и 10 снизу
А как в этом случае union будет работать? Они реально в один запрос объединит?

Denis
30.04.2017
15:17:35

Mikhail
30.04.2017
15:18:21
А кто-нибудь в курсе, группирование запросов в libpg вошло в итоге или нет в 9.6.0 релизе?
Вот этот патч
https://www.postgresql.org/message-id/flat/CAMsr+YFUjJytRyV4J-16bEoiZyH=4nj+sQ7JP9ajwz=B4dMMZw@mail.gmail.com#CAMsr+YFUjJytRyV4J-16bEoiZyH=4nj+sQ7JP9ajwz=B4dMMZw@mail.gmail.com
Я просто не очень понимаю как в итоге отследить статус этого патча, вошел или нет

Google

Mikhail
30.04.2017
15:40:26
Denis Теперь другой вопрос. Допустим та таблица, а которой я говорил - это вьюха. Есть ли смысл заюзать materialized view чтобы можно было заюзать индекс btree_gist учитывая что исходные данные будут обновлятся часто и само представление будет большим? Я думаю делать refresh к это вьюхе перед тем как запросить данные через индекс btree_gist
Стоит ли игра свеч вообщем, или в этом случае можно просто использовать row_number, т.к. производительность будет и так низкая
А OFFSET так же работает как и ROW_NUMBER, или ему не требуется перенумеровывать?
можно еще так
select userId
from test_table
offset (select row_number - 11 from test_table where userId = myId)
limit 21


Denis
30.04.2017
22:23:50
А OFFSET так же работает как и ROW_NUMBER, или ему не требуется перенумеровывать?
Оффсет - это страшная штука)) Ее можно использовать только при отладке, но не в промышленном коде. Проблема в том, что offset 1000000 на самом деле физически этот миллион строк считает с диска, но просто не покажет в результате запроса. И естественно, это будет медленно. Я помню, Маркус Винланд почти при каждом удобном случае кричит про опасность оффсета - http://use-the-index-luke.com/sql/partial-results/fetch-next-page


raksita
30.04.2017
22:34:24
В matview могут быть индексы. "CREATE INDEX constructs an index on the specified column(s) of the specified relation, which can be a table or a materialized view."
https://www.postgresql.org/docs/current/static/sql-createindex.html

Denis
30.04.2017
22:35:49

Сергей
30.04.2017
22:36:02
Да, могут

raksita
30.04.2017
22:36:02
В документации есть пример с GiST и file_fdw: https://www.postgresql.org/docs/current/static/rules-materializedviews.html

Сергей
30.04.2017
22:36:23
Матвью это ж обычная таблица с данными
Реальными, не вычисленными

Denis
30.04.2017
22:37:00
Ну да, это понятно. Просто я думал, это не реализовано


Mikhail
30.04.2017
22:41:47
CREATE TABLE deals(id SERIAL PRIMARY KEY, user_id INTEGER, time TIMESTAMP, amount MONEY)
вот изначальная таблица
нужно составить рейтинг юзеров. Юзер обладает наибольшим рейтингом если сумма его amount за последнюю неделю максимально
вот теперь нужно для некоторых юзеров найти 10 сверху и снизу ближайших соперников соответственно этому рейтингу
Как сделать без materialized view не использова numrow не очень пока представляю