Запрос выбора SQL с оптимизацией нескольких подзапросов - PullRequest
0 голосов
/ 27 мая 2019

У меня есть база данных MySql с такими таблицами:

PageviewEvents:
pageviewId | eventId | eventValue | eventTime

SessionPageviews:
id | sessionId | page 

PageviewEvents.pageviewId - это ссылка на SessionPageviews.id как внешний ключ.

Когда мне нужно выбрать некоторые данные по eventId, я использую этот запрос:

SELECT 
    sp.page as Page, count(*)
from PageviewEvents pe
left join SessionPageviews sp on sp.id = pe.pageviewId
where pe.eventId = 1
GROUP by sp.page
order BY 2 DESC

И получите таблицу, подобную этой:

page | count_of_event_1

Но теперь мне нужно выбрать больше данных:

page | count_of_event_1 | count_of_event_2 ... | count_of_event_N

Я начал с 2 событий и попытался сделать что-то вроде белого:

SELECT 
    sp.page as Page, 
    (SELECT count(*) from PageviewEvents pe1 left join SessionPageviews sp1 on sp1.id = pe1.pageviewId where pe1.eventId = 1 and sp1.page = sp.page) as count_of_event_1,
    (SELECT count(*) from PageviewEvents pe1 left join SessionPageviews sp1 on sp1.id = pe1.pageviewId where pe1.eventId = 2 and sp1.page = sp.page) as count_of_event_2 
from PageviewEvents pe
left join SessionPageviews sp on sp.id = pe.pageviewId
where pe.eventId = 1 OR pe.eventId = 2
GROUP by sp.page
order BY 2 DESC

Когда я запускаю этот запрос на удаленном сервере, он зависает.

Есть ли ошибки в моем запросе? Как это оптимизировать?

Ответы [ 2 ]

2 голосов
/ 27 мая 2019

Вы можете попробовать использовать условное агрегирование:

SELECT
    sp.page AS Page,
    COUNT(CASE WHEN pe.eventId = 1 THEN 1 END) AS count_of_event_1,
    COUNT(CASE WHEN pe.eventId = 2 THEN 1 END) AS count_of_event_2
FROM PageviewEvents pe
LEFT JOIN SessionPageviews sp
    ON sp.id = pe.pageviewId
WHERE
    pe.eventId IN (1, 2)
GROUP BY
    sp.page
ORDER BY
    2 DESC;

Помимо вышесказанного, вы можете рассмотреть возможность добавления в таблицу следующего индекса:

CREATE INDEX idx ON SessionPageviews (pageviewId, eventId);

Это может помочь ускорить объединениемежду двумя столами.

1 голос
/ 27 мая 2019

Во-первых, ваш запрос подозрительный.Вы используете LEFT JOIN, но вы агрегируете по столбцу в таблице second .Я сомневаюсь, что вы действительно хотите строку с NULL первым столбцом.

Вы можете написать запрос, используя условное агрегирование (как указывает Тим).Я бы выразил это как:

select sp.page as Page, 
       sum( pe.eventid = 1 ) as count_of_event_1,
       sum( pe.eventid = 1 ) as count_of_event_2
from SessionPageviews sp join
     PageviewEvents pe
     on sp.id = pe.pageviewId
where pe.eventId in (1, 2)
group by sp.page
order by 2 desc;

Тогда для этого запроса есть две стратегии индексации.Если у вас много типов событий (или если 1 и 2 относительно редки), то:

  • SessionPageviews(id, page)
  • PageviewEvents(eventId, pageviewId)

В противном случае:

  • SessionPageviews(page, id)
  • PageviewEvents(pageviewId, eventId)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...