2017-04-20 76 views
0

我一直在使用相同的SQL查询几个小时,它终于工作。但是,这是非常缓慢..我一直在试图优化它,但没有运气,任何帮助。下面是该查询(批号的左连接...):股票与缓慢的SQL查询

$sql ="SELECT u.id, u.display_name, IFNULL(SUM(r.total_rating)/COUNT(r.total_rating), 0) AS avg_rating, s.title AS study FROM users u 
    LEFT JOIN rating r ON u.id = r.user_id 
    LEFT JOIN usermeta m ON u.id = m.user_id 
    LEFT JOIN usermeta m1 ON u.id = m1.user_id 
    LEFT JOIN studies s ON m.meta_value = s.id 
    WHERE m.meta_key = 'study' AND m1.meta_key = 'subjects' AND m1.meta_value REGEXP '$subjectsvalues' 
    GROUP BY u.id, r.total_rating 
    ORDER BY avg_rating DESC 
    LIMIT 10"; 

表结构,用户表:

id | display_name | email 
------------------------- 
1 | Khar   | ... 
2 | SantaCruz | ... 

表结构的评价表:

id | rating_title | total_rating | user_id 
------------------------------------------- 
1 | dffd   | 5    | 1 
2 | fddfdffdd | 4    | 1 

的表结构usermeta表格:

id | user_id | meta_key | meta_value 
------------------------------------- 
1 | 1  | study  | 132 
2 | 1  | subjects | 121,231 

为研究表表结构:

id | title 
---------- 
1 | dsdsf 
2 | sdfdf 

主题值,像这样的处理:

$subjectsvalues = ''; 

$subjects = explode(",", $subjects); 
foreach($subjects as $val) { 
    $subjectsvalues = $subjectsvalues.",".$val.",|"; 
} 
$subjectsvalues = $subjectsvalues."notdata"; 
+0

这是很多左连接。请编辑您的问题以包含表格的表格结构以及您的预期结果。 –

+0

嗨@JenR,我已更新帖子,谢谢! –

+0

你确定查询结果是否正确?您正在按'r.total_rating'进行分组,并在同一列上计算“SUM”和“COUNT”agreggates。我认为这个分组应该放在'u.id,u.display_name,s.title' – Xint0

回答

0

首先,left join s为不必要的。所以,试试这个:

SELECT u.id, u.display_name, AVG(r.total_rating) AS avg_rating, s.title AS study 
FROM users u JOIN 
    rating r 
    ON u.id = r.user_id JOIN 
    usermeta m 
    ON u.id = m.user_id JOIN 
    usermeta m1 
    ON u.id = m1.user_id JOIN 
    studies s 
    ON m.meta_value = s.id 
WHERE m.meta_key = 'study' AND m1.meta_key = 'subjects' AND m1.meta_value REGEXP '$subjectsvalues' 
GROUP BY u.id, r.total_rating 
ORDER BY avg_rating DESC 
LIMIT 10; 

然后,我会倾向于尝试usermeta(meta_key, user_id, meta_value)指标。我假设表中的主要ID都是主键。

+0

好的,我明白了。我会给它一个镜头,谢谢一堆!顺便说一句,我已更新帖子,以包括表结构。 –

+0

嗨戈登,我已更新帖子,包括表结构和$ subjectvalues变量。我将如何去索引? –

0

我不能建议编辑Gordon Linoff的答案,所以这是一个改进版本。你不需要joinusermeta两次,除非usermeta正在与自己比较。

SELECT u.id, u.display_name, AVG(r.total_rating) AS avg_rating, s.title AS study 
FROM users u JOIN 
    rating r 
    ON u.id = r.user_id JOIN 
    usermeta m 
    ON u.id = m.user_id JOIN 
    studies s 
    ON m.meta_value = s.id 
WHERE m.meta_key = 'study' OR (m.meta_key = 'subjects' AND m.meta_value REGEXP '$subjectsvalues') 
GROUP BY u.id, r.total_rating 
ORDER BY avg_rating DESC 
LIMIT 10; 

另外,你能解释一下你的正则表达式的效用吗?它很可能不会与$任何内容匹配,表明该模式的结束位于正则表达式的开始位置。

+0

感谢您的回答!非常有帮助,$ subjectvalues是一个包含我们正在搜索的主题ID的变量。例如。 ,142213。 –

+0

您应该为问题添加[tag:PHP]标签。 –

+0

我已经添加了一个php标记,谢谢! –