Гость
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Оптимальный JOIN запрос / 17 сообщений из 17, страница 1 из 1
20.06.2018, 00:43
    #39662750
Aleksey K
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
Задача такая. На сервер поступают данные типа:
productId

userId

time

group1 colums list

group2 colums list

Колонки группы 1 меняются редко, поэтому возникла идея разбить данные на 2 таблицы и в первую добавлять записи только тогда, когда они меняются. Во вторую таблицу идут статистические данные, которые меняются и вставляются при каждом поступлении данных:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
table1                                      table2      
           
productId|userId|time |columns1...|         productId|userId|time |columns2...|
---------+------+-----+-----------+         ---------+------+-----+-----------+
product1 | id1  | 1   | some data |         product1 | id1  | 1   | some data |
         |      |     |           |         product1 | id1  | 2   | some data |
         |      |     |           |         product1 | id1  | 3   | some data |
product1 | id1  | 4   | some data |         product1 | id1  | 4   | some data |
         |      |     |           |         product1 | id1  | 5   | some data |
         |      |     |           |         product1 | id1  | 6   | some data |
         |      |     |           |         product1 | id1  | 7   | some data |
product1 | id1  | 8   | some data |         product1 | id1  | 8   | some data |
product1 | id1  | 9   | some data |         product1 | id1  | 9   | some data |


Нужно создать запрос или лучше представление (view), которое даст возможность рассматривать 2 таблицы как одну целую, типа:

Код: plsql
1.
2.
3.
4.
5.
SELECT table2.time, * -- список колонок 1 и 2 таблиц
FROM table1
JOIN table2
ON table1.productId = table2.productId AND table1.userId = table2.userId AND
   table1.time <= table2.time AND table1.time > ... 


Нужно продолжить условие JOIN, чтобы в результате строки, где


table1.time = 1 соединились со строками table2.time = 1,2,3

table1.time = 4 соединились со строками table2.time = 4,5,6,7

table1.time = 8 соединились со строками table2.time = 8

table1.time = 9 соединились со строками table2.time = 9

и т.п. Как это можно оптимальнее написать? Благодарю!

--
С уважением,
Алексей.
...
Рейтинг: 0 / 0
20.06.2018, 02:19
    #39662763
982183
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
table1.time <= table2.time - совершенно лишнее

(table1.time = table2.time) or (table1.time = 4 and inlist(table2.time,4,5,6,7))
...
Рейтинг: 0 / 0
20.06.2018, 02:22
    #39662764
982183
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
сорри

(table1.time = table2.time) or (table1.time = 4 and (table2.time IN(4,5,6,7)))
...
Рейтинг: 0 / 0
20.06.2018, 02:38
    #39662765
Aleksey K
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
982183, это смешно. Данные приведены для примера, я не знаю какие они будут и какое будет время.

Если условие будет table1.time <= table2.time, то строки table2.time = 4..7 соединятся с table2.time = 1 и 4, А нужно только с 4-й. Поэтому условие нужно ограничить как-то:

Код: sql
1.
table1.time <= table2.time AND table1.time > ...


чтобы 1-я строка не включалась. Соответственно, для 8-й строки из 2 таблицы нужно отфильтровать 1-ю и 4-ю из 1-й. Для 9-й строки из 2 таблицы нужно отфильтровать 1-ю, 4-ю и 8-ю из 1-й и смержить только с 9-й. Все строки из 2-й таблицы больше 9-й нужно смержить только с 9-й строкой из 1-й таблицы.
...
Рейтинг: 0 / 0
20.06.2018, 02:45
    #39662766
Aleksey K
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
Правда можно тупо сделать: добавить во 2-ю таблицу колонку table1_time и при вставке записей заполнять её для JOIN-a значением:
Код: sql
1.
SELECT max(time) FROM table1 WHERE productId = product_inserted_value AND userId = inserted_uuid


Но хочется сделать покрасивше с JOIN-ом.
...
Рейтинг: 0 / 0
20.06.2018, 03:01
    #39662768
982183
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
Ну так задачу ставить надо правильно.
...
Рейтинг: 0 / 0
20.06.2018, 03:31
    #39662770
982183
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
С ходу могу предложить завести таблицу связей time1, time2

time1 = max(table1.time) with table1.time <= table2.time
...
Рейтинг: 0 / 0
20.06.2018, 05:41
    #39662782
982183
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
или применить CROSS APPLY
С ним будет "оптимальней"
...
Рейтинг: 0 / 0
20.06.2018, 05:46
    #39662783
982183
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
Схематично так:

SELECT table2.time, table1.*
FROM table2
CROSS APPLY
(SELECT max(table1.time) FROM table1 WHERE table1.time <= table2.time )
...
Рейтинг: 0 / 0
20.06.2018, 06:12
    #39662786
