[英]Mysql - help me optimize this query (improved question)
About the system: - There are tutors who create classes and packs - A tags based search approach is being followed.Tag relations are created when new tutors register and when tutors create packs (this makes tutors and packs searcheable). 关于系统: -有辅导老师创建班级和课程包-遵循基于标签的搜索方法。当新辅导老师注册并在辅导老师创建课程包时会创建标签关系(这使辅导老师和课程包可搜索)。 For details please check the section How tags work in this system ?
有关详细信息,请检查标签在此系统中如何工作 ? below.
下面。
Following is the concerned query 以下是相关查询
SELECT SUM(DISTINCT( t.tag LIKE "%Dictatorship%" )) AS key_1_total_matches,
SUM(DISTINCT( t.tag LIKE "%democracy%" )) AS key_2_total_matches,
COUNT(DISTINCT( od.id_od )) AS tutor_popularity,
CASE
WHEN ( IF(( wc.id_wc > 0 ), ( wc.wc_api_status = 1
AND wc.wc_type = 0
AND wc.class_date > '2010-06-01 22:00:56'
AND wccp.status = 1
AND ( wccp.country_code = 'IE'
OR wccp.country_code IN ( 'INT' )
) ), 0)
) THEN 1
ELSE 0
END AS 'classes_published',
CASE
WHEN ( IF(( lp.id_lp > 0 ), ( lp.id_status = 1
AND lp.published = 1
AND lpcp.status = 1
AND ( lpcp.country_code = 'IE'
OR lpcp.country_code IN ( 'INT' )
) ), 0)
) THEN 1
ELSE 0
END AS 'packs_published',
td . *,
u . *
FROM tutor_details AS td
JOIN users AS u
ON u.id_user = td.id_user
LEFT JOIN learning_packs_tag_relations AS lptagrels
ON td.id_tutor = lptagrels.id_tutor
LEFT JOIN learning_packs AS lp
ON lptagrels.id_lp = lp.id_lp
LEFT JOIN learning_packs_categories AS lpc
ON lpc.id_lp_cat = lp.id_lp_cat
LEFT JOIN learning_packs_categories AS lpcp
ON lpcp.id_lp_cat = lpc.id_parent
LEFT JOIN learning_pack_content AS lpct
ON ( lp.id_lp = lpct.id_lp )
LEFT JOIN webclasses_tag_relations AS wtagrels
ON td.id_tutor = wtagrels.id_tutor
LEFT JOIN webclasses AS wc
ON wtagrels.id_wc = wc.id_wc
LEFT JOIN learning_packs_categories AS wcc
ON wcc.id_lp_cat = wc.id_wp_cat
LEFT JOIN learning_packs_categories AS wccp
ON wccp.id_lp_cat = wcc.id_parent
LEFT JOIN order_details AS od
ON td.id_tutor = od.id_author
LEFT JOIN orders AS o
ON od.id_order = o.id_order
LEFT JOIN tutors_tag_relations AS ttagrels
ON td.id_tutor = ttagrels.id_tutor
JOIN tags AS t
ON ( t.id_tag = ttagrels.id_tag )
OR ( t.id_tag = lptagrels.id_tag )
OR ( t.id_tag = wtagrels.id_tag )
WHERE ( u.country = 'IE'
OR u.country IN ( 'INT' ) )
AND CASE
WHEN ( ( t.id_tag = lptagrels.id_tag )
AND ( lp.id_lp > 0 ) ) THEN lp.id_status = 1
AND lp.published = 1
AND lpcp.status = 1
AND ( lpcp.country_code = 'IE'
OR lpcp.country_code IN (
'INT'
) )
ELSE 1
END
AND CASE
WHEN ( ( t.id_tag = wtagrels.id_tag )
AND ( wc.id_wc > 0 ) ) THEN wc.wc_api_status = 1
AND wc.wc_type = 0
AND
wc.class_date > '2010-06-01 22:00:56'
AND wccp.status = 1
AND ( wccp.country_code = 'IE'
OR wccp.country_code IN (
'INT'
) )
ELSE 1
END
AND CASE
WHEN ( od.id_od > 0 ) THEN od.id_author = td.id_tutor
AND o.order_status = 'paid'
AND CASE
WHEN ( od.id_wc > 0 ) THEN od.can_attend_class = 1
ELSE 1
END
ELSE 1
END
AND ( t.tag LIKE "%Dictatorship%"
OR t.tag LIKE "%Democracy%" )
GROUP BY td.id_tutor
HAVING key_1_total_matches = 1
AND key_2_total_matches = 1
ORDER BY tutor_popularity DESC,
u.surname ASC,
u.name ASC
LIMIT 0, 20
The problem 问题
The results returned by the above query are correct (AND logic working as per expectation), but the time taken by the query rises alarmingly for heavier data and for the current data I have it is like 25 seconds as against normal query timings of the order of 0.005 - 0.0002 seconds, which makes it totally unusable. 以上查询返回的结果是正确的(AND逻辑按预期工作),但是对于较重的数据,查询所花费的时间令人震惊地增加,对于我拥有的当前数据,该查询的时间大约为25秒(与订单的正常查询时间相比) 0.005-0.0002秒,这使其完全无法使用。
It is possible that some of the delay is being caused because all the possible fields have not yet been indexed. 由于尚未索引所有可能的字段,因此可能导致某些延迟。 The tag field of tags table is indexed.
标签表的标签字段已建立索引。 Is there something faulty with the query?
查询有问题吗? What can be the reason behind 20+ seconds of execution time?
超过20秒的执行时间会是什么原因?
How tags work in this system? 标签在此系统中如何工作?
The explain query output:- Please see this screenshot - http://www.test.examvillage.com/Explain_query.jpg 说明查询输出:-请参见此屏幕截图-http: //www.test.examvillage.com/Explain_query.jpg
You may see if it helps adding indexes on following fields: 您可能会看到它是否有助于在以下字段上添加索引:
lptagrels.id_tutor
wtagrels.id_tutor
od.id_author
and then try to get rid of the case-when
structures from the where clause. 然后尝试从where子句中删除
case-when
结构。 You can add some table specific restrictions directly to join like: left join t2 on t1.id = t2.id AND ...
to make code more readable. 您可以直接添加一些特定于表的限制来
left join t2 on t1.id = t2.id AND ...
例如: left join t2 on t1.id = t2.id AND ...
以使代码更具可读性。
EDIT: Seems you have a wrong approach here: you search for all tags and then count the tags that match search. 编辑:似乎您在这里有一个错误的方法:搜索所有标签,然后计算与搜索匹配的标签。 Instead you should search for tags that match and then count results that have these tags.
相反,您应该搜索匹配的标签,然后计算具有这些标签的结果。
I've recently had a similar problem. 我最近也遇到过类似的问题。 I had to modify a query to implement a new feature, and that meant adding several joins and left joins.
我必须修改查询以实现新功能,这意味着要添加多个联接和左联接。 The logic was correctly implemented, but it took forever with some bigger tables.
该逻辑已正确实现,但它用了一些更大的表。
The solution was a complete rewrite, as Brian suggests. 正如Brian所建议的,该解决方案是一个完整的重写。
My new approach was something like this: 我的新方法是这样的:
All this was done in a stored procedure, the end result has passed unit tests, and is blazing fast. 所有这些都是在存储过程中完成的,最终结果已经通过了单元测试,并且发展迅速。
UPDATE UPDATE
Please test this query, to see if it returns the same results as the original. 请测试此查询,以查看其返回的结果是否与原始查询相同。 If it does, then I will further try to find a better implementation.
如果可以,那么我将进一步尝试找到更好的实现。
SELECT SUM(DISTINCT( t.tag LIKE "%Dictatorship%" )) AS key_1_total_matches,
SUM(DISTINCT( t.tag LIKE "%democracy%" )) AS key_2_total_matches,
COUNT(DISTINCT( od.id_od )) AS tutor_popularity,
(wc.id_wc > 0
AND wc.wc_api_status = 1
AND wc.wc_type = 0
AND wc.class_date > '2010-06-01 22:00:56'
AND wccp.status = 1
AND ( wccp.country_code = 'IE' OR wccp.country_code IN ( 'INT' ))
) AS 'classes_published',
(lp.id_lp > 0
AND lp.id_status = 1
AND lp.published = 1
AND lpcp.status = 1
AND ( lpcp.country_code = 'IE' OR lpcp.country_code IN ( 'INT' ) )
) AS 'packs_published',
td . *,
u . *
FROM tutor_details AS td JOIN users AS u ON u.id_user = td.id_user
LEFT JOIN order_details AS od ON td.id_tutor = od.id_author
LEFT JOIN orders AS o ON od.id_order = o.id_order
LEFT JOIN learning_packs_tag_relations AS lptagrels ON td.id_tutor = lptagrels.id_tutor --
LEFT JOIN learning_packs AS lp ON lptagrels.id_lp = lp.id_lp
LEFT JOIN learning_packs_categories AS lpc ON lpc.id_lp_cat = lp.id_lp_cat
LEFT JOIN learning_packs_categories AS lpcp ON lpcp.id_lp_cat = lpc.id_parent
LEFT JOIN learning_pack_content AS lpct ON ( lp.id_lp = lpct.id_lp )
LEFT JOIN webclasses_tag_relations AS wtagrels ON td.id_tutor = wtagrels.id_tutor --
LEFT JOIN webclasses AS wc ON wtagrels.id_wc = wc.id_wc
LEFT JOIN learning_packs_categories AS wcc ON wcc.id_lp_cat = wc.id_wp_cat
LEFT JOIN learning_packs_categories AS wccp ON wccp.id_lp_cat = wcc.id_parent
LEFT JOIN tutors_tag_relations AS ttagrels ON td.id_tutor = ttagrels.id_tutor --
JOIN tags AS t ON ( t.id_tag = ttagrels.id_tag )
OR ( t.id_tag = lptagrels.id_tag )
OR ( t.id_tag = wtagrels.id_tag )
WHERE ( u.country = 'IE' OR u.country IN ( 'INT' ) )
AND (NOT ( t.id_tag = lptagrels.id_tag AND lp.id_lp > 0)
or (lp.id_status = 1
AND lp.published = 1
AND lpcp.status = 1
AND ( lpcp.country_code = 'IE' OR lpcp.country_code IN ('INT') )
)
)
AND (not (t.id_tag = wtagrels.id_tag AND wc.id_wc > 0 )
or (
wc.wc_api_status = 1
AND wc.wc_type = 0
AND wc.class_date > '2010-06-01 22:00:56'
AND wccp.status = 1
AND ( wccp.country_code = 'IE' OR wccp.country_code IN ('INT' ) )
)
)
AND (NOT (od.id_od > 0)
OR (
od.id_author = td.id_tutor
AND o.order_status = 'paid'
AND (NOT (od.id_wc > 0) OR od.can_attend_class = 1)
)
)
AND ( t.tag LIKE "%Dictatorship%" OR t.tag LIKE "%Democracy%" )
GROUP BY td.id_tutor
HAVING key_1_total_matches = 1
AND key_2_total_matches = 1
ORDER BY tutor_popularity DESC,
u.surname ASC,
u.name ASC
LIMIT 0, 20
Take this code out the back and shoot it. 将此代码取出来拍摄。
Then start again. 然后重新开始。
I'm not being flippant but this is horrific and you would do yourself and anyone else touching it in the future a big favour by getting rid of it right now. 我不是在轻描淡写,但是这太可怕了,您将自己和将来的任何其他人触摸它,现在就摆脱它会成为一个大忙。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.