За последние 24 часа нас посетил 22891 программист и 1712 роботов. Сейчас ищут 1738 программистов ...

Вложенный запрос нещадно тормозит

Тема в разделе "PHP и базы данных", создана пользователем vasa_c, 15 апр 2008.

  1. vasa_c

    vasa_c Активный пользователь

    С нами с:
    22 мар 2006
    Сообщения:
    1.760
    Симпатии:
    0
    Адрес:
    гор.Ленинград
    Тупось...

    Есть сайт, на нём пользователи. В районе 100 000.

    Пользователи могут быть по разному взаимосвязаны. Пример - "взаимные друзья".
    Эти связи хранятся, допустим, в таблице `friends`:
    `one` int not null,
    `two` int not null,
    unique(`one`,`two`)

    Если два пользователя (с `id` - 3 и 5, допустим) друзья - этому соответствует две записи в таблице `friends`: (3,5) и (5,3).

    Количество взаимосвязей в районе 500K, соответственно записей - 1M.

    Получаем всех друзей заданного пользователя:
    SELECT `two` FROM `friends` WHERE `one`=7 -- id-ы всех друзей пользователя 7.

    Запрос из пыха через mysql_query проходит примерно за 0,7 мс. Вполне терпимо.


    Есть таблица `table` каких-то сущностей, относящихся к пользователям:
    `id` auto_increment,
    `user_id` int not null
    ...
    KEY (`user_id`)

    100К записей.

    Нужно получить сущности (хотя бы их id-ы) относящиеся к друзьям заданного пользователя. Используем вложенный запрос:
    SELECT `id` FROM `table` WHERE `user_id` IN (SELECT `two` FROM `friends` WHERE `one`=7)

    Выполняется в среднем за 0,3 сек, то есть ни в какие ворота не лезет.

    Делаю на первый взгляд совсем уж тупо:
    - выбираю всех друзей.
    - в пыхе циклом формирую строку со списком их id-ов.
    - SELECT `id` FROM `table` WHERE `user_id` IN (1, 2, 3, 4, 5, 6 ...) - подставляю сформированную строку.

    Среднее время всего этого - 2-10 мс.

    То есть два запроса и куча пыхокода "сделали" один аналогичный mysql-запрос в сотню раз.

    Где может быть подстава?

    FreeBSD7.0, mysql5.0.45, php5.2.5
     
  2. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    тут много хитростей у мускула, как он представляет разные списки.
    но сначала вопрос - почему не пишем select ... from users, friends where us_id=friends.one and friends.one=7
    ?
     
  3. vasa_c

    vasa_c Активный пользователь

    С нами с:
    22 мар 2006
    Сообщения:
    1.760
    Симпатии:
    0
    Адрес:
    гор.Ленинград
    Ибо слабо понимаем, чем он нам поможет
     
  4. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    внутренний джойн работает быстрее всего по скорости.
    Как работает ин - покрыто мраком, хотя есть предположения. В частности что используются разные алгоритмы при разных объемах списка и способе его задания.
     
  5. vasa_c

    vasa_c Активный пользователь

    С нами с:
    22 мар 2006
    Сообщения:
    1.760
    Симпатии:
    0
    Адрес:
    гор.Ленинград
    По идее, да, лучше так, видимо:
    [sql]SELECT `table`.`id` FROM `table` , `friends` WHERE `table`.`user` = `friends`.`two` AND `friends`.`one` =7[/sql]

    Спасибо.

    Но скорость всё равно одного порядка с вариантом с php-циклом.