2013-02-08 4 views
0

Я запускаю поисковый запрос для сайта, который собирает element, которые соответствуют запросу. Однако может быть или не быть один или более items, которые связаны с element. Итак, у меня есть подзапрос, который подсчитывает совпадения всех items, связанных с element.Выполнение подзапроса только по результатам родительского запроса

Этот запрос действительно работает. Но невероятно медленно. Сейчас мне требуется около 50 секунд. Если я сдавливаю подзапрос, это намного, намного быстрее.

SELECT DISTINCT e.id, 
    MATCH (e.heading) AGAINST ('+(room)') AS h_score, 
    MATCH (e.text) AGAINST ('+(room)') AS t_score, 
    ( 
     SELECT SUM(MATCH (item.heading, item.text) AGAINST ('+(room)')) AS itemscore 
      FROM item LEFT JOIN _element_item ON item.id = _element_item.item_id 
      WHERE _element_item.item_id = e.id 
      AND MATCH (item.heading, item.text) AGAINST ('+(room)') 
    ) AS i_score 

    FROM element AS e 
    LEFT JOIN _element_brand ON e.id = _element_brand.element_id 
    LEFT JOIN _element_language ON e.id = _element_language.element_id 
    LEFT JOIN _element_region ON e.id = _element_region.element_id 
    LEFT JOIN _element_type ON e.id = _element_type.element_id 
    LEFT JOIN _element_group ON e.id = _element_group.element_id  

    WHERE _element_brand.brand_id = 1 
    AND _element_language.language_iso = 'en' 
    AND _element_region.region_id = 1 
    AND _element_type.type_id = 1 
    AND _element_group.group_id = 1 
    AND e.replacement_id IS NULL 
    AND e.status = 1 
    AND MATCH (e.heading, e.text) AGAINST ('+(room)') 
    ORDER BY t_score + h_score DESC LIMIT 100 

Есть ли способ заставить это работать быстрее?

Я предполагаю, что он запускает полный подзапрос для каждого element перед тем, как сопоставить element? Могу ли я заставить его запустить подзапрос по совпадениям в родительском запросе? Если да, то как?

+0

У вас есть LEFT JOINs, но затем следуйте своему предложению WHERE, чтобы иметь конкретные критерии против этих таблиц, что приводит к INNER JOIN. Это было ваше намерение, или вы действительно имели в виду, что они были ЛЕВЫМИ ПРИСОЕДИНЯЯМИ. Если это так, переместите ваши И-критерии в соответствующий LEFT JOIN. – DRapp

+0

ЕСЛИ Я честен, я думаю, что они закончились ЛЕВЫМИ ПРИСОЕДИНЯЯМИ, потому что это сработало. Но я ищу только те элементы, которые соответствуют критериям в таблицах связывания (начиная с подчеркивания). Меня не интересуют значения в объединенных таблицах. – ironinthesoul

ответ

0

Позвольте мне пояснить левое соединение для ваших образцов.

select e.heading 
    FROM element AS e 
      LEFT JOIN _element_brand 
       ON e.id = _element_brand.element_id 
    WHERE 
      e.SomeColumn = 'test' 
     AND _element_brand.brand_id = 1 

это то же самое, как

select e.heading 
    FROM element AS e 
      JOIN _element_brand 
       ON e.id = _element_brand.element_id 
    WHERE 
      e.SomeColumn = 'test' 
     AND _element_brand.brand_id = 1 

, поскольку условие WHERE форсирует только возвращать записи, которые имеют соответствие _element_brand запись и Brand_ID, что запись в = 1. Таким образом, это будет возвращать только записи, где "e.SomeColumn = 'тест'" И Brand_ID = 1.

Теперь посмотрим на настоящий левый присоединиться

select e.heading 
    FROM element AS e 
      LEFT JOIN _element_brand 
       ON e.id = _element_brand.element_id 
      AND _element_brand.brand_id = 1 
    WHERE 
     e.SomeColumn = 'test' 

