所以我目前正在运行此查询。但是,在phpmyadmin外部运行时会导致504超时错误。我认为这与查询返回或访问的行数有多大有关。 我对mySQL并不是很有经验,所以这是我能做的最好的事情:
SELECT
s.surveyId,
q.cat,
SUM((sac.answer_id*q.weight))/SUM(q.weight) AS score,
user.division_id,
user.unit_id,
user.department_id,
user.team_id,
division.division_name,
unit.unit_name,
dpt.department_name,
team.team_name
FROM survey_answers_cache sac
JOIN surveys s ON s.surveyId = sac.surveyid
JOIN subcluster sc ON s.subcluster_id = sc.subcluster_id
JOIN cluster c ON sc.cluster_id = c.cluster_id
JOIN user ON user.user_id = sac.user_id
JOIN questions q ON q.question_id = sac.question_id
JOIN division ON division.division_id = user.division_id
LEFT JOIN unit ON unit.unit_id = user.unit_id
LEFT JOIN department dpt ON dpt.department_id = user.department_id
LEFT JOIN team ON team.team_id = user.team_id
WHERE c.cluster_id=? AND sc.subcluster_id=? AND s.active=0 AND s.prepare=0
GROUP BY user.team_id, s.surveyId, q.cat
ORDER BY s.surveyId, user.team_id, q.cat ASC
我得到的问题是,当我得到正确的结果返回时,它会快速运行(假设为+ -500ms)但是当结果有两倍的行时,则需要超过5分钟然后导致504超时。 另一个问题是我自己没有创建这个数据库,所以我没有自己设置索引。我正在考虑改进这些,因此我使用了explain命令:
我看到很多主键和几个双索引,但我不确定这是否会对性能产生很大影响。
编辑:这段代码占用了所有执行时间:
$start_time = microtime(true);
$stmt = $conn->query($query); //query is simply the query above.
while ($row = $stmt->fetch_assoc()){
$resultSurveys["scores"][] = $row;
}
$stmt->close();
$end_time = microtime(true);
$duration = $end_time - $start_time; //value typically the execution time #reallyHigh...
所以我的问题 :是否可以(非常?)通过更改数据库密钥来提高查询性能,还是应该将查询分成多个较小的查询?
非常感谢任何帮助!
P.S。如果您认为我的问题遗漏了,请不要只是下载,而是在下面写下评论或建议编辑,我会尽力添加所需的信息!
答案 0 :(得分:1)
EXPLAIN结果显示出问题迹象
使用临时;使用filesort:ORDER BY需要创建临时表来进行排序。
用户表if
的第3行是ALL,type
和key
为NULL:表示每次都需要扫描整个表以检索结果。
建议:
ref
数据库(跨数据库查询)。PS:查询优化是一门需要耐心和努力的艺术。没有银弹。 欢迎来到优化MySQL的精美艺术!
答案 1 :(得分:1)
你可以尝试这样的事情(虽然我不适合测试这个)
SELECT
sac.surveyId,
q.cat,
SUM((sac.answer_id*q.weight))/SUM(q.weight) AS score,
user.division_id,
user.unit_id,
user.department_id,
user.team_id,
division.division_name,
unit.unit_name,
dpt.department_name,
team.team_name
FROM survey_answers_cache sac
JOIN
(
SELECT
s.surveyId,
sc.subcluster_id
FROM
surveys s
JOIN subcluster sc ON s.subcluster_id = sc.subcluster_id
JOIN cluster c ON sc.cluster_id = c.cluster_id
WHERE
c.cluster_id=? AND sc.subcluster_id=? AND s.active=0 AND s.prepare=0
) AS v ON v.surveyid = sac.surveyid
JOIN user ON user.user_id = sac.user_id
JOIN questions q ON q.question_id = sac.question_id
JOIN division ON division.division_id = user.division_id
LEFT JOIN unit ON unit.unit_id = user.unit_id
LEFT JOIN department dpt ON dpt.department_id = user.department_id
LEFT JOIN team ON team.team_id = user.team_id
GROUP BY user.team_id, v.surveyId, q.cat
ORDER BY v.surveyId, user.team_id, q.cat ASC
所以我希望我没有弄乱任何东西。
无论如何,这个想法是在内部查询中根据你的where条件只选择你需要的行。这将创建一个较小的tmp表,因为它只会提取2个字段。
然后在外部查询中,您将加入到实际从其中拉出其余数据的表,订单和组。这样,您就可以对较小的数据集进行排序和分组。而且你的where子句可以以最佳方式运行。
您甚至可以省略其中一些表作为您从其中一些表中提取的唯一数据,但却没有看到完整的架构以及它的相关性,这很难说。
但一般来说这部分(子查询)
SELECT
s.surveyId,
sc.subcluster_id
FROM
surveys s
JOIN subcluster sc ON s.subcluster_id = sc.subcluster_id
JOIN cluster c ON sc.cluster_id = c.cluster_id
WHERE
c.cluster_id=? AND sc.subcluster_id=? AND s.active=0 AND s.prepare=0
WHERE子句直接影响的是什么。看到这一点,我们可以优化这个部分,然后用它来加入你需要的其他数据。
从上面可以很容易地推断出删除表的示例,请考虑这个
SELECT
s.surveyId,
sc.subcluster_id
FROM
surveys s
JOIN subcluster sc ON s.subcluster_id = sc.subcluster_id
WHERE
sc.cluster_id=? AND sc.subcluster_id=? AND s.active=0 AND s.prepare=0
c
表cluster
从不用于从中提取数据,仅用于从哪里提取数据。所以不是
JOIN cluster c ON sc.cluster_id = c.cluster_id
WHERE
c.cluster_id=?
与
相同或相当于WHERE
sc.cluster_id=?
因此我们可以彻底消除这种联接。
答案 2 :(得分:0)
我认为当您添加此问题时会发生问题:
JOIN user ON user.cluster_id = sc.subcluster_id
JOIN survey_answers_cache sac ON (sac.surveyId = s.surveyId AND sac.user_id = user.user_id)
额外条件sac.user_id = user.user_id可能很容易不一致。
您可以尝试使用用户表进行第二次加入吗?
概率pd。你可以添加一个" SHOW CREATE TABLE"