Медленный запрос с наличием на поле вычисления

0

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

Это заняло более 1 секунды, и запрос объяснения говорит мне, что 30k строк отфильтровываются. Так что 30k фильтруется для 150k строк в моей базе разработки DB... мой сервер в сети намного больше, чем это....

Здесь мой запрос:

SELECT  profils.*,
        Users.username,
        ( SELECT  count(*)
                from  profilsphotos pp
            where  pp.iduser=Profils.iduser
        ) as nbpics,
        ATAN2(SQRT(POW(COS(RADIANS(50.78961000)) * SIN(RADIANS(Y(gm_coor) - 4.64956000)),
                        2) + POW(COS(RADIANS(X(gm_coor))) * SIN(RADIANS(50.78961000)) - SIN(RADIANS(X(gm_coor))) * COS(RADIANS(50.78961000)) * COS(RADIANS(Y(gm_coor) - 4.64956000)),
                                                2)), (SIN(RADIANS(X(gm_coor))) * SIN(RADIANS(50.78961000)) + COS(RADIANS(X(gm_coor))) * COS(RADIANS(50.78961000)) * COS(RADIANS(Y(gm_coor) - 4.64956000)))
             ) * 6372.795 AS distance
    from  Users
    inner join  Profils  ON Users.id=Profils.iduser
    where  Profils.Actif=1
      and  profils.idsexe=2
      and  profils.idlookingfor=1
      and  Profils.iduser<>1
    HAVING  distance<400
    order by  Users.id desc, distance asc
    limit  12 

Обратите внимание, что я добавляю индекс на эти четыре поля: actif, idsexe, idlookingfor и iduser

Что случилось с моим запросом?

Большое спасибо !

паскаль

  • 0
    Можете ли вы вставить вывод объяснения, а также результат этого запроса: выберите число (*) в разделе Внутреннее объединение пользователей Profils on Users.id = Profils.iduser, где Profils.Actif = 1 и profils.idsexe = 2 и profils.idlookingfor = 1 и Profils.iduser <> 1
  • 0
    Привет Марк, То же самое .... 30k отфильтрованы ....
Теги:
optimization
performance
having

2 ответа

0

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

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

Сначала создайте соответствующие индексы для запроса:

ALTER TABLE
  'Profils'
ADD
  INDEX 'profils_idx_actif_iduser' ('Actif', 'iduser');

ALTER TABLE
  'Users'
ADD
  INDEX 'users_idx_id_username' ('id', 'username');

ALTER TABLE
  'profils'
ADD
  INDEX 'profils_idx_idsexe_idlookingfor' ('idsexe', 'idlookingfor');

ALTER TABLE
  'profilsphotos'
ADD
  INDEX 'profilsphotos_idx_iduser' ('iduser');

Теперь создайте таблицу temp и проиндексируйте ее:

-- Transformed subquery to a temp table to improve performance
CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS SELECT
        count(*) AS nbpics,
        iduser 
    FROM
        profilsphotos pp 
    WHERE
        1 = 1 
    GROUP BY
        iduser 
    ORDER BY
        NULL;

ALTER TABLE
  'temp1'
ADD
  INDEX 'temp1_idx_iduser_nbpics' ('iduser', 'nbpics');

Теперь попробуйте запустить этот запрос вместо исходного и посмотреть, работает ли он быстрее:

SELECT
        optimizedSub1.*,
        temp1.nbpics 
    FROM
        (SELECT
            Users.username,
            ATAN2(SQRT(POW(COS(RADIANS(50.78961000)) * SIN(RADIANS(Y(Profils.gm_coor) - 4.64956000)),
            2) + POW(COS(RADIANS(X(Profils.gm_coor))) * SIN(RADIANS(50.78961000)) - SIN(RADIANS(X(Profils.gm_coor))) * COS(RADIANS(50.78961000)) * COS(RADIANS(Y(Profils.gm_coor) - 4.64956000)),
            2)),
            (SIN(RADIANS(X(Profils.gm_coor))) * SIN(RADIANS(50.78961000)) + COS(RADIANS(X(Profils.gm_coor))) * COS(RADIANS(50.78961000)) * COS(RADIANS(Y(Profils.gm_coor) - 4.64956000)))) * 6372.795 AS distance 
        FROM
            Users 
        INNER JOIN
            Profils 
                ON Users.id = Profils.iduser 
        WHERE
            Profils.Actif = 1 
            AND profils.idsexe = 2 
            AND profils.idlookingfor = 1 
            AND Profils.iduser <> 1 
        HAVING
            distance < 400 
        ORDER BY
            Users.id DESC,
            distance ASC LIMIT 12) AS optimizedSub1 
    LEFT JOIN
        temp1 
            ON temp1.iduser = optimizedSub1.iduser
  • 0
    Привет Томер, спасибо! Это то же самое ... 30 тыс. Строк .... Кроме того ... это нормально ... я всегда должен заново создавать временную таблицу? потому что, если я скопирую и вставлю ваш последний запрос ... MySQL сказал, что temp1 не существует! Спасибо за вашу помощь !
  • 0
    @ pascal22 - временная таблица будет доступна только для этого конкретного сеанса, поэтому ее следует создавать и индексировать каждый раз, как при выполнении запроса. Была ли продолжительность выполнения улучшена в целом?
Показать ещё 1 комментарий
0

Profils необходимо

INDEX(Actif, idsexe, idlookingfor) -- in any order

Возможно, distance должно быть первым?..

order by  Users.id desc, distance asc

Что такое Y(gm_coor)? Если это хранимая функция, нам нужно знать больше. В какой таблице есть gm_coor? После этого, возможно, мы можем обсуждать "ограничительную рамку" как частичное ускорение.

Сделайте еще одно вложение SELECTs и переместите вычисления nbpics на него. В настоящее время COUNT(*) выполняется 30K раз. После изменения это будет всего 12 раз.

переформулирование

SELECT  p2.*,
        u.username, 
        ( SELECT  COUNT(*)
            FROM  profilsphotos pp
            where  pp.iduser = p2.iduser 
        ) as nbpics,
        x.distance
    FROM  
        ( SELECT  p1.id,    -- assuming this the PK of Profils
                  (...) AS distance
            FROM  Profils AS p1
            WHERE  p1.Actif=1
              and  p1.idsexe=2
              and  p1.idlookingfor=1
              and  p1.iduser<>1
            HAVING  distance < 400
            ORDER BY  distance
            LIMIT  12 
        ) AS x
    JOIN  profils AS p2 USING(id)
    JOIN  Users AS u  ON u.id = p2.iduser;
  • 0
    Привет Рик !! То же самое ... 30k + фильтруется ..
  • 0
    Привет Рик! То же самое ... более 30 тысяч строк ... Я добавил actif, idsexe, idlooking для индекса .... Я изменил порядок на: order by disrance asc, users.id desc .. Все то же самое ...
Показать ещё 10 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню