За последние 24 часа нас посетили 33024 программиста и 1821 робот. Сейчас ищут 853 программиста ...

Подскажите как объединить 2 запроса в 1

Тема в разделе "MySQL", создана пользователем marsik, 2 янв 2011.

  1. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    Подскажите как объединить 2 запроса в 1:

    Код (Text):
    1. SELECT DISTINCT theme.city_id, city.id, city.parent FROM theme, city WHERE theme.city_id = city.id
    2. SELECT * FROM city WHERE id IN(паренты предыдущего запроса)
    почитал учебник Мартина Грабера, попробовал коррелированный подзапрос:
    Код (Text):
    1. SELECT * FROM city WHERE city.id IN (SELECT DISTINCT theme.city_id, city.id, city.parent FROM theme, city WHERE theme.city_id = city.id)
    ничего не получилось, выдало ошибку: Operand should contain 1 column(s)
     
  2. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    Если честно - совсем непонятно, что именно ты хочешь сделать данным запросом.

    Если можно - выложи структуру таблиц и опиши задачу
     
  3. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    Код (Text):
    1. SELECT DISTINCT theme.city_id, city.id, city.parent FROM theme, city WHERE theme.city_id = city.id
    получаем данные по городам по которым есть темы и получаем паренты(вышестоящие регионы городов)
    Код (Text):
    1.  
    2. city_id     id  parent
    3. 46         46   2
    4. 252          252    4
    5. 464       464   9
    Код (Text):
    1. SELECT * FROM city WHERE id IN(паренты предыдущего запроса)
    получаем полные данные о регионе

    т.е. нужно вывести регионы, города которых есть в темах

    в таблице theme есть id, title, description, city_id
    в таблице city есть id name parent, по первому запросу можем сопоставить только по city_id и id
     
  4. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    SELECT * FROM city WHERE id IN (SELECT DISTINCT city.parent FROM theme, city WHERE theme.city_id = city.id )
     
  5. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    Спасибо, видать не правильно ранее выбирал, запрос долгий: Showing rows 0 - 11 (12 total, Query took 1.0308 sec) 76 сообщений, при 9000 уже Showing rows 0 - 24 (25 total, Query took 90.1977 sec)?

    SELECT DISTINCT city.parent FROM theme, city WHERE theme.city_id = city.id - Showing rows 0 - 11 (12 total, Query took 0.0036 sec)

    IN прибавляет много времени, каким то образом можно уменьшить?
     
  6. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    индекс стоит по полю theme.city_id ?

    нужен обычный.
     
  7. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    не было, поставил, время упало Showing rows 0 - 11 (12 total, Query took 0.3998 sec) много это или нормально?
    чудеса индексы творят, где было при 9000 уже Showing rows 0 - 24 (25 total, Query took 90.1977 sec) стало Showing rows 0 - 24 (25 total, Query took 0.0067 sec)
     
  8. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    ну это тебе решать - много или мало)))
    От задачи зависит.

    А индексы да, нужная вещь.

    Попробуй сделать EXPLAIN может еще чего покажет
     
  9. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    Код (Text):
    1. id  select_type            table    type    possible_keys   key     key_len     ref     rows    Extra
    2. 1   PRIMARY                city     ALL     NULL    NULL    NULL    NULL    480     Using where
    3. 2   DEPENDENT SUBQUERY     city     ref     PRIMARY,parent  parent  4   func    18  Using temporary
    4. 2   DEPENDENT SUBQUERY     theme    eq_ref  city_id     city_id     5   for.city.id     36  Using where; Using index
    не нормально?
    не нашел описание для Using where для Extra в справочнике
     
  10. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    Нормально. Тут вряд ли можно что-то оптимизировать. Вариант - временная таблица, но это уже будет не один запрос, а если я не ошибаюсь 3.
     
  11. Chushkin

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

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    SELECT t.*, c.xxx, r.xxx FROM theme t
    left join city as c on c.id = t.city_id
    left join city as r on r.id = c.parent_id
    WHERE t.xxx = ...

    И никаких подзапросов. Join-ы наше всё. ;)
    Как всегда - сначала решаем, что хотим получить, потом конструируем запрос. Задача: Получить список тем с параметрами городов и регионов. Решение: (см. выше). Т.е. одновременно со списком тем получаем параметры городов и параметры регионов. Вместо xxx прописать нужные колонки/поля, повторить сколько надо. WHERE - только если необходимо ограничить выборку по темам.
    Если задача "Получить только список регионов, доступных в нужной теме/темах", то и запрос будет другим.
    п.с.
    Правда я не понял, как у Вас город может быть регионом(потомком) города. :/
     
  12. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    вариант, но дает избыточные данные
     
  13. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    странно выходит, проверял раз 10, везде индексы одинаковые но при 76 сообщениях время генерации больше чем при 9000 сообщениях, по логике вроде как должно быть наоборот, но в 76 сообщениях городов в 2 раза больше, возможно оно накладывает доп. время.
     
  14. <?=RPG?>

    <?=RPG?> Активный пользователь

    С нами с:
    19 ноя 2010
    Сообщения:
    451
    Симпатии:
    0
  15. tommyangelo

    tommyangelo Старожил

    С нами с:
    6 дек 2009
    Сообщения:
    2.549
    Симпатии:
    0
    Адрес:
    Мариуполь
    Chushkin Джоины зачастую излишни. Подзапрос, особенно по ключу, может быть гораздо быстрее
     
  16. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    так по этому запросу SELECT DISTINCT city.parent FROM theme, city WHERE theme.city_id = city.id без DISTINCT вроде бы никак, будут выходить дубли регионов.

    tommyangelo походу IN сильно время оттягивает, с join выходит быстрее: Showing rows 0 - 29 (70 total, Query took 0.0046 sec) но хз как исключить дубли, DISTINCT перед SELECT не реагирует
     
  17. <?=RPG?>

    <?=RPG?> Активный пользователь

    С нами с:
    19 ноя 2010
    Сообщения:
    451
    Симпатии:
    0
    IN не оттягивает время, оттягивает время похоже подзапрос в IN

    По ссылке есть решение (скорее всего). В любом случае нужно искать альтернативное решение. Я бы также советовал вам заняться профилированием и анализом запроса.
     
  18. Chushkin

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

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Какие ещё избыточные данные? Вы о чём?
     
  19. Chushkin

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

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Зависит от запроса. В простых запросах, типа приведённого выше, join-ы быстрее. В подавляющем большинстве случаев join-ы лучше, чем подзапросы, на то их и придумали.
    Кроме того, стоит учитывать оптимизатор движка, иногда на сложных запросах он глючит и скорость падает на порядок - тогда нужен бубен и отличное знание движка, чтоб вправить ему мозги. Но это очень редко - исключение из правил. А так, join's наше всё.
     
  20. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    такие которые исключали через distinct, здесь выводятся по много раз одни и те же города, т.е. если у нас 1000 тем с одного города, то выведется 1000 раз этот город
     
  21. Chushkin

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

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Если внимательно читать, то выше я писал "Если задача "Получить только список регионов, доступных в нужной теме/темах", то и запрос будет другим.".
    Вы уж разберитесь для начала, что Вам нужно. Список тем с параметрами городов или список городов в теме(ах).
     
  22. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    вы наверное темы не читаете с начало?
    в 3 сообщение было - т.е. нужно вывести регионы, города которых есть в темах
     
  23. Chushkin

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

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Ну тогда и ищите регионы. Те же join's, что-то вроде:
    SELECT r.* FROM city r
    inner join city as c on c.parent_id = r.id
    inner join theme t on t.city_id = c.id
    WHERE t.xxx = ...

    Смысл inner тут надеюсь понятен?
    п.с.
    Кроме того, можно использовать GROUP BY с left join, если запрос небольшой. Это работает, но не красиво в плане SQL, более правильно с inner.
     
  24. marsik

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

    С нами с:
    30 дек 2008
    Сообщения:
    246
    Симпатии:
    17
    помоемому полюбому что с outer, inner будут дубли или я путаю?
     
  25. Chushkin

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

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Конечно. Вспоминаем как работает запрос с inner: записи должны быть найдены в обоих таблицах.
    Описание запроса по дилетантски: Получить(select) регионы(from) id которых есть в(inner) city как(on) parent_id, а города есть в(inner) theme как(on) city_id.
    Эквивалент этого запроса с использованием подзапросов будет что-то вроде:
    SELECT r.* FROM city r
    where
    exists( select * from city c where c.parent_id = r.id and exists(select * from theme where t.city_id = c.id) )

    Эффектисвность вариантов сами сравните, а потом нам расскажете.