Помогите оптимизировать запрос с UNION

Тема в разделе "Базы данных", создана пользователем -Dima-, 3 июл 2012.

Модераторы: latteo
  1. -Dima-

    -Dima-

    Регистр.:
    3 окт 2009
    Сообщения:
    167
    Симпатии:
    66
    Собственно есть такой запрос:

    Код:
    (SELECT * FROM `table1` WHERE id IN ( 736,14419,4170,14116 ))
    UNION
    (SELECT * FROM `table2` WHERE id IN ( 2995,3480,5981,5282 ))
    UNION
    (SELECT * FROM `table3` WHERE id IN ( 4610,13668,9654 ))
    UNION
    (SELECT * FROM `table4` WHERE id IN ( 5292 ))
    ORDER BY `column4` ASC
    
    по полям id стоит индекс.
    Мне нужно из таблиц брать произвольные строки
    Голова уже пухнет:hi:

    Можно ли как-то оптимизировать такой запрос??
    Т.к. в данном примере таких таблиц всего 4, а если их будет на порядок больше...
     
  2. DrakonHaSh

    DrakonHaSh

    Регистр.:
    29 июн 2010
    Сообщения:
    358
    Симпатии:
    122
    ваше оптимизировать это оптимизировать быстродействие ?
    или оптимизировать текст запроса ? (можно, по идее, процедуру написать)

    вообще-то такое ощущение что у вас таблицах table1..table4 одни и те же колонки на '99%' - в таком случае оптимизировать, вполне возможно, надо не запрос а организацию и логику БД
     
  3. -Dima-

    -Dima-

    Регистр.:
    3 окт 2009
    Сообщения:
    167
    Симпатии:
    66
    Да, под "оптимизировать" я имел ввиду и быстродействие и текст запроса, ну или хоть что-то одно :)

    Ощущение у вас верное.
    Может вы и правы, я тоже об этом думал.
    Но мне кажется, если их объеденить, тогда будет сложнее делать выборку рандомных значений с учетом параметров...
    Ну вот к примеру, допустим мне нужно выбрать рандомных 5 картинок синего цвета, 3 картинки пурпурного и 4 картинки бирюзового.
    картинок синего цвета -15к шт
    пурпурного - 9к шт
    бирюзового - 13к шт
    (пример вымышлен).
    Может как-то лучше можно организовать, но мне как разбить на разные таблицы, что-то ничего на ум не пришло...
     
  4. ShaDeRzz

    ShaDeRzz

    Регистр.:
    16 окт 2007
    Сообщения:
    176
    Симпатии:
    65
    Согласно многим тестам, решение с UNION и заранее указанными id в условии IN -- самое производительное на MySQL, при условии, что проставлены необходимые индексы.

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

    Можно тут почитать затяжные дискуссии на эту тему: http://habrahabr.ru/post/54176/
     
  5. -Dima-

    -Dima-

    Регистр.:
    3 окт 2009
    Сообщения:
    167
    Симпатии:
    66
    Угу, спасибо, листал вчера ))
    Но так и не пришел к оптимальному решению...
    Да, если происходят частые удаления, тут действительно напряг будет, тут мне понравилась идея с триггерами.
    Но благо у меня в данном случае нет частых обновлений.
    Кстати, вот тоже интересные 2 дискуссии:
    http://habrahabr.ru/post/55864/
    http://habrahabr.ru/post/44807/

    Просто думал, что может кто уже нашел для себя оптимальный вариант, для такой задачи...:rolleyes:
    Не знаю вот, как с процедурами будет дело обстоять, еще не пробовал.
    Но что-то мне кажется, что остановлюсь на первоначальном варианте...))
     
  6. unkn0wn

    unkn0wn

    Регистр.:
    22 дек 2006
    Сообщения:
    163
    Симпатии:
    86
    Решение с юнионом довольно шустрое само по себе, если есть индекс по id - там работы-то по индексу пройтись и выдернуть нужную строку, так что тут оптимизировать просто нечего, модификации пойдут только во вред. А вот с удалением все интереснее - можно нагородить огород с еще одной табличкой-очередью и двумя триггерами, срабатыающими по delete и insert, но что-то мне подсказывает, что если размер дыры не столь заметен, активных delete не планируется, а выборки рандомные, то проще либо заведомо делать выборку на 1-2 элемента больше и потом из массива просто выбирать нужное количество, либо сверять количество запрошенных строк к реально выбранным и потом просто сделать довыборку, если IN попал на дыру.
     
  7. afonya09

    afonya09

    Регистр.:
    31 янв 2009
    Сообщения:
    260
    Симпатии:
    18
    Для начала я бы посоветовал убрать "*" и union зфменить на union all.
    union объединяет и группирует наборы данных.
    Если ИД во всех ин-ах разные то это решение вам подойдет.

    Покажите полный текст запроса....
     
    -Dima- нравится это.
  8. ImNIK

    ImNIK Писатель

    Регистр.:
    7 июл 2012
    Сообщения:
    3
    Симпатии:
    0
    К сожалению с MySQL работал мало. Но если брать MS SQL к вышесказанному, вместо чисел лучше в запросе что-бы была переменная, иначе постоянно перед выполнением перестраивается план.
    А вообще действительно интересно увидеть весь запрос.
    А во вторых, что содержится в этих таблицах, может быть была возможность использовать 1 таблицу под эту задачу вместо 4?
     
  9. -Dima-

    -Dima-

    Регистр.:
    3 окт 2009
    Сообщения:
    167
    Симпатии:
    66
    по поводу * не уверен, что это много даст, если я перечислю все столбцы вместо этого..

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

    За union all, спасибо. Вылетело из головы..
    Одинаковых строк то нету, точно)