我的 Sql 查询非常慢(60秒),有人有改进的想法吗?
我的查询很慢。我正在 3 张桌子之间搜索。 Se_movies = 80000 条记录,se_movie_contenttags=160 万条记录,se_movie_descriptiontags -200000 条记录
两个简化查询。
OR - 慢
SELECT SQL_NO_CACHE count(movie_id)
FROM se_movies LEFT JOIN se_users ON se_movies.movie_user_id=se_users.user_id
LEFT JOIN
(
SELECT did , cid , ifnull(cid,did) as uid FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
LEFT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
ON dtag.did=ctag.cid
UNION
SELECT did , cid , ifnull(cid,did) as uid FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
RIGHT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
ON dtag.did=ctag.cid
)
AS tagobjects ON se_movies.movie_id=tagobjects.uid
WHERE ( se_movies.movie_title LIKE '%dog%') **OR** ( (cid IS NOT NULL or did IS NOT NULL) and uid IS NOT NULL )
AND - 快
SELECT SQL_NO_CACHE count(movie_id)
FROM se_movies LEFT JOIN se_users ON se_movies.movie_user_id=se_users.user_id
LEFT JOIN
(
SELECT did , cid , ifnull(cid,did) as uid FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
LEFT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
ON dtag.did=ctag.cid
UNION
SELECT did , cid , ifnull(cid,did) as uid FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
RIGHT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
ON dtag.did=ctag.cid
)
AS tagobjects ON se_movies.movie_id=tagobjects.uid
WHERE ( se_movies.movie_title LIKE '%dog%') **AND** ( (cid IS NOT NULL or did IS NOT NULL) and uid IS NOT NULL )
每个人单独,
( se_movies.movie_title LIKE '%dog%') - around 300
(cid IS NOT NULL or did IS NOT NULL) and uid IS NOT NULL - return 595
但如果他们中的任何人返回大约 50 或更少,则速度很快。
基本上,如果任何关键字在每个标签和电影表标题中的值超过 500,则需要 60 秒,
否则需要 2.3 秒。
有更好的办法吗?
我知道你可以在这两者之间进行 UNION... 和 AND 对于其他东西...
搜索标题 OR ( contenttag 或 desctag )
问题是查询的变体太多...
如果数据位于两个不同的表中,执行 OR 是否有问题?无论如何要加快他们的速度?
谢谢。
系统 - mysql apache2 php5 ubuntu - 亚马逊 aws。
解释 在此处输入链接说明
已解决IT BY
SELECT SQL_NO_CACHE 计数(movie_id) FROM se_movies LEFT JOIN se_users ON se_movies.movie_user_id=se_users.user_id 内连接 ( SELECT tag_object_id AS movieid FROM se_movie_contenttags WHERE tag_name IN ('dog') 联盟 选择 tag_object_id AS movieid FROM se_movie_descriptiontags WHERE tag_name IN ('dog') 联盟 SELECT s1.movie_id AS movieid FROM se_movies as s1 WHERE s1.movie_title LIKE '%dog%' 联盟 SELECT s2.movie_id AS movieid FROM se_movies as s2 WHERE s2.movie_desc LIKE '%dog%' ) AS tagobjects ON se_movies.movie_id=tagobjects.movi
eid .5sec
My query is slow. I am searching between 3 tables. Se_movies = 80000 records , se_movie_contenttags=1.6 mil records , se_movie_descriptiontags -200000 records
two simplified queries.
OR - SLOW
SELECT SQL_NO_CACHE count(movie_id)
FROM se_movies LEFT JOIN se_users ON se_movies.movie_user_id=se_users.user_id
LEFT JOIN
(
SELECT did , cid , ifnull(cid,did) as uid FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
LEFT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
ON dtag.did=ctag.cid
UNION
SELECT did , cid , ifnull(cid,did) as uid FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
RIGHT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
ON dtag.did=ctag.cid
)
AS tagobjects ON se_movies.movie_id=tagobjects.uid
WHERE ( se_movies.movie_title LIKE '%dog%') **OR** ( (cid IS NOT NULL or did IS NOT NULL) and uid IS NOT NULL )
AND - Fast
SELECT SQL_NO_CACHE count(movie_id)
FROM se_movies LEFT JOIN se_users ON se_movies.movie_user_id=se_users.user_id
LEFT JOIN
(
SELECT did , cid , ifnull(cid,did) as uid FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
LEFT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
ON dtag.did=ctag.cid
UNION
SELECT did , cid , ifnull(cid,did) as uid FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
RIGHT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
ON dtag.did=ctag.cid
)
AS tagobjects ON se_movies.movie_id=tagobjects.uid
WHERE ( se_movies.movie_title LIKE '%dog%') **AND** ( (cid IS NOT NULL or did IS NOT NULL) and uid IS NOT NULL )
each one alone
( se_movies.movie_title LIKE '%dog%') - around 300
(cid IS NOT NULL or did IS NOT NULL) and uid IS NOT NULL - return 595
but it is fast if anyone of them return around 50 or less.
Basically if any keyword has above 500 in each tags and movie table title...it takes 60 sec
otherwise 2.3 sec.
is there a better way ?
i know u can do UNION between these two...
and AND for other stuff...
Search- title OR ( contenttag or desctag )
Issue is too many variations of the query...
Is it problem doing OR if the data is in two different tables? Anyway to speed them up?.
Thanks.
System - mysql apache2 php5 ubuntu - amazon aws.
Explain
enter link description here
SOLVED IT BY
SELECT SQL_NO_CACHE count(movie_id)
FROM se_movies LEFT JOIN se_users ON se_movies.movie_user_id=se_users.user_id
INNER JOIN
( SELECT tag_object_id AS movieid FROM se_movie_contenttags WHERE tag_name IN ('dog')
UNION
SELECT tag_object_id AS movieid FROM se_movie_descriptiontags WHERE tag_name IN ('dog')
UNION
SELECT s1.movie_id AS movieid FROM se_movies as s1 WHERE s1.movie_title LIKE '%dog%'
UNION
SELECT s2.movie_id AS movieid FROM se_movies as s2 WHERE s2.movie_desc LIKE '%dog%'
)
AS tagobjects ON se_movies.movie_id=tagobjects.movieid
.5sec
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果
se_movie_descriptiontags
和se_movie_contenttags
包含成对的(movie_id, tag)
并且您想要包含具有特定标签的所有电影,我将替换 < code>tagobjects 内联视图:此查询将返回在任何或两个
se_movie_descriptiontags
和 中具有标签“dog”的电影 IDse_movie_contenttags
表。然后您可以在主查询上删除OR ((cid IS NOT NULL OR did IS NOT NULL) AND uid IS NOT NULL)
。最终的完整查询将是:
另外,请注意
(se_movies.movie_title LIKE '%dog%')
本身就是一个性能杀手,因为它无法通过使用上的索引来优化>movie_title
列,肯定会引起表扫描。这主要是因为条件以通配符开头。对于这种类型的场景,我建议研究 MySQL 的全文搜索功能。If
se_movie_descriptiontags
andse_movie_contenttags
contain pairs of(movie_id, tag)
and you want to include all movies that have certain tags, I would replace thetagobjects
in-line view with:This query will return the movie ids that have the tag 'dog' in any or both
se_movie_descriptiontags
andse_movie_contenttags
tables. And then you can get rid ofOR ((cid IS NOT NULL OR did IS NOT NULL) AND uid IS NOT NULL)
on the main query.The final full query would be:
Also, note that
(se_movies.movie_title LIKE '%dog%')
alone is a performance killer, because it can't be optimized by using an index on themovie_title
column, and will certainly cause a table scan. This is mainly due to the fact that the condition starts with a wildcard. For this type of scenario I would suggest looking into full-text search capabilities of MySQL.