编写MySQL查询的更有效方法?

时间:2011-10-05 21:57:12

标签: mysql optimization

我的网站突然开始吐出以下错误:

  

“表'/tmp/#sql_645a_1.MYI'的密钥文件不正确;尝试修复它”

我删除它,该网站工作正常。

我的服务器技术支持人员建议我清理查询并提高效率。

以下是查询:

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

非常感谢任何帮助。也许可以通过JOIN来完成?

非常感谢,

斯科特

更新:这是工作查询,我仍然觉得它可以优化。

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

3 个答案:

答案 0 :(得分:3)

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);

如果社区帖子不必拥有用户和主题,则对最后两个联接使用LEFT JOIN。

您需要为cpk子查询创建支持索引:

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

此查询必须是最快的,因为cpk子查询一直只能获得五个键。

更新2011-10-10 16:28美国东部时间

此查询消除了不明确的topic_id问题:

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;

答案 1 :(得分:0)

  • 您可以减少所选字段的数量。

      

    *运算符将选择所有(3)表中的所有字段。这可能会变得很大。那说,   我认为mysql非常聪明,可以将这个计划放在一边,这样就不需要为所选择的5行访问除了之外的数据页。

  • 您确定所有涉及的(外国)密钥都已编入索引吗?

这是我的刺:

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

答案 2 :(得分:0)

然后用于排序数据的临时表可能会变得太大。我已经看到这种情况发生在/ tmp /空间不足时。 LIMIT子句不会使它更快或更容易,因为必须首先对完整数据集进行排序。

在某些情况下,MySQL不使用临时表对数据进行排序。您可以在此处阅读:http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html

如果您设法满足正确的条件(通常使用正确的索引),它也会查询您的查询。

如果这没有帮助(在某些情况下你无法摆脱繁重的排序),试着找出/ tmp /上有多少可用空间,看看它是否可以扩展。此外,如上所述,仅选择所需的列(而不是*)可以使临时表更小并且无论如何都被认为是最佳实践(因此使用显式JOIN而不是隐式JOIN)。