我的 Sql 查询非常慢(60秒),有人有改进的想法吗?

发布于 2024-11-08 17:25:54 字数 3206 浏览 0 评论 0原文

我的查询很慢。我正在 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.movi​​e_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.movi​​e_id AS movieid FROM se_movies as s1 WHERE s1.movi​​e_title LIKE '%dog%' 联盟 SELECT s2.movi​​e_id AS movieid FROM se_movies as s2 WHERE s2.movi​​e_desc LIKE '%dog%' ) AS tagobjects ON se_movies.movi​​e_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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

Oo萌小芽oO 2024-11-15 17:25:54

如果 se_movie_descriptiontagsse_movie_contenttags 包含成对的 (movie_id, tag) 并且您想要包含具有特定标签的所有电影,我将替换 < code>tagobjects 内联视图:

SELECT `tag_object_id` AS `uid` FROM `se_movie_descriptiontags`
WHERE `tag_name` IN ('dog')
UNION
SELECT `tag_object_id` FROM `se_movie_contenttags`
WHERE `tag_name` IN ('dog')

此查询将返回在任何或两个 se_movie_descriptiontags 和 中具有标签“dog”的电影 ID se_movie_contenttags 表。然后您可以在主查询上删除 OR ((cid IS NOT NULL OR did IS NOT NULL) AND uid IS NOT NULL)

最终的完整查询将是:

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 `uid` FROM `se_movie_descriptiontags`
        WHERE `tag_name` IN ('dog')
        UNION
        SELECT `tag_object_id` FROM `se_movie_contenttags`
        WHERE `tag_name` IN ('dog')
    ) AS tagobjects ON se_movies.movie_id=tagobjects.uid
WHERE (se_movies.movie_title LIKE '%dog%')

另外,请注意 (se_movies.movi​​e_title LIKE '%dog%') 本身就是一个性能杀手,因为它无法通过使用 上的索引来优化>movie_title 列,肯定会引起表扫描。这主要是因为条件以通配符开头。对于这种类型的场景,我建议研究 MySQL 的全文搜索功能。

If se_movie_descriptiontags and se_movie_contenttags contain pairs of (movie_id, tag) and you want to include all movies that have certain tags, I would replace the tagobjects in-line view with:

SELECT `tag_object_id` AS `uid` FROM `se_movie_descriptiontags`
WHERE `tag_name` IN ('dog')
UNION
SELECT `tag_object_id` FROM `se_movie_contenttags`
WHERE `tag_name` IN ('dog')

This query will return the movie ids that have the tag 'dog' in any or both se_movie_descriptiontags and se_movie_contenttags tables. And then you can get rid of OR ((cid IS NOT NULL OR did IS NOT NULL) AND uid IS NOT NULL) on the main query.

The final full query would be:

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 `uid` FROM `se_movie_descriptiontags`
        WHERE `tag_name` IN ('dog')
        UNION
        SELECT `tag_object_id` FROM `se_movie_contenttags`
        WHERE `tag_name` IN ('dog')
    ) AS tagobjects ON se_movies.movie_id=tagobjects.uid
WHERE (se_movies.movie_title LIKE '%dog%')

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 the movie_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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文