Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Выборка из двух таблиц с группировкой и агрегатными функциями / 22 сообщений из 22, страница 1 из 1
17.11.2017, 10:26
    #39554893
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
Добрый день!

Есть 2 таблицы: A и B
Таблица А имеет следующие колонки: id, parent, child
Таблица B: id, a_id, update_date

Нужно выбрать 3 последних (по id) записи для нужного нам parent , при этом еще и maх(update_date) для них из таблицы B.

Вот что получилось:

SELECT
(SELECT id FROM a WHERE id = b.a_id) AS id,
(SELECT child FROM a WHERE id = b.a_id) AS child,
max(update_date) AS update_date
FROM b
WHERE a_id IN (
SELECT max(id)
FROM a
WHERE parent = 'test'
GROUP BY child
)
GROUP BY id_a
ORDER BY update_date DESC
LIMIT 3;

Но, запрос получился очень нагруженным - порядка 0.2-0.5с (думаю из-за IN ). Есть смутные сомнения, что можно сделать проще (может через UNION), но не сображу как. Может будут какие-то идеи, как упростить этот изврат)
Спасибо!
...
Рейтинг: 0 / 0
17.11.2017, 10:44
    #39554899
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobee,

специально для таких как ты - "торопыжек-писателей-нечитателей" сделали Ф.А.К. и закрепили его в ТОП-топиках....
...
Рейтинг: 0 / 0
17.11.2017, 10:46
    #39554901
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobee,

а также такой Ф.А.К.
...
Рейтинг: 0 / 0
17.11.2017, 10:47
    #39554904
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobee,

З.Ы.
в общем, основной посыл ты, надеюсь,понял? для начала прочитай все топовые топики в факами. если не найдешь ответы на свои вопросы - возвращайся в форум и спрашивай....
...
Рейтинг: 0 / 0
19.11.2017, 17:11
    #39555739
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
Добрый Э - Эхagrobee,

З.Ы.
в общем, основной посыл ты, надеюсь,понял? для начала прочитай все топовые топики в факами. если не найдешь ответы на свои вопросы - возвращайся в форум и спрашивай....

Я так понимаю, вы предлагаете реализовать запрос с использованием переменных? Ранее использовал переменные только в хранимых процедурах, опыта использования в запросах нет. Прочитал топики, нашел даже на хабрахабре тему "Оптимизация запросов MySQL с использованием пользовательских переменных", изучил ее, но с реализацией применительно к моему вопросу по-прежнему сложности.
...
Рейтинг: 0 / 0
20.11.2017, 23:46
    #39556462
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
Вот что получилось у меня

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
select zz.id, child, max(`update_date`) update_date from b right join 
(select * from
(SELECT a.*, if(@child=a.child, @rownum:=@rownum+1, @rownum:=1+least(0,@child:=a.child)) AS rown
FROM a, (select @rownum:=1, @child:='_') zz WHERE `parent` = 'test' order by a.`id` desc
) yy
where rown < 2) 
zz on b.a_id=a.id
group by child
order by update_date desc limit 3



У меня таблицы с колонками немного другие, поэтому мог ошибиться при написании варианта, что выше.
Правда так и не уверен в правильности логики запроса, хотя скорость реально в 5-10 раз и выросла.
...
Рейтинг: 0 / 0
21.11.2017, 09:27
    #39556571
javajdbc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobee,

вы нагородили огород...

авторНужно выбрать 3 последних (по id) записи для нужного нам parent, при этом еще и maх(update_date) для них из таблицы B.

...ваша выборка берет 3 последних по дате_апдате...
что надо -- 3 последних по ИД или по дате_апдате?
...
Рейтинг: 0 / 0
21.11.2017, 09:43
    #39556584
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
Нужно взять 3 последних записи из таблицы А (определяем по id) и последнюю запись для каждой из них из таблицы B (определяем по update_date)
...
Рейтинг: 0 / 0
21.11.2017, 10:03
    #39556599
javajdbc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobeeНужно взять 3 последних записи из таблицы А (определяем по id) и последнюю запись для каждой из них из таблицы B (определяем по update_date)