Это вернет все записи из элемента, которые имеют «e.SomeColumn =„тест“» НЕЗАВИСИМО иметь запись в таблице _element_Brand и _element_brand.brand_id = 1.

Так что, если у вас 100 элементов с SomeColumn = 'test', а из них 50 записей имеют действительные записи в таблице _element_brand для соответствующего идентификатора. Из этих 50 только 20 специфически имели бренд_id = 1 ...

Первые два примера запросов (объединение слева с ГДЕ и объединение) ТОЛЬКО вернули бы 20 записей, в которых было всего 20 записей.

Запрос LAST по-прежнему будет возвращать 100 записей, которые только что были квалифицированы на основе «теста».

Надеюсь, это пояснит, основывается ли ваш сценарий на данных ... иногда видение в книге или документе может фактически не прояснить, кто пытается ее понять.

SELECT DISTINCT 
     STRAIGHT_JOIN 
     e.id, 
     MATCH (e.heading) AGAINST ('+(room)') AS h_score, 
     MATCH (e.text) AGAINST ('+(room)') AS t_score, 
     (SELECT SUM(MATCH (item.heading, item.text) AGAINST ('+(room)')) 
      FROM _element_item 
       JOIN item 
       ON _element_item.item_id = item.id 
       AND MATCH (item.heading, item.text) AGAINST ('+(room)') 
      WHERE 
       e.id = _element_item.item_id) AS i_score 
    FROM 
     element AS e 
     JOIN _element_brand 
      ON e.id = _element_brand.element_id 
      AND _element_brand.brand_id = 1 

     JOIN _element_language 
      ON e.id = _element_language.element_id 
      AND _element_language.language_iso = 'en' 

     JOIN _element_region 
      ON e.id = _element_region.element_id 
      AND _element_region.region_id = 1 

     JOIN _element_type 
      ON e.id = _element_type.element_id 
      AND _element_type.type_id = 1 

     JOIN _element_group ON e.id = _element_group.element_id  
      AND _element_group.group_id = 1 
    WHERE 
      e.status = 1 
     and e.replacement_id IS NULL 
     AND MATCH (e.heading, e.text) AGAINST ('+(room)') 
    ORDER BY 
     t_score + h_score DESC 
    LIMIT 100 

Я перестроился, чтобы присоединиться. Кроме того, слегка изменил поле select sum() для i_score, которое, кажется, убивает ваш запрос. Я также добавил ключевое слово «STRAIGHT_JOIN» вверху, чтобы сообщить о запуске запроса в представленном порядке.

Мой единственный вопрос обзор на поле выбора ... Вы присоединяетесь

e.id к _element_item.item_id, затем от _element_item.item_id до .... item-id

Итак, что сказал, МОЖНО быть упрощено, что

e.id = item.id, и вы можете полностью удалить таблицу _element_item, если они действительно совпадают, но, похоже, это таблица моста, которая для данного элемента может иметь много элементов.

+0

Хм, я думал, что это то, чего я добился с помощью WHERE _element_item.item_id = e.id. Но я так долго смотрел на код, что мой мозг - это месиво! Разве это не делает то, что я хочу? Если нет, что я не понимаю? – ironinthesoul

+0

@ironinthesoul, пересмотренный ответ для разъяснения слева. – DRapp

+0

Спасибо @DRapp, очень хорошо объяснил. Теперь я изменил свои соединения на внутренние соединения. Я действительно должен это знать, но иногда его пропускают. Изменение объединений вычеркнуло небольшую сумму из моего запроса, но не значительную сумму. Моя страница создается за 52 секунды, но если я удалю подзапрос, она опустится до 3 секунд. Все еще ищут решение для его ускорения. Я не вижу, как лучше привязать его только к соответствующим родительским результатам. Но из того, что я понимаю, подзапрос запускается первым, так что, возможно, я ничего не могу с этим поделать? – ironinthesoul

Смежные вопросы