За последние 24 часа нас посетили 22863 программиста и 1234 робота. Сейчас ищут 775 программистов ...

MySQL виснет на вложенных запросах

Тема в разделе "MySQL", создана пользователем Easy, 15 июл 2011.

  1. Easy

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

    С нами с:
    15 июл 2011
    Сообщения:
    286
    Симпатии:
    0
    неужели вложенный запрос вычисляется каждый раз, для каждой новой строки? Да даже если и так, не может это повесить базу. Пример.
    Есть таблица city
    [sql]id | pid| name[/sql]
    pid - id страны

    есть street
    [sql]id | pid | name[/sql]
    pid - id города

    есть area (районы города)
    [sql]id | pid | name[/sql]
    pid - id города

    и таблица area_street (улица - район)
    [sql]id | area | street[/sql]


    так вот, предположим нужны вывести все улицы определённого района города одним запросом.

    Упростим, без фильтра по городу беру, так как уже в принципе район привязан к городу и один район не будет в разных городах.

    [sql]SELECT * FROM `street` WHERE `id` IN ( SELECT GROUP_CONCAT(`street`) FROM `area_street` WHERE `area` = 1 );[/sql]

    Этот запрос ждал минуту, при всём при этом в базе всего 70 000 улиц.
    В районе 1 - 12 улиц.
    Берём зарпос
    [sql]SELECT GROUP_CONCAT(`street`) FROM `area_street` WHERE `area` = 1;[/sql]
    результат
    [sql]1,2,3,4,5,6,7,8,9,10,11,12[/sql]

    Выводит мгновенно, не засекал время, но вообще не виснет, ну и с чего бы виснуть такому запросу.
    теперь берём подставляем
    [sql]SELECT * FROM `street` WHERE `id` IN ( 1,2,3,4,5,6,7,8,9,10,11,12 );[/sql]
    Выводит 12 улиц, тоже мгновенно

    Почему вместе виснет? Ждал минуту, нагрузка на проц 100% проц атлон 5600+
    Приходится отрубать службу.
    Я понимаю что можно сделать так
    [sql]SELECT `street`.* FROM `street`, `area_street` WHERE `street`.`id` = `street` AND `area` = 1;[/sql]

    И будет выведено 12 улиц, но вопрос именно про вложенный запрос, так как на сайте MySQL читал что с версии 4.1 кажется или раньше, запросы вложенные идентичны запросу с объединением, но что то разница очень велика :)

    Так как база не моя, я просто брал дамп заливал и испытывал, потом создал индексы для полей `area_street`.`area` и `street`.`id`
    запрос стал выполнятся около 4х секунд и возвращать только одну улицу.

    где я ошибаюсь с вложенным запросом, почему зависает и работает не так как задумано?
     
  2. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    а ты поставь LIMIT 1 и посмотри сколько 1 строка выполняется
     
  3. Easy

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

    С нами с:
    15 июл 2011
    Сообщения:
    286
    Симпатии:
    0
    C LIMIT 1 мгновенное
    А с LIMIT 2 повисло :)
     
  4. armadillo

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

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    это что за порнография?
    GROUP_CONCAT возвращает строку, которая используется в IN( как одно значение.
    надо возвращать набор данных.

    Но в любом случае для вашей задачи (и этой и других возможных) вам не нужны вложенные запросы. Пишите нормальные JOIN'ы.
     
  5. Easy

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

    С нами с:
    15 июл 2011
    Сообщения:
    286
    Симпатии:
    0
    мне для задачи как раз нужен был именно вложенный запрос, так как мне в класс нужно было передавать только массив который потом объединится во что то похожее на WHERE ' . implode(' AND ', $where);
    по этому я и написал
    $where[] = "`id` IN ( SELECT GROUP_CONCAT(`street`) FROM `area_street` WHERE `area` = 1 )";

    у меня 2 варианта, либо сделать вложенный, либо сделать вначале отдельно [sql] SELECT GROUP_CONCAT(`street`) FROM `area_street` WHERE `area` = 1[/sql]
    а потом уже его отправить параметром :)
    я сделал 2 запроса, так как со вложенным не вышло :)
     
  6. Easy

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

    С нами с:
    15 июл 2011
    Сообщения:
    286
    Симпатии:
    0
    интересно
    так
    [sql]SELECT * FROM `street` WHERE `id` IN ( SELECT `street` FROM `area_street` WHERE `area` = 1 ) limit 12;[/sql]
    всё работает :) и с любым числом меньше 12
    а вот если написать 13 то виснет.
     
  7. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    индекс стоит по area ?
    обычный нужен.
    Ну и по id