если нужна вся запись из Б (а не только время)
то примерно так:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
select *
from 
       (
        select 
        z.*,
        (select max(date_up) from B where B.a_id = A.id) md
        from
             (
             select *
             from A
             WHERE parent = 'test'
             order by id desc
             limit 3
             ) z
        ) z2
join B AS B2 
ON B2.a_id = z2.id
AND B2.date_up = z2.md



скорость может быть доли милисекунды по индексам.
предпологается что две последниее строчки дают уникальную связку.
...
Рейтинг: 0 / 0
21.11.2017, 21:18
    #39557167
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
Ругается на то, что в
Код: sql
1.
(select max(date_up) from B where B.a_id = A.id) md


не определена колонка A.id
...
Рейтинг: 0 / 0
21.11.2017, 22:18
    #39557188
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
Полагаю, там z.id имелось ввиду.
Наверное то, что надо! Спасибо!
...
Рейтинг: 0 / 0
21.11.2017, 22:49
    #39557201
javajdbc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobeeПолагаю, там z.id имелось ввиду.
Наверное то, что надо! Спасибо!

....да, конечно з.ид...

скорость должна быть меньше милисекунды...
если больше, надо (можно, если нужно) подгонять индексы...
...
Рейтинг: 0 / 0
21.11.2017, 23:50
    #39557220
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
javajdbc,

Да, скорость хорошая. Но только результат не тот :) Показывает три строчки с одинаковыми child, а должны быть все разные. Видимо, я неправильно описал задачу.
...
Рейтинг: 0 / 0
21.11.2017, 23:53
    #39557222
javajdbc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobeejavajdbc,

Да, скорость хорошая. Но только результат не тот :) Показывает три строчки с одинаковыми child, а должны быть все разные. Видимо, я неправильно описал задачу.


...самое простое -- дайте набор тестовых репресентативных данных
и ожидаемый результат....
...
Рейтинг: 0 / 0
22.11.2017, 00:30
    #39557230
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
Эхх, щас как опишу задачу в художественной форме! :)

Вот слушайте.
Поле боя. Каждый боец сам за себя. У каждого бойца есть автомат. Из автомата можно стрелять только очередью. Очередь может состоять минимум из одной пули, максимум теоретически не ограничен. Выпускать очередь можно только в других бойцов на поле, и больше никуда. Одной очередью поразить более одной цели нельзя, но цели можно менять, начиная новую очередь. Перед тем, как давать очередь, нужно обязательно выбрать цель — другого конкретного бойца. И вот на поле боя бойцы стреляют друг в друга очередями. Месиво, короче говоря :)

В базе данных это месиво описывается у нас следующим образом:
1. Таблица q — "Очереди"
1.1. Поле id — идентификатор очереди (автоинкремент)
1.2. Поле shooter — "Стрелок" — боец, выпускающий очередь пуль
1.3. Поле target — "Цель" — боец, в которого стрелок выпускает очередь пуль

2. Таблица b — "Пули"
2.1. Поле id — идентификатор пули (автоинкремент)
2.2. Поле q_id — идентификатор очереди, из которой эта пуля
2.3. Поле time — время вылета пули
2.4. Поле damage — урон, нанесённый цели этой пулей


Задача:
По этим двум таблицам составить запрос, выясняющий:
1) В каких трёх последних бойцов (разных бойцов) стрелял заданный стрелок.
2) При этом для каждого из трёх бойцов узнать:
а) время последней вылетевшей в него пули,
б) урон, который нанесла эта пуля,
в) из какой очереди (id) была эта пуля

То есть, таблица-результат должна состоять из трёх строк и следующих четырёх столбцов:
1) r_target
2) r_time
3) r_damage
4) r_q_id

Строки таблицы должны располагаться в обратном порядке, то есть, начиная с последнего бойца, в которого он стрелял.
Идентификатор пули не участвует в запросе, от него ничего не зависит, его можно отбросить.

Такая вот задачка.
На самом деле у меня тут нет никаких бойцов и никакого месива, просто так понятнее должно быть :)


Решение, в общем-то, уже есть, только скорость запроса не устраивает.
20-40 миллисекунд, а хотелось бы 2-4 :)
Вот оно, это решение, работающее правильно, но его нужно усовершенствовать по скорости:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SELECT * FROM(
	SELECT id, if(@t<>target, @t:=target, NULL) target, time, damage FROM(
		SELECT q.id id, target, time, damage
		FROM q, b, (SELECT @t:='') init
		WHERE shooter = 'John' AND q.id = q_id
		ORDER BY target, time DESC
		) x
	) y
