SQL выборка из трех таблиц - подскажите

12
banshee(oleg)
На сайте с 12.08.2007
Offline
140
2644

Всем ку.

Я обычно работал с достаточно простыми sql-запросами в своих проектах, а тут попался орешек покрупнее - решил попросить помощи у вас :)

Итак,

имеется 3 таблицы - с партнерами, кликами и серчами

у кликов и серчей есть ид партнера pid

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

Если без серчей, то такая конструкция работает:

SELECT ud_feed_rwd_users.*, COUNT(DISTINCT ud_feed_clicks.id) AS clicks_count FROM ud_feed_rwd_users LEFT JOIN ud_feed_clicks ON ud_feed_rwd_users.id = ud_feed_clicks.pid GROUP BY ud_feed_rwd_users.id ORDER BY clicks_count DESC LIMIT 0, 10

С серчами я пробую такое, но что-то не так (возможно, что я просто косякнул с синтаксисом, а может, уже запутался серьезнее):

SELECT ud_feed_rwd_users.*, COUNT(DISTINCT ud_feed_clicks.id) AS clicks_count, COUNT(DISTINCT ud_feed_searches.id) AS searches_count FROM ud_feed_rwd_users LEFT JOIN ud_feed_clicks, ud_feed_searches ON ud_feed_rwd_users.id = ud_feed_clicks.pid, ud_feed_rwd_users.id = ud_feed_searches.pid GROUP BY ud_feed_rwd_users.id ORDER BY clicks_count DESC LIMIT 0, 10

--

Параллельно еще мини-вопрос терзает, имеет ли смысл тут использовать DISTINCT, ведь id в ud_feed_clicks и ud_feed_searches и так уникальный параметр и, может, правильнее и дешевле использовать COUNT(ud_feed_clicks.*)?

--

Я просто первый раз использую конструкцию LEFT JOIN .. ON и чувствую что уже немного подзапутался.

А Все, все! Я был невнимателен, сравнение с параметром третьей таблицы идет в еще одном LEFT JOIN, вот как правильно:

SELECT ud_feed_rwd_users.*, COUNT(DISTINCT ud_feed_clicks.id) AS clicks_count, COUNT(DISTINCT ud_feed_searches.id) AS searches_count FROM ud_feed_rwd_users LEFT JOIN ud_feed_clicks ON ud_feed_rwd_users.id = ud_feed_clicks.pid LEFT JOIN ud_feed_searches ON ud_feed_rwd_users.id = ud_feed_searches.pid GROUP BY ud_feed_rwd_users.id ORDER BY clicks_count DESC LIMIT 0, 10

Насчет DISTINCT по-прежнему не откажусь от совета.

AN
На сайте с 05.06.2004
Offline
243
#1

Если есть возможность, DISTINCT надо убрать.

Это очень "тяжелая" штука.

Размещу ваши баннеры на посещаемых сайтах. Места еще есть! Возможен безнал. (/ru/forum/324945) Нужны копирайтеры/рерайтеры - медики. Пишите в личку. (/ru/forum/676932)
[Удален]
#2
banshee(oleg):
Параллельно еще мини-вопрос терзает, имеет ли смысл тут использовать DISTINCT, ведь id в ud_feed_clicks и ud_feed_searches и так уникальный параметр и, может, правильнее и дешевле использовать COUNT(ud_feed_clicks.*)?

А что общего между Distinct и Count? Первое убирает повторяющиеся поля, второе их считает.

Вообще если я вас правильно понял то вам нужно такое


SELECT `partners`.`id` as `id`,
count (`clicks`.`id`) as `clickz`,
count (`searches`.`id`) as `searchez`
FROM `partners`,`clicks`,`searches`
WHERE `partners`.`id`=`clicks`.`pid`
AND `partners`.`id`=`searches`.`id`
GROUP BY `partners`.`id`
ORDER BY `clickz` DESC
LIMIT 0,10

ЗЫ. Научитесь нормально оформлять код запросов, я не могу прочитать когда все это слеплено в одну строку да еще и с такими именами полей

N
На сайте с 06.05.2007
Offline
419
#3

Непонятно какой смысл вы здесь вкладываете в distinct ?

