powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Оптимальный JOIN запрос
17 сообщений из 17, страница 1 из 1
Оптимальный JOIN запрос
    #39662750
Фотография Aleksey K
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Задача такая. На сервер поступают данные типа:
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
Оптимальный JOIN запрос
    #39662763
982183
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
table1.time <= table2.time - совершенно лишнее

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

(table1.time = table2.time) or (table1.time = 4 and (table2.time IN(4,5,6,7)))
...
Рейтинг: 0 / 0
Оптимальный JOIN запрос
    #39662765
Фотография Aleksey K
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Оптимальный JOIN запрос
    #39662766
Фотография Aleksey K
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Правда можно тупо сделать: добавить во 2-ю таблицу колонку table1_time и при вставке записей заполнять её для JOIN-a значением:
Код: sql
1.
SELECT max(time) FROM table1 WHERE productId = product_inserted_value AND userId = inserted_uuid


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

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

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

при помощи LEAD получать в первой таблице следующее за текущим время, джойн делать between-у
...
Рейтинг: 0 / 0
Оптимальный JOIN запрос
    #39662793
Фотография Щукина Анна
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Щукина Анна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
Оптимальный JOIN запрос
    #39662961
vsl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
vsl
Гость
Aleksey K,

Не рассматривали идею просто хранить в table2 ссылку на запись из table1, актуальную на момент сохранения? join в этом случае будет элементарным.
...
Рейтинг: 0 / 0
Оптимальный JOIN запрос
    #39662964
Фотография Aleksey K
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Оптимальный JOIN запрос
    #39663165
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Оптимальный JOIN запрос
    #39663179
Фотография Aleksey K
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwqдумается дешевле апдейтить тебл1 в момент прихода отсечки .
Выборки потом будут крупные. Уже добавил колонку во 2-ю таблицу - так и буду делать - проще всего. Спасибо! Внешний ключ на 3 колонки добавил.
...
Рейтинг: 0 / 0
Оптимальный JOIN запрос
    #39663640
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksey Kqwwqдумается дешевле апдейтить тебл1 в момент прихода отсечки .
Выборки потом будут крупные. Уже добавил колонку во 2-ю таблицу - так и буду делать - проще всего. Спасибо! Внешний ключ на 3 колонки добавил.

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

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


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


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