WHERE target IS NOT NULL
ORDER BY time DESC
LIMIT 3;
...
Рейтинг: 0 / 0
22.11.2017, 01:33
    #39557241
javajdbc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobee,

...если (если!) последняя по времени пуля в таргет
однозначно приходит из последней по ИД очереди в таргет, то
обрезку ЛИМИТ 3 последние поули можно упростить
на две независимые задачи:
1. поиск 3-х последний очередей по последним 3-м таргетам
2. поиск последних пуль.

вы имеете 20 мс потому что сначала идет джоин а потом обрезка по 3-м последним

если условие вверху выполняется, то уберите джоин внутри
и найдите 3 последние очереди ТОЛЬКО из таблицы КУ
апотом повторите для последних пуль в уже выбраных очередях
(которых всего 3)

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

------------------------------------------

кроме переменых, задачу можно решить и другими способами как во втором ФАК-е.
будет ли ето быстрее -- вопрос для проверки

-----------------------------------------

по любому имеет смысл сделать ЕКСПЛЕЙН и выставить
сюда на обсуждение. у вас и связки и филтры и сортировка..
есть потенциал для оптимизации

-----------------------------------------------

если б вы смогли денормализовать (специально излишне добавить)
колонки ТРАГЕТ и СОУРСЕ в таблицу пуль, то все было в шоколаде...

-------------------------------------

...а еще бы колонку с флажком ДА/НЕТ "последняя пуля" --
...да правильный составной индекс -- шоколад с орешками!
...
Рейтинг: 0 / 0
22.11.2017, 02:09
    #39557248
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
javajdbc...если (если!) последняя по времени пуля в таргет
однозначно приходит из последней по ИД очереди в таргет, то
обрезку ЛИМИТ 3 последние поули можно упростить
на две независимые задачи:
1. поиск 3-х последний очередей по последним 3-м таргетам
2. поиск последних пуль.

вы имеете 20 мс потому что сначала идет джоин а потом обрезка по 3-м последним

если условие вверху выполняется, то уберите джоин внутри
и найдите 3 последние очереди ТОЛЬКО из таблицы КУ
апотом повторите для последних пуль в уже выбраных очередях
(которых всего 3)

если у вас много очередей и пуль, то такой двойной подход может
(но не обязательно) ускорить запрос.
Забыл, забыл один момент описать. Автомата, автомата-то ТРИ! :) То есть, теоретически, один автомат может стрелять одну очередь от самого начала игры и до самого конца. В общем, не получится так разделить задачу на две.

javajdbcкроме переменых, задачу можно решить и другими способами как во втором ФАК-е.
будет ли ето быстрее -- вопрос для проверки
Угу, почитаю, спасибо.

javajdbcпо любому имеет смысл сделать ЕКСПЛЕЙН и выставить
сюда на обсуждение. у вас и связки и филтры и сортировка..
есть потенциал для оптимизации
Сделаю.

javajdbcесли б вы смогли денормализовать (специально излишне добавить)
колонки ТРАГЕТ и СОУРСЕ в таблицу пуль, то все было в шоколаде...
Воооот! Это то, что я предлагаю руководителю, но он никак не соглашается пока добавлять ещё колонки :) Буду работать над этим :)

javajdbc...а еще бы колонку с флажком ДА/НЕТ "последняя пуля" --
...да правильный составной индекс -- шоколад с орешками!
Так, ну составной индекс это после эксплейна, я так понимаю. А флажок "последняя пуля", получается, надо снимать с предпоследней пули, когда вылетает новая последняя, так?
...
Рейтинг: 0 / 0
22.11.2017, 11:19
    #39557367
javajdbc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobee,


agrobeeЗабыл, забыл один момент описать. Автомата, автомата-то ТРИ! :) То есть, теоретически, один автомат может стрелять одну очередь от самого начала игры и до самого конца. В общем, не получится так разделить задачу на две.

...ну ок, тогда да, сначала джоин а потом выборка последней записи

agrobeeВоооот! Это то, что я предлагаю руководителю, но он никак не соглашается пока добавлять ещё колонки :) Буду работать над этим :)