вряд ли ud_feed_clicks.id и ud_feed_searches.id содержат неуникальные значения и, я думаю, mysql сам догадается не тупить, но все равно лучше disctinct убрать.

Кнопка вызова админа ()
banshee(oleg)
На сайте с 12.08.2007
Offline
140
#4

Да вот дело в том, что пример с distinct выдает правильные результаты (допустим, есть 1 партнер, 2 клика и 5 серчей) :

1 партнер / 2 клика / 5 серчей

а без дистинкта (вариант, предложенный neolord) выдает неверные результаты:

1 партнер / 10 кликов / 10 серчей

[Удален]
#5
netwind:

вряд ли ud_feed_clicks.id и ud_feed_searches.id содержат неуникальные значения
banshee(oleg):

а без дистинкта (вариант, предложенный neolord) выдает неверные результаты:
1 партнер / 10 кликов / 10 серчей

Видимо содержат. Тогда конечно вы от дистинкта никуда не уйдете. Но на самом деле не такое уж это тяжкое бремя, особенно по числовому индексу

banshee(oleg)
На сайте с 12.08.2007
Offline
140
#6

id во всех этих таблицах - PRIMARY KEY (т.е. уникален).

А насчет нагрузки - пробовал сейчас (плюс еще временные рамки только за сегодня) с таблицами по 10k записей - тормозит мощно (только что замерял - 13 секунд). Конечно этот расчет будет кешироваться раз в час, но и таблицы будут по миллиону.

[Удален]
#7

киньте побаловатся тестовые таблицы по 10к на мыльце? ya@phpdude.ru

N
На сайте с 06.05.2007
Offline
419
#8

banshee(oleg), без disctinct, похоже, никак. Но, так как ваши две группировки не связаны, и сортируете вы только по одной, вы можете завернуть сортировку внутрь подзапроса и выбрать данные второй группировки уже по индексу. при большом объеме данных должно получиться быстрее, так как вы пропускаете полную сортировку всех получившихся в объединении строк .

netwind добавил 24.02.2009 в 19:04

Как-то так. таблицы я приблизительно воссоздал.

select ud_feed_rwd_users.*,innertab.clicks_count as clicks_count,COUNT(ud_feed_searches.id) as searches_count
from (
select pid,count(ud_feed_clicks.id) as clicks_count
from ud_feed_clicks
group by pid
order by clicks_count desc limit 0,10 )
as innertab, ud_feed_rwd_users, ud_feed_searches
where
ud_feed_rwd_users.id=innertab.pid and ud_feed_rwd_users.id=ud_feed_searches.pid
group by ud_feed_rwd_users.id;

у меня тут query_cost вышел вообще 0 против 7.92 :) надо данных закидать генератором и проверить.

+----+-------------+-------------------+--------+---------------+---------+---------+-------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------------+--------+---------------+---------+---------+-------+------+---------------------------------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | |
| 1 | PRIMARY | ud_feed_rwd_users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
| 1 | PRIMARY | ud_feed_searches | ref | pid | pid | 5 | const | 4 | Using where |
| 2 | DERIVED | ud_feed_clicks | ALL | NULL | NULL | NULL | NULL | 2 | Using temporary; Using filesort |
+----+-------------+-------------------+--------+---------------+---------+---------+-------+------+---------------------------------+

от полного сканирования clicks это не избавляет. нужны или дополнительные таблички для агрегированных данных или ограничивать под дате.

banshee(oleg)
На сайте с 12.08.2007
Offline
140
#9

Да, я сейчас ехал домой и все думал об этом.. :) Пришел к примерно такой логике, что надо сделать выборку со всеми условиями из кликов, сгруппировав по pid, а потом уже из оставшихся двух таблиц брать данные для полученных всего-то десяти индексов. Это, я так понимаю, как раз то, что Вы (netwind) написали.. обязательно попробую сегодня. И замеряю производительность в паре вариантов.

bearman, к сожалению, эти таблицы на "live test" сервере содержат слишком приватное инфо, ;) Чтоб побаловаться можно и сгенерировать :)

[Удален]
#10

banshee(oleg), если приватно, то разбирайте сами. генерить чтобы помочь ВАМ, я не собираюсь :) есть другие дела.

12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий