具有大量数据的多个连接的 MySql 查询

Posted

技术标签:

【中文标题】具有大量数据的多个连接的 MySql 查询【英文标题】:MySql Query with multiple joins with huge data 【发布时间】:2019-06-10 09:06:07 【问题描述】:

我在一个数据库中有三个表

表 feedback_responses

    resp_id(Primary) | name | mobile | pnr | message | added_on

表 feedback_response_items

    feed_item_id | resp_id | qn_id | ans_id

表 feedback_answers

    ans_id(Primary) | ans_desc | qn_id

我想要显示 feedback_responses 表 中的所有行,并且每行包含 feedback_response_items 中与表 feedback_responses 的主键匹配的 9 个项目这是 resp_id

所以我会得到所有问题的ans_id,我会得到表feedback_answers

中响应的答案描述

查询是

$f=$db->Query("
        SELECT fr.resp_id, fr.name, fr.mobile, fr.pnr, fr.message,
        (SELECT ans_id FROM feedback_response_items fr1 WHERE fr.resp_id = fr1.resp_id  AND fr1.qn_id='1') AS qn1Ans,
        (SELECT ans_id FROM feedback_response_items fr2 WHERE fr.resp_id = fr2.resp_id  AND fr2.qn_id='2') AS qn2Ans,
        (SELECT ans_id FROM feedback_response_items fr3 WHERE fr.resp_id = fr3.resp_id  AND fr3.qn_id='3') AS qn3Ans,
        (SELECT ans_id FROM feedback_response_items fr4 WHERE fr.resp_id = fr4.resp_id  AND fr4.qn_id='4') AS qn4Ans,
        (SELECT ans_id FROM feedback_response_items fr5 WHERE fr.resp_id = fr5.resp_id  AND fr5.qn_id='5') AS qn5Ans,
        (SELECT ans_id FROM feedback_response_items fr6 WHERE fr.resp_id = fr6.resp_id  AND fr6.qn_id='6') AS qn6Ans,
        (SELECT ans_id FROM feedback_response_items fr7 WHERE fr.resp_id = fr7.resp_id  AND fr7.qn_id='7') AS qn7Ans,
        (SELECT ans_id FROM feedback_response_items fr8 WHERE fr.resp_id = fr8.resp_id  AND fr8.qn_id='8') AS qn8Ans,
        (SELECT ans_id FROM feedback_response_items fr10 WHERE fr.resp_id = fr10.resp_id  AND fr10.qn_id='10') AS qn10Ans
        FROM feedback_responses fr
        "); 

上面的查询需要很多时间(超过 2 分钟)来执行如何优化它,我对此感到震惊,任何反馈都将非常感激。

【问题讨论】:

顺便说一句,您可以通过命名列 response_id、answer_id 等来拯救追随您的可怜的管理员。 【参考方案1】:

我认为,如果您在 select 语句中移动子查询,并 JOIN 项目表,您的查询将运行得非常快! (似乎子查询对每一行都执行,所以需要时间)。这将起作用:

SELECT fr.resp_id, fr.name, fr.mobile, fr.pnr, fr.message,
MAX(IF(fri.qn_id='1',ans_id,0)) AS qn1Ans,
MAX(IF(fri.qn_id='2',ans_id,0)) AS qn2Ans,
MAX(IF(fri.qn_id='3',ans_id,0)) AS qn3Ans,
MAX(IF(fri.qn_id='4',ans_id,0)) AS qn4Ans,
MAX(IF(fri.qn_id='5',ans_id,0)) AS qn5Ans,
MAX(IF(fri.qn_id='6',ans_id,0)) AS qn6Ans,
MAX(IF(fri.qn_id='7',ans_id,0)) AS qn7Ans,
MAX(IF(fri.qn_id='8',ans_id,0)) AS qn8Ans,
MAX(IF(fri.qn_id='10',ans_id,0)) AS qn10Ans,
FROM feedback_responses fr
JOIN feedback_response_items fri ON fr.resp_id = fri.resp_id 
GROUP BY fr.resp_id, fr.name, fr.mobile, fr.pnr, fr.message

希望对你有帮助!

【讨论】:

【参考方案2】:

这可能不是一个让您完全满意的答案,因为可能需要一些编程:

您忽略了指定为各种表指定的索引。对于表 feedback_response_items,您应该至少在列 resp_id 上定义了一个索引(并且在 qn_id 上的一个索引可能不会有任何影响)。如果没有,请这样做,看看如何减少执行时间。

如果您已经定义了索引或定义索引并没有显着提高执行时间,则需要进行一些编程。您的 SQL 应该是:

SELECT fr.resp_id, fr.name, fr.mobile, fr.pnr, fr.message, fri.ans_id /*, fa.ans_desc */
FROM feedback_responses fr
JOIN feedback_response_items fri ON fr.resp_id = fri.resp_id    
                                    AND fri.qn_id IN ('1','2','3','4','5','6','7','8','10')
/* JOIN feedback_answers fa on fri.ans_id = fa.ans_id */
ORDER BY fri.qn_id
;

删除上述 SQL 中的 cmets 以检索答案。现在对于 fr.resp_id 的每个值,将返回 9 行。目的是让这个 SQL 由一个计算机程序发出,该程序将处理 9 行的组并根据需要显示结果。

【讨论】:

以上是关于具有大量数据的多个连接的 MySql 查询的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 选择查询与连接和大量的结果优化

PHP、MySQL 和大量简单查询

构建具有大量数据通信的系统的最佳方法是啥?

具有大量查询的 node-postgres

阿里四面:为何MySQL没有使用建立的索引?

mysql如何批量查询大量数据