...возможно, ето будет единственый способ ускорится с 20 до 2 мс...
(если индексы уже оптимальные)


agrobeeТак, ну составной индекс это после эксплейна, я так понимаю. А флажок "последняя пуля", получается, надо снимать с предпоследней пули, когда вылетает новая последняя, так?

...да, опятже ето зависит от конкретного способа и интенсивности инсертов.
если пули вставляются одновремено группой то
легко пометить последнюю пулю один раз....если пули
вставляются отдельно, то придется ставить флажок и
убирать флажок из предыдушей пули...

...т.е. медленее/сложнее на вставке >> быстрее / легче на чтении...
надо ли делать так или нет -- покажет только експерименты....
...
Рейтинг: 0 / 0
22.11.2017, 13:36
    #39557482
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
EXPLAIN
SELECT * FROM(
	SELECT id, if(@t<>target, @t:=target, NULL) target, time, damage FROM(
		SELECT q.id id, target, time, damage
		FROM q, b, (SELECT @t:='') init
		WHERE shooter = 'John' AND q.id = q_id
		ORDER BY target, time DESC
		) x
	) y
WHERE target IS NOT NULL
ORDER BY time DESC
LIMIT 3;



Вот эксплейн по запросу:

Код: sql
1.
2.
3.
4.
5.
6.
7.
id	select_type	table		partitions	type	possible_keys		key		key_len	ref		rows	filtered	Extra
1	PRIMARY		<derived2>			ALL									2756	90.00		Using where; Using filesort
2	DERIVED		<derived3>			ALL									2756	100.00	
3	DERIVED		<derived4>			system									1	100.00		Using temporary; Using filesort
3	DERIVED		q				ref	PRIMARY,shooter_index	shooter_index	402	const		1552	100.00	
3	DERIVED		b				ref	q_id_index		q_id_index	8	db.q.id		1	100.00	
4	DERIVED																		No tables used



Читаю ФАКи...
...
Рейтинг: 0 / 0
22.11.2017, 14:41
    #39557535
javajdbc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobee,

...по експлейну вроде ОК, может кто-нибудь другой
увидит улучшения....
...
Рейтинг: 0 / 0
22.11.2017, 14:59
    #39557559
agrobee
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
Вот вариант с дополнительными полями, о котором я изначально думал.

Если в таблицу "q" добавить два дополнительных поля:
1) галочку "последняя очередь в данную цель" - "last_target_q",
2) ссылку на последнюю пулю в данной очереди - "last_b_id",
то запрос можно сделать такой:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT x.*, time, damage
FROM(
	SELECT q.id, target
	FROM q
	WHERE shooter = 'John' AND last_target_q = 1
	ORDER BY last_b_id DESC
	LIMIT 3
	) x, b
WHERE last_b_id = b.id;



Я думаю, такой запрос будет работать ооочень быстро. Как думаете?
А чтобы галочка last_target_q корректно обновлялась, перед тем, как начинать новую очередь, нужно выполнять следующее:

Код: sql
1.
2.
3.
UPDATE q
SET last_target_q = 0
WHERE shooter = 'John' AND target = 'Tom' AND last_target_q = 1;



Тоже довольно быстро будет получаться, мне кажется.
А после вылета новой пули, сразу отмечать её в очереди:

Код: sql
1.
2.
3.
UPDATE q
SET last_b_id = last_insert_id()
WHERE id = 'id текущей очереди';


В условиях, когда выборка трёх последних целей делается чаще, чем даже выпуск пуль, такой подход вполне оправдан, мне кажется. Как думаете?
...
Рейтинг: 0 / 0
22.11.2017, 16:22
    #39557654
javajdbc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выборка из двух таблиц с группировкой и агрегатными функциями
agrobee,

да, ето тоже "контролируемая" денормализация.
в данном случае -- апстрим нормализация -- от
чайлд на перента. то что скорость чтения увеличится --
однозначно -- вопрос насколько усложнистся/замедлица запись...

точнее -- запись точно замедлица -- вопрос будет ли ето допустимо...
...
Рейтинг: 0 / 0
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Выборка из двух таблиц с группировкой и агрегатными функциями / 22 сообщений из 22, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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