慢查询:这个例子的实际解决方案?

slow queries: a practical solution to this example?

我刚刚下载了我的慢查询日志 经常显示的一个查询是

select * from feedback_to_user
left join user_tb on  feedback_to_user.feedbacker_id = user_tb.user_id
left join user_to_photo on  feedback_to_user.feedbacker_id = user_to_photo.user_id
where  feedback_to_user.feedbackee_id="7375"    
AND user_tb.admin_review = "1"  
AND user_tb.user_published = "1"    
AND user_tb.user_active = "1"        
AND user_tb.user_verified = "1"             
order by  feedback_to_user.ftu_id DESC;

那我该如何解决呢?是语法还是在 phpmyadmin 中?

请用EXPLAIN分析一下,见:

http://dev.mysql.com/doc/refman/5.7/en/using-explain.html

遗憾的是,我们不知道您的 table 结构行计数和索引,但您应该从优化开始阅读:

http://dev.mysql.com/doc/refman/5.7/en/select-optimization.html

正如 Patrick 已经建议的那样,您应该使用 EXPLAIN。

但一般来说,您应该考虑以下几点(按查询检查顺序):

select * from feedback_to_user...

真的有必要 select 所有 带有那个星号的字段吗? 也许你只需要几个。让大量数据飞来飞去只是为了忽略 and/or 丢弃是没有意义的;首先最好不要 select 他们。此外,这种方式 MySQL 将更好地估计实际检索成本,并可能更好地优化查询(稍后参见覆盖索引)。

left join user_tb on feedback_to_user.feedbacker_id = user_tb.user_id

您是否希望不成为 feedbacker_id 中的任何用户,以便该行的所有 user_tb 字段都为 NULL,您仍然需要该行吗? 如果不是,则使用直接 JOIN(不是 LEFT JOIN)。改进可能可以忽略不计——但它们仍然是免费的(出于同样的原因,如果您有疑问,请保留 LEFT JOIN)。

left join user_to_photo on feedback_to_user.feedbacker_id = user_to_photo.user_id

同上。您只需要 行和 一张照片吗?如果是,加入。

where feedback_to_user.feedbackee_id="7375"
AND user_tb.admin_review = "1"
AND user_tb.user_published = "1"
AND user_tb.user_active = "1"
AND user_tb.user_verified = "1"

所有这些字段都是VARCHAR还是整数?如果您只在其中存储整数(和偶尔的 NULL),那么拥有一个整数数据字段将产生不错的收益。如果您将它们用作标志,那么 TINYINT 可能(也可能不会)进一步提高性能。也可以研究位域。

但是,如果您有很多这样的查询,最好在 user_tb 上使用您要查询的字段创建一个索引:

CREATE INDEX user_db_flags 
ON user_tb(admin_review, 
           user_published,
           user_active,
           user_verified);

您也可以尝试向其中添加您在 JOIN 中使用的 user_id 字段:

-- remove previous index
ALTER TABLE user_tb DROP INDEX user_db_flags;

-- add index
CREATE INDEX user_db_flags 
ON user_tb(user_id,
           admin_review, 
           user_published,
           user_active,
           user_verified);

feedback_to_user 上的索引:

CREATE INDEX feedback_to_user_id 
        ON feedback_to_user(feedbacker_id, feedbackee_id, ftu_id);

您也可以尝试交换这些位置:

CREATE INDEX feedback_to_user_id 
        ON feedback_to_user(feedbackee_id, feedbacker_id, ftu_id);

这将有助于MySQL摆脱冗余信息并快速找到您需要的信息。

如果 JOINed table 中的一个只有很少、非常小的场,并且 selection 非常精确(例如 feedback_to_user如果你 select 一个 feedbackee_id),你可能会使用 "covering index",即一个索引,其中包含你在第一个位置搜索的字段,以及你需要的字段在下一个位置.特别是如果 table 有许多其他更大的字段,这允许 MySQL 在索引 上查询 而根本不需要加载 table。如果索引比 table 足够小,速度增益可能会很大。否则,不要打扰 -- 维护索引也是有成本的。