Щукина Анна
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
Aleksey K,

при помощи LEAD получать в первой таблице следующее за текущим время, джойн делать between-у
...
Рейтинг: 0 / 0
20.06.2018, 06:44
    #39662793
Щукина Анна
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
Щукина АннаAleksey K,

при помощи LEAD получать в первой таблице следующее за текущим время, джойн делать between-уСхематично как-то так:
<=== Кликни тут - оно откроется...
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
with
  table1 (productId, userId, time, columns1) as
    (
	  select *
	    from (
		        values
				  ('product1', 'id1 ', 1, 'some data T1 1'),
				  ('product1', 'id1 ', 4, 'some data T1 4'),
				  ('product1', 'id1 ', 8, 'some data T1 8'),
				  ('product1', 'id1 ', 9, 'some data T1 9')
		     )v(a,b,c,d)
	)
, table2 (productId, userId, time, columns2) as 
    (
	  select *
	    from (
		        values
				  ('product1', 'id1 ',  1, 'some data T2 1'),
				  ('product1', 'id1 ',  2, 'some data T2 2'),
				  ('product1', 'id1 ',  3, 'some data T2 3'),
				  ('product1', 'id1 ',  4, 'some data T2 4'),
				  ('product1', 'id1 ',  5, 'some data T2 5'),
				  ('product1', 'id1 ',  6, 'some data T2 6'),
				  ('product1', 'id1 ',  7, 'some data T2 7'),
				  ('product1', 'id1 ',  8, 'some data T2 8'),
				  ('product1', 'id1 ',  9, 'some data T2 9')
		     )v(a,b,c,d)
	)

select t1.productId, t1.userId
     , t1.time_begin as time1, t2.time as time2
	 , t1.columns1, t2.columns2
  from (
          select t.productId, t.userId, t.time as time_begin, columns1
		       , lead(t.time - 1, 1, t.time) over(partition by t.productId, t.userId order by t.time) as time_end
		    from table1 t
       ) t1
  join table2 t2
    on t1.productId = t2.productId
   and t1.userId = t2.userId
   and t2.time between t1.time_begin and t1.time_end

...
Рейтинг: 0 / 0
20.06.2018, 12:15
    #39662961
vsl
vsl
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
Aleksey K,

Не рассматривали идею просто хранить в table2 ссылку на запись из table1, актуальную на момент сохранения? join в этом случае будет элементарным.
...
Рейтинг: 0 / 0
20.06.2018, 12:20
    #39662964
Aleksey K
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
...
Рейтинг: 0 / 0
20.06.2018, 16:28
    #39663165
qwwq
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
Aleksey K,

если для мелких выборок, в кач-ве заместителя полноджойна с оконными (щукина)
такое вью :
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
SELECT table2.time, * 
FROM table2 t2
,lateral (select * from table1 t11
	left join lateral (select time as time12 from table1 t12
			where t12.time > t11.time 
				and t12.productId =t11.productId
				and t12.userId =t11.userId
			order by t12.time limit 1
			) t12
	where 	t11.productId = t2.productId
		AND t11.userId = t2.userId
		AND t11.time <= t2.time AND (time12 > t2.time or time12 is null)
	order by t11.time desc limit 1 --опционально
	) t1


не вычитывал,

для больших видимо оконное.

думается дешевле апдейтить тебл1 в момент прихода отсечки .
...
Рейтинг: 0 / 0
20.06.2018, 16:55
    #39663179
Aleksey K
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
qwwqдумается дешевле апдейтить тебл1 в момент прихода отсечки .
Выборки потом будут крупные. Уже добавил колонку во 2-ю таблицу - так и буду делать - проще всего. Спасибо! Внешний ключ на 3 колонки добавил.
...
Рейтинг: 0 / 0
21.06.2018, 13:59
    #39663640
qwwq
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
Aleksey Kqwwqдумается дешевле апдейтить тебл1 в момент прихода отсечки .
Выборки потом будут крупные. Уже добавил колонку во 2-ю таблицу - так и буду делать - проще всего. Спасибо! Внешний ключ на 3 колонки добавил.

для хешджойна фк не нужен и индекс (на большой таблице) скорее вреден. если она реально большая.
добавьте поле в 1-ю (короткую таблу) и попробуйте индекс на ренджи. (range от двух таймов)
если разница мощностей порядки -- д.б. не хуже.

хотя и так неплохо.


а если основной поиск идет по неуказанным полям 1--й -- ваше решение скорее верное, чем нет.
...
Рейтинг: 0 / 0
21.06.2018, 15:33
    #39663674
Aleksey K
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимальный JOIN запрос
qwwq, да, дата майнинг потом будет по всем полям искать.
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Оптимальный JOIN запрос / 17 сообщений из 17, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]