繁体   English   中英

通过结果优化查询顺序到使用文件排序;

[英]optimizing query order by results to Using 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

我尝试了所有我能想到的索引组合,在google中搜索了如何最好地对它进行索引,但没有任何效果。

此查询对500个退回商品收取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   

显示创建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

显示创建用户

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

对于查询本身,最好的索引似乎是...

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部分确实很小。)

请尝试以下方法:

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

就我而言,它有帮助。

将日期添加到您的index1键,以便msg_id和date都在索引中。

Dems所说的应该是正确的,但是如果您使用的是InnoDB,则还有一个额外的细节:也许您是为集群表上二级索引付出了代价-本质上,通过二级索引访问行需要通过一级查询进行额外的查找,即聚类索引。 这种“双重查找”可能会使索引对查询优化器的吸引力降低。

为了减轻这种情况,请尝试使用索引覆盖 select语句中的所有字段:

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

看来优化器正在尝试通过ID强制索引以建立对用户表的联接。 由于您正在进行左联接(这没有意义,因为我希望每个条目都具有用户ID,因此是正常的INNER JOIN),因此我将其保持左联接。

因此,我将尝试以下方法。 根据MESSAGE 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,并且我不记得子查询中是否允许order by,如果可以,则可以优化内部预查询(使用别名“ R2”)并按在那里,因此它使用(msgid,date)索引并仅返回该集合...然后,联接到ID上的用户表,此时从源结果集中不需要索引,只需将用户表上的索引找到匹配。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM