Как оптимизировать MySQL запрос (группа и порядок) - PullRequest
4 голосов
/ 29 июля 2009

Привет всем, у меня запрос на оптимизацию. Это работает, но это собака, производительность мудрая.

Это звучит так:

SELECT  *
FROM    (
        SELECT  *
        FROM    views
        WHERE   user_id = '1'
        ORDER BY
                page DESC
        ) v
GROUP BY
        v.session

Я отслеживаю просмотры на разных страницах и хочу знать наибольшую страницу за сеанс, чтобы узнать, насколько далеко они нажали (им нужно просматривать каждую страницу до конца) в любой сессии.

По сути, я пытаюсь ЗАКАЗАТЬ результаты до ГРУППЫ. Которое вышеизложенное достигается при значительной стоимости.

Кто-нибудь, кто может дать мне пощечину, как это сделать? Спасибо, ребята!

Обновление:

Объяснение:

"1" "PRIMARY"   "<derived2>"    "ALL"   \N  \N  \N  \N  "3545"  "Using temporary; Using filesort"

"2" "DERIVED"   "views" "index" \N  "page"  "5" \N  "196168"    "Using where"

Схема:

ID       int(8) unsigned  (NULL)     NO      PRI     (NULL)   auto_increment  select,insert,update,references         
page     int(8)           (NULL)     YES     MUL     (NULL)                   select,insert,update,references         
user_id  int(8)           (NULL)     YES             (NULL)                   select,insert,update,references         
session  int(8)           (NULL)     YES             (NULL)                   select,insert,update,references         
created  datetime         (NULL)     NO                                       select,insert,update,references       

Указатель Информация:

views            0  PRIMARY              1  ID           A               196008    (NULL)  (NULL)          BTREE    

views            1  page                 1  page         A                  259    (NULL)  (NULL)  YES     BTREE 

Ответы [ 4 ]

8 голосов
/ 29 июля 2009

Я отслеживаю просмотры на разных страницах и хочу знать наибольшую страницу за сеанс, чтобы узнать, как далеко они нажали (им необходимо просматривать каждую страницу до конца) в любой сессии.

Заказ перед группировкой - очень ненадежный способ сделать это.

MySQL расширяет синтаксис GROUP BY: вы можете использовать несгруппированные и неагрегированные поля в предложениях SELECT и ORDER BY.

В этом случае случайное значение page выводится для каждого session.

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

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

Однако на практике возвращаются значения из первой отсканированной строки.

Так как вы используете ORDER BY page DESC в своем подзапросе, эта строка является строкой с максимальным page на сеанс.

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

Но вам даже не нужно делать такие неприятные трюки.

Просто используйте агрегатные функции:

SELECT  MAX(page)
FROM    views
WHERE   user_id = '1'
GROUP BY
        session

Это документированный и чистый способ сделать то, что вы хотите.

Создайте составной индекс на (user_id, session, page), чтобы запрос выполнялся быстрее.

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

SELECT  v.*
FROM    (
        SELECT  DISTINCT user_id, session
        FROM    views
        ) vo
JOIN    views v
ON      v.id =
        (
        SELECT  id
        FROM    views vi
        WHERE   vi.user_id = vo.user_id
                AND vi.session = vo.session
        ORDER BY
                page DESC
        LIMIT 1
        )

Предполагается, что id - это PRIMARY KEY на views.

4 голосов
/ 29 июля 2009

Я думаю, что ваш подзапрос не нужен. Вы получите те же результаты из этого гораздо более простого (и более быстрого) запроса:

SELECT *
FROM views 
WHERE user_id = '1' 
GROUP BY session
ORDER BY page DESC

Кроме того, у вас должен быть индекс для каждого поля, которое вы группируете, упорядочиваете или «где». В этом случае вам нужен индекс для user_id, session и page.

0 голосов
/ 29 июля 2009

Проблема в подселекте. ВЫБРАТЬ * ОТ (ВЫБРАТЬ * ОТ)

Вы должны использовать соединение. К какому типу данных относится ваше поле 'page'?

0 голосов
/ 29 июля 2009

Я бы предложил составной (многостолбцовый) индекс для user_id, page. Это предполагает, что внутренний запрос является медленной частью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...