2012-03-16 55 views
2

查询:按结果优化查询顺序使用filesort;

SELECT 
     r.reply_id, 
     r.msg_id, 
     r.uid, 
     r.body, 
     r.date, 
     u.username as username, 
     u.profile_picture as profile_picture 
    FROM 
     pm_replies as r 
     LEFT JOIN users as u 
      ON u.uid = r.uid 
    WHERE 
     r.msg_id = '784351921943772258' 

    ORDER BY r.date DESC 

我尝试了所有指标的组合我能想到的,在谷歌搜索如何尽我所能指数这一点,但没有奏效。

这个查询需要0,33上归还物品和计数 ...


说明:

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE r ALL  index1 NULL NULL NULL 540  Using where; Using filesort 
1 SIMPLE u eq_ref uid  uid  8 site.r.uid 1 

SHOW CREATE pm_replies

CREATE TABLE `pm_replies` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`reply_id` bigint(20) NOT NULL, 
`msg_id` bigint(20) NOT NULL, 
`uid` bigint(20) NOT NULL, 
`body` text COLLATE utf8_unicode_ci NOT NULL, 
`date` datetime NOT NULL, 
PRIMARY KEY (`id`), 
KEY `index1` (`msg_id`,`date`,`uid`) 
) ENGINE=MyISAM AUTO_INCREMENT=541 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

SHOW创建用户

CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT, 
`uid` bigint(20) NOT NULL, 
`username` varchar(20) COLLATE utf8_unicode_ci NOT NULL, 
`email` text CHARACTER SET latin1 NOT NULL, 
`password` text CHARACTER SET latin1 NOT NULL, 
`profile_picture` text COLLATE utf8_unicode_ci NOT NULL, 
`date_registered` datetime NOT NULL, 
PRIMARY KEY (`id`), 
UNIQUE KEY `uid` (`uid`), 
UNIQUE KEY `username` (`username`) 
) ENGINE=MyISAM AUTO_INCREMENT=2004 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 
+0

你可以添加'SHOW CREATE TABLE pm_replies','SHOW CREATE TABLE users','EXPLAIN SELECT <你的整个选择在这里>'的输出吗?除此之外,可能的索引将是'r.msg_id,r.uid',你会希望'u.uid'也有索引(最好唯一)。 – Konerak 2012-03-16 09:40:08

+0

@Konerak更新问题 – fxuser 2012-03-16 09:46:20

+0

你有索引u.uid,r.uid,r.msg_id和r.date吗?编辑:我看到...尝试索引日期pm_replies – 2012-03-16 09:46:26

回答

0

请试试这个:

SELECT 
     r.reply_id, 
     r.msg_id, 
     r.uid, 
     r.body, 
     r.date, 
     u.username as username, 
     u.profile_picture as profile_picture 
    FROM 
     pm_replies as r 
     LEFT JOIN users as u 
      ON (u.uid = r.uid AND r.msg_id = '784351921943772258') 
    ORDER BY r.date DESC 

在我的情况下,它帮助。

+0

相同的加载时间。 – fxuser 2012-03-16 09:43:08

+1

这在功能上是不同的,而且很可能是不正确的。 OP根据'msg_id'从'pm_replies'中获取一组特定的行,然后将它们连接到'users'。 *(可能只是一行)*您从***_replies中取得所有***行,但只将它们连接到'用户'作为特定​​的'msg_id',所有其他所有行都通过,但是作为NULL。这不是一个答案。 – MatBailie 2012-03-16 09:43:41

+0

您是否为索引字段r.msg_id和r.date? – Mirodil 2012-03-16 09:44:20

5

对于查询,因为它是最好的指标,似乎是......

pm_replies: (msg_id, date, uid) 
users:  (uid) 

重要的一项是pm_replies。您可以使用它来过滤您的数据(首先是过滤器列),然后对数据进行排序(订单栏位于第二位)。

如果您删除了过滤器,则会有所不同。那么你只需要(date, uid)作为你的索引。

