2015-03-08 2 views
0

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

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

Это всегда работало нормально и, казалось, делало все, в чем я нуждался, - однако запрос, который я только что написал, имеет больше вложенных запросов, чем обычно, и, кажется, вызывает внутреннюю ошибку сервера (журнал ошибок «mod_fcgid: чтение данных таймаут через 31 секунду ").

Мне интересно, если моя структура кода ужасно неэффективна и если есть лучший способ достичь моего запроса?

Вот мой текущий SQL

SELECT response_value, fk_intervention_id, fk_question_id FROM responses_submitted where fk_intervention_id in (
    SELECT pk_intervention_id FROM interventions where fk_module_id = 4 and fk_country_id in 
     (SELECT fk_country_id from country_region where fk_region_id in 
      (SELECT fk_region_id from country_region where fk_country_id = 25) 
     ) 
    AND year=2013) 
AND fk_question_id in (119, 122, 100, 1363, 130, 119, 122, 125, 127, 126, 138, 140) 

Стоит отметить: это прекрасно работает в MySQL Workbench, но когда я запускаю его через PDO это вызывает тайм-аут.

Далее отметим: упрощение запроса (удаление окончательного вложенного запроса) предотвратить ошибку, так что кажется, уверен, что это является проблемой тайм-аут со сложностью запроса

ответ

3

Я бы реорганизовать это в нечто вроде следующего , Это более понятно, чем все подвыборки, однако я не знаю, справится ли это с вашей проблемой производительности. (Я переработан по виду, так что могут быть ошибки)

SELECT response_value, fk_intervention_id, fk_question_id 
FROM responses_submitted 
INNER JOIN interventions ON responses_submitted.fk_intervention_id = interventions.pk_intervention_id 
INNER JOIN country_region ON interventions.fk_country_id = country_region.fk_country_id 
Where 
interventions.fk_module_id = 4 
AND country_region.fk_country_id = 25 
AND year = 2013 
AND fk_question_id in (119, 122, 100, 1363, 130, 119, 122, 125, 127, 126, 138, 140) 
+0

Хорошо спасибо! Я действительно не понимаю, как использовать JOINs, поэтому мне нужно научиться понимать ваш код: он почти работает, но выбирает все ответы только для одного вмешательства в регионе, а не для всех вмешательств в регионе. – Gideon

+0

check out: http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/ – Jeremy

1

мне интересно, если моя структура кода ужасно неэффективно и, если есть лучший способ достичь мой запрос?

Да. И если вы хотите увидеть, насколько это неэффективно, поместите EXPLAIN EXTENDED перед запросом. Мой любимый ресурс для понимания вывода запроса MySQL объяснить, http://www.sitepoint.com/using-explain-to-write-better-mysql-queries/

inre вашего ответа на @jeremy выше,

Я не очень понимаю, как использовать JOIN и поэтому я буду иметь, чтобы научиться понимать код:

Хорошо, так что вы обязательно должны узнать, как использовать присоединяется, если ты собираешься использовать SQL для чего-нибудь. Это фундаментально. Вы напишете ужасный SQL и сделаете ужасные ошибки моделирования данных, если вы не поймете объединения. Потратьте время, чтобы изучить и понять их

В плане того, что ваш запрос должен выглядеть, это должно выглядеть примерно так:

SELECT response_value, fk_intervention_id, fk_question_id 
FROM responses_submitted AS a 
INNER JOIN interventions AS b 
    ON a.fk_intervention_id = b.pk_intervention_id 
INNER JOIN country_region AS c 
    ON b.fk_country_id = c.fk_country_id 
WHERE a.fk_question_id IN (119, 122, 100, 1363, 130, 119, 122, 125, 127, 126, 138, 140) 
AND b.fk_module_id = 4 
AND b.year = 2013 
AND c.fk_country_id = 25 

Я eyeballed @ запрос Джереми выше и, кажется, то же самое, хотя вы упомянули, что этот результат был неточным. На основе того, что вы поделили, этого не должно быть.Если да, то я бы рекомендовал диагностику проблемы пути определения, если любой из ваших ключей присоединиться многие ко многим, например,

SELECT fk_country_id, count(*) FROM country_region GROUP BY fk_country_id HAVING COUNT(*) > 1; /*based on what you described, this should be null*/ 

SELECT pk_intervention_id, count(*) FROM interventions WHERE fk_module_id = 4 AND year = 2013 GROUP BY pk_intervention_id HAVING count(*) > 1; /*based on what you described, this should be null*/ 

т.д.

Наконец, я настоятельно рекомендовал бы немного узнать больше о индексах MySQL и как их можно использовать для оптимизации запросов. Просто Eyeballing это, казалось бы мне, что индекс на

country_region.fk_country_id

responses.fk_question_id

interventions.pk_intervention_id

interventions.fk_module_id

, вероятно, будет минимальным. ... хотя вы почти наверняка оптимизировали их совсем немного. Используйте запрос EXPLAIN выше, и это поможет вам понять, как это сделать.

Удачи

+1

Это невероятно полезно - спасибо, что нашли время, чтобы написать его. Я думаю, что проблема с кодом Джереми (не то, что это его код, вероятно, моя структура) заключается в том, что одна из таблиц у меня много. country_region принимает идентификаторы страны и связывает их со многими идентификаторами регионов (я думаю, это правильно, поскольку страна может быть в нескольких регионах). Я еще изучу ваш комментарий. – Gideon

+0

Ну, если таблица country_region не содержит данные, необходимые для ответа на ваш вопрос (например, в случае выбора верхнего запроса), мне кажется, что вы можете просто полностью удалить эту таблицу (и это объединение) и просто добавить предложение where на interventions.fk_country_id (поэтому в моей версии запроса удалите соединение в country_region и замените «AND c.fk_country_id = 25» на «AND b.fk_country_id = 25») – evanv

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