慢sql优化(1):limit下desc和asc性能相差百倍

背景:Task任务,需要将最近一天的数据查询出来,然后同步到kafka中。

一次慢查询的优化

环境:mysql5.7.26
表数据总量:4千万数据
单日数据量:1百万数据
表索引:date_user_id_idx(date、user_id)
主键索引:id
需求:需要将60天的数据归到到历史表,需要将昨天的数据同步给kafka。
sql:select * from tb_temp where date = 20220919

V1升级(分批次查询)

优化方案:限制每次查询的数量,分多次查出。

此时我们一般会使用分页查询。

  • 一般最常用的就是offset+limit偏移量进行查询。但是会带来深分页的性能损耗,是不推荐使用这种方案的。

  • 另一种方案就是使用cursor游标的方式,每次查询数据后得到一个游标id,然后代入到sql条件中。

select * from  tb_temp where date = 20220919 and id<=xxx order by id desc limit 5000

思考点:为什么要专门引入order by id desc

需要注意的时候,因为select * from tb_temp where date = 20220919命中的是date_user_id_idx索引。联合索引的规则:先根据date排序、然后根据user_id排序。所以这条只查询date返回的主键id是无序的。而游标分页需要一个有序的游标id,我们既然要借助主键id作为游标id,所以需要专门引入order by id desc

思考点:为什么引入order by id desc后,sql执行计划从date_user_id_idx变为主键索引

如果命中date_user_id_idx二级索引的话,我们得到的二级索引下的id是无序的。那么会带来回表查询+文件排序(100w数据)的性能损耗。那么在mysql看来直接走id主键索引性能会更优。

V2升级(limit底层原理)

而我们采用的正是V1版本的升级方案(游标法),但代码执行过程依旧会存在两种慢sql。

慢sql-1(归档历史数据):select * from tb_temp where date = 20220723 and id<=9223372036854775807(因为第一次的的时候给框架默认游标是Long.MAX) order by id desc limit 5000

慢sql-2(同步昨日数据):select * from tb_temp where date = 20220921 and id<=12344566(“临界数据的id”) order by id desc limit 5000

limit 200执行原理:

  1. 在表中拉取到200条数据后,终止;
  2. 扫描完where条件规定的返回后,终止;

当查询出的行数无法满足limit的限制时,mysql需要将where范围内的数据全部扫描完,流程才会被结束。

那么我们可以看到:

慢sql1(归档历史数据):由于是第一次查询所以框架给的游标id是默认值也就是Long的最大值。而0723的数据分布在聚簇索引树最左侧,本次查询就会在聚簇索引树的最右侧发起查询。期间会涉及到大量的IO操作,导致我们查询很慢。但是(归档历史数据)的sql第二次查询的时候:select * from tb_temp where date = 20220723 and id<=111122002 order by id desc limit 5000已经确定了范围,就会导致查询非常快速。

慢sql1(同步昨日数据):20220921数据分布在聚簇索引树的最右侧,所以开始的时候查询效率很高,但是到了20220921数据的边界处时,只查询到了288条数据,没有满足5000条数据的终止条件,且我们并没有给出终止条件(date不是终止条件,而是筛选条件)所以依旧会一路去左查询满足条件的数据,直到遍历完全表数据。

优化方案:

mysql的id是自增主键,逻辑上我们认为date和id是有关系的。所以需要查询当天的第一笔或者最后一笔id,作为终止limit的条件。

以同步昨日数据为例:

-- 先查询上一天的最后一笔数据的lastId
select id from tb_temp where date = 20220920 order by id desc limit 1;

- 再将这笔id代入到下面sql中
elect * from tb_temp where date = 20220921 and id<=12344566 and id>lastId order by id desc limit 5000

彩蛋:

为什么要查询上一天最后一笔数据的id,而不是当天的第一笔id,其实也和上面讲的有关系。

如果查询20220921的第一笔id的话(select id from tb_temp where date = 20220921 order by id limit 1)那么mysql会从聚簇索引树的最左侧开始寻找(而实际上这笔数据位于最右侧,从而带来很多无用的性能开销)。

相关文章

MySQL正序和倒序排序思考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容