索引中的最后一个字段只是使其成为联接的一小部分,其重要部分实际上是users上的索引。

还有很多事情要说,关于这一点,至少在一本书中整整一章,如果你想要的话,还有几本书。但我希望这有助于。


编辑

这并不是说我对pm_replies建议的指数是一个指数涵盖三个方面,而不仅仅是三个指标。这确保索引中的所有条目都按这些列进行了预先排序。这就像在Excel中按三列分类数据一样。

有三个单独的索引就像有三个选项卡上的Excel数据。每个按不同的字段排序。

只有在三个字段上有一个索引才会得到此行为...
- 你可以用相同的MSG_ID
选择一个记录“一堆” - 这整个“一堆”是彼此相邻,没有间隙,等
- 即整个“一堆”日期顺序排列为MSG_ID
- 对于具有相同日期的任何行,它们是由USER_ID下令

(同样user_ID的一部分真的是很微小的。)

+1

+1,日期是我认为的关键。 – davidethell 2012-03-16 09:55:11

+0

所以你说要创建3列3索引?如果是这样,这似乎仍然没有帮助。 – fxuser 2012-03-16 09:59:16

+0

已更新EXPLAIN和SHOW CREATE TABLE的回复 – fxuser 2012-03-16 10:06:42

0

日期加到您的索引1键,以便MSG_ID和日期都是该指数。

+0

仍然没有任何变化 – fxuser 2012-03-16 09:56:52

0

什么Dems is saying应该是正确的,但有一个额外的细节,如果你正使用InnoDB:也许你付出的secondary indexes on clustered tables价格 - 从本质上讲,通过二级索引访问行需要额外查找槽小学,即聚类索引。这种“双查找”可能会使索引对查询优化器的吸引力下降。

为了缓解这个问题,尝试covering所有字段在SELECT语句与指数:

pm_replies: (msg_id, date, uid, reply_id, body, date) 
users:  (uid, username, profile_picture) 
+0

我所有的表都是myisam,我改为innodb只是为了测试dems的评论。 – fxuser 2012-03-16 11:34:31

+0

@fxuser还有一件事:您是否尝试过使用索引pm_replies:(msg_id,uid)',因为这是一个左连接,'users'是“外”表。另外,你是否尝试移除LEFT,只是为了看看会发生什么? – 2012-03-16 12:18:25

+0

@fxuser甚至是'pm_replies:(uid,msg_id)'? – 2012-03-16 12:28:03

0

看起来优化器试图强行通过ID索引,使加入的用户表。由于你正在做一个左连接(这是没有意义的,因为我期望每个条目都有一个用户ID,因此是一个正常的INNER JOIN),所以我会保持它的左连接。

所以,我会尝试以下。查询只是基于通过对自己的优点日期下降的消息ID和顺序的答复,然后离开加盟,如

SELECT 
     r.reply_id, 
     r.msg_id, 
     r.uid, 
     r.body, 
     r.date, 
     u.username as username, 
     u.profile_picture as profile_picture 
    FROM 
     (select R2.* 
      from pm_replies R2 
      where r2.msg_id = '784351921943772258') r 
     LEFT JOIN users as u 
      ON u.uid = r.uid 
    ORDER BY 
     r.date DESC 

另外,由于我没有MySQL的随手可得,而不能记住子查询中是否允许排序,如果是这样,您可以优化内部预查询(使用别名“R2”)并在那里放置顺序,因此它使用(msgid,date)索引并返回该集合...然后,从源结果集中加入到用户表上的用户表上没有索引所需的ID,只是用户表上的索引来查找匹配。

+0

这需要更长的时间才能加载并在2列(msg_id,date)上添加1个索引也不会起作用。 – fxuser 2012-03-16 13:34:29

+0

@fxuser,对不起,它不起作用,但你总是必须尝试替代引擎可能的想法。这是一个简单的测试,要么工作得更快,要么更快。只是寻找性能改进的众多方法之一。 – DRapp 2012-03-16 13:43:51