开发者

Can anyone help me tame this unwieldy MySQL query before it gets worse?

I'm not very good at SQL, but I'm certainly learning.

So this one provides content for a couple of lists below wordpress posts. One is, "More popular articles from this user," and the other is "More popular articles in this category."

Articles can be published by editors, or submitted by logged in or anonymous users. It just checks all the articles to see whether they're from the same user, or under the same category as the post the list is being displayed for. When a user submits an article, it's still "posted by" whichever admin posted the article (since they must be approved first). So there's a separate db entry which is present when a user submits an article.

The basic structure:

select post_id, post_title, post_name, (
    //number of times this article has been
    //favorited, to help sort them
) as favorited, (
    //whether this article is from the same user
    select count(*) > 0 from wp_users //have to put something, it's just a flag
    where exists (
        //see if this post was authored by the the same开发者_StackOverflow社区 user(s)
        and not exists (
            //make sure it's not a user submitted article. If it is,
            //we want to group it by the submitting user, not the
            //approving editor
        )
    )
    or exists (
        //see if an 'original submitter username' exists for this post,
        //and if so, see if it matches the post we're generating the list for
    )
) as under_users, (
    //see if this post is under the same category
) as under_category

And my messy query:

select p.ID, p.post_title, p.post_name, (
  select count(*)
  from wp_usermeta as um
  where um.meta_key = 'wpfp_favorites'
  and POSITION(CONCAT("\"",p.ID,"\"") IN um.meta_value)
) as favorited, (
  select count(*) > 0 from wp_users
  where exists ( 
    select *
    from wp_terms as t, wp_term_taxonomy as tt, wp_term_relationships as tr
    where tt.taxonomy = 'author'
    and tr.object_id = p.ID
    and tr.term_taxonomy_id = tt.term_taxonomy_id
    and t.term_id = tt.term_id
    and t.term_id in (
      select t2.term_id
      from wp_terms as t2, wp_term_taxonomy as tt2, wp_term_relationships as tr2
      where tt2.taxonomy = 'author'
      and tr2.object_id = 535
      and tr2.term_taxonomy_id = tt2.term_taxonomy_id
      and t2.term_id = tt2.term_id
    )
    and not exists (
      select *
      from wp_postmeta as pm
      where pm.post_id = 535
      and pm.meta_key = 'Original Submitter Username'
    )
  )
  or exists (
    select *
    from wp_postmeta as pm
    where pm.post_id = p.ID
    and pm.meta_key = 'Original Submitter Username'
    and pm.meta_value = (
      select pm2.meta_value
      from wp_postmeta as pm2
      where pm2.post_id = 535
      and pm2.meta_key = 'Original Submitter Username'
    )
  )  
) as under_users, (
  select count(*) > 0 from wp_users
  where exists (
    select *
    from wp_terms as t, wp_term_taxonomy as tt, wp_term_relationships as tr
    where tt.taxonomy = 'category'
    and tr.object_id = p.ID
    and tr.term_taxonomy_id = tt.term_taxonomy_id
    and t.term_id = tt.term_id
    and t.term_id in (
      select t2.term_id
      from wp_terms as t2, wp_term_taxonomy as tt2, wp_term_relationships as tr2
      where tt2.taxonomy = 'category'
      and tr2.object_id = 535
      and tr2.term_taxonomy_id = tt2.term_taxonomy_id
      and t2.term_id = tt2.term_id
      and t2.term_id not in (3, 4)
    )
  )
) as under_category
from wp_posts as p
where p.post_type = 'post' 
and p.ID != 535
and p.post_status = 'publish'
having (
  under_users != 0
  or under_category != 0
)
order by favorited desc

I feel like it could be so much shorter, and better, but I don't know how to do it. I seem to be querying for the same things several times in the query and, I'm afraid to add anything else to it (differentiate between logged-in and anon submitters, sort articles by views as well as favorites, etc) lest it collapse in on itself and become a black hole.

Any tips to help me with this?


You might be better off splitting off some of these subqueries at the application level. You can then change your EXISTS clauses to EXISTS IN (ids...).

I've found that nested subqueries in MySQL tend to be horribly slow because of the number of rows that need to be examined at once. Breaking the subqueries on the application level allows you to employ caching, and gives you greater control of what your subqueries are doing, all while making your SQL easier to read.


Don't worry too much about your query being complicated. In real-world applications queries get like this. If it starts to become a problem (remember you can embed comments inside an SQL statement), you can create views that take care of some of the subqueries. For example your subquery for under_category. You could create a view thus...

create view under_category_view as
    select tr.object_id AS p_id
        from wp_terms              as t,
             wp_term_taxonomy      as tt,
             wp_term_relationships as tr
        where tt.taxonomy             = 'category'
              and tr.term_taxonomy_id = tt.term_taxonomy_id
              and t.term_id           = tt.term_id
              and t.term_id in (select t2.term_id
                                    from wp_terms              as t2,
                                         wp_term_taxonomy      as tt2,
                                         wp_term_relationships as tr2
                                    where tt2.taxonomy = 'category'
                                          and tr2.object_id = 535
                                          and tr2.term_taxonomy_id = tt2.term_taxonomy_id
                                          and t2.term_id = tt2.term_id
                                          and t2.term_id not in (3, 4));

and then in your big query you would use...

select count(*) > 0 from wp_users
  where exists (select *
                    from user_category_view
                    where p_id = p.id) as under_category

Incidentally, I find splitting lines vertically and using big indents as I have done here helps to make a chunky query easier to read.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