开发者

More Efficient Way To Write MySQL Query?

My site has suddenly started spitting out the following error:

"Incorrect key file for table '/tmp/#sql_645a_1.M开发者_运维知识库YI'; try to repair it"

I remove it, the site works fine.

My server tech support guys suggest I clean up the query and make it more efficient.

Here's the query:

SELECT *, FROM_UNIXTIME(post_time, '%Y-%c-%d %H:%i') as posttime 
FROM communityposts, communitytopics, communityusers 
WHERE communityposts.poster_id=communityusers.user_id 
AND communityposts.topic_id=communitytopics.topic_id 
ORDER BY post_time DESC LIMIT 5

Any help is greatly appreciated. Perhaps can be done with a JOIN?

Many thanks,

Scott

UPDATE: Here's the working query, I still feel it could be optimised though.

SELECT
    communityposts.post_id, communityposts.topic_id, communityposts.post_time,
    communityusers.user_id, , communitytopics.topic_title, communityusers.username,
    communityusers.user_avatar, 
    FROM_UNIXTIME(post_time, '%Y-%c-%d %H:%i') as post time 
FROM
    communityposts,
    communitytopics,
    communityusers
WHERE 
    communityposts.poster_id=communityusers.user_id
    AND communityposts.topic_id=communitytopics.topic_id
ORDER BY post_time DESC LIMIT 5


SELECT
    A.*,B.*,C.*,FROM_UNIXTIME(post_time, '%Y-%c-%d %H:%i') as posttime  
FROM
    (
        SELECT id,poster_id,topic_id
        FROM communityposts
        ORDER BY post_time DESC
        LIMIT 5
    ) cpk
    INNER JOIN communityposts A USING (id)
    INNER JOIN communityusers B ON cpk.poster_id=B.user_id
    INNER JOIN communitytopics C USING (topic_id);

If a community post does not have to have a user and a topic, then use LEFT JOINs for the last two joins.

You will need to create a supporting index for the cpk subquqery:

ALTER TABLE communityposts ADD INDEX (posttime,id,poster_id,topic_id);

This query has to be the fastest because the cpk subquery only gets five keys ALL THE TIME.

UPDATE 2011-10-10 16:28 EDT

This query eliminiates the ambiguous topic_id issue:

SELECT
    A.post_id, cpk.topic_id, A.post_time,
    B.user_id, C.topic_title, B.username,
    B.user_avatar, 
    FROM_UNIXTIME(post_time, '%Y-%c-%d %H:%i') as posttime  
FROM
    (
        SELECT id,poster_id,topic_id
        FROM communityposts
        ORDER BY post_time DESC
        LIMIT 5
    ) cpk
    INNER JOIN communityposts A USING (id)
    INNER JOIN communityusers B ON cpk.poster_id=B.user_id
    INNER JOIN communitytopics C ON cpk.topic_id=C.topic_id;


Then temp table used for sorting the data probably gets too big. I have seen this happen when the /tmp/ runs out of space. The LIMIT clause does not make it any quicker or easier, as the sorting of the full data set has to be done first.

Under some conditions, MySQL does not use a temp table to sort data. You can read about it here: http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html

If you manage to meet the right conditions (mostly use the correct indexes), it will also peed up your query.

If this doesn't help (in some cases you can't escape the heavy sorting), try to find out how much free space there is on /tmp/, and see if it can be expanded. Also, as sehe mentioned, selecting only the needed columns (instead of *) can make the temp table smaller and is considered best practice anyway (and so is using explicit JOINs instead of implicit ones).


  • You could reduce the number of fields selected.

    The * operator will select all fields from all (3) tables. This may get big. That said, I think mysql is smart enough to lay this plan out so that it doesn't need to access the data pages except for the 5 rows being selected.

  • Are you sure that all the involved (foreign) keys are indexed?

Here's my stab:

SELECT posts.*, FROM_UNIXTIME(post_time, '%Y-%c-%d %H:%i') as posttime 
FROM communityposts posts
     INNER JOIN communitytopics topics ON posts.topic_id = topics.topic_id
     INNER JOIN communityusers users ON posts.poster_id = users.user_id
ORDER BY post_time DESC LIMIT 5
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