作者:白日星445533 | 来源:互联网 | 2023-08-22 23:26
基本情况:数据表差不多有一千万条数据,用的是mycat分库。数据表的里的索引有PRIMARYidAppName(AppName,custidStatus,channel)建表语句如
主要介绍了两个方法:
- 第一个是
FORCE INDEX (PRIMARY)
:这个理解很直白就是强行加索引 - 第二个是late row lookups,也就是文章的重点,其实就是先构造一个只有id的子查询,然后再
join
一起。这样极大的提高效率。如下示例代码,o
是通过你的表和只有id查询出来的临时字表,l
是要join一起包含所有字段的表。
SELECT xx,xxx,....
FROM (
SELECT id
FROM <你的表>
ORDER BY
id
LIMIT <返回条数的范围>
) o
JOIN <你的表> l
ON l.id = o.id
ORDER BY
l.id
把范围查询放在最后;
索引:
AppName (AppName, channel, custidStatus)
SELECT
`id`,
`emailto`,
`channel`,
`AppName`,
`AmazonOrderId`
FROM
`eis_email_history`
WHERE `AppName` = 21
AND `channel` = '***'
AND `custidStatus` IN (0, 1, 2)
ORDER BY id DESC
LIMIT 50
排序也是遵循索引顺序的,所以索引顺序是至关重要的一部分。
是可以的,不过我发现你的主键是没有自增的,你可以检查下是否有受主键 ID 的一个影响,又或者 mysql 的版本影响。我所使用的 mysql 版本为 5.5.53
编辑一下我的答案,晚上回来查了一下《高性能mysql》。我的答案如下:将索引改为
AppName (id, AppName, custidStatus, channel)
order by 子句需要索引的列顺序需要满足索引的最左前缀的要求,所以ID需要排在第一。
有一种情况下order by子句可以不满足索引的最左前缀的要求,就是前导列为常量的时候。但是查询的where
WHERE `AppName` = 21
AND `custidStatus` IN (0, 1, 2)
AND `channel` = '***'
)
custidStatus列中有多个等于条件,对于排序来说,这也是一种范围查询,所以不满足最左前缀的要求。所以下面的索引是错误的。
AppName (AppName, custidStatus, channel,id)
PS:这是晚上专门查书看的资料,有疑问或者觉得我错误的可以再讨论一下?
explain
SELECT
`id`
FROM
`eis_email_history`
WHERE
`AppName` = 21
AND `custidStatus` IN (0, 1, 2)
AND `channel` = '***'
ORDER BY
`id`
LIMIT 50
这个执行看下?
分享下 https://segmentfault.com/a/11...