引用多个表的SQL查询的正确结构是什么?

时间:2015-03-08 03:45:03

标签: mysql 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工作台中运行良好,但是当我通过PDO运行它会导致超时。

进一步说明:简化查询(删除最终的嵌套查询)可以防止错误,因此看起来确定这是查询复杂性的超时问题

2 个答案:

答案 0 :(得分: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) 

答案 1 :(得分:1)

  

我想知道我的代码结构是否非常低效,是否有更好的方法来实现我的查询?

是。如果您想查看效率是多么低效,请在查询前放置EXPLAIN EXTENDED。我最喜欢理解MySQL解释查询输出的资源是http://www.sitepoint.com/using-explain-to-write-better-mysql-queries/

将您对@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

我在上面看到@ jeremy的查询并且似乎是相同的,尽管你提到这个结果是不准确的。根据你分享的内容,它不应该是。如果是,我建议您通过确定您的连接键是否有多对来进行故障排除,例如

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索引以及它们如何用于优化查询的知识。只要注意这一点,在我看来,

上的索引

country_region.fk_country_id

responses.fk_question_id

interventions.pk_intervention_id

interventions.fk_module_id

可能是最低限度....虽然你几乎可以肯定地优化那些。使用上面的EXPLAIN查询,它可以帮助您了解如何。

祝